# Getting Started

Starting building on top of the Mission Control API is simple and straightforward. The following guide will help you go from having no knowledge of our platform, through being able to make some simple requests, to forming your first application.

# The Zaikio Platform

The Zaikio Platform consists of a group of applications that work together to solve the hard problems of building and integrating modern software for the print industry. For development work, we offer a sandbox account, which has no cost to you to explore and experiment with, and is ideal for getting started.

Sandbox

You can explore our Sandbox at hub.sandbox.zaikio.com (opens new window). You'll need an account there to proceed with this tutorial, so this might be a good time to register.

# Prerequisites

  • A Zaikio Account - freely available from hub.sandbox.zaikio.com
  • An Organization setup in your Zaikio Account
  • NodeJS installed, although other programming languages are fine, just not covered in this tutorial.

# Good to know

# Authentication

Before we can make any requests to the Zaikio Platform, we will need to be able to authenticate ourselves. This might be a good time to familiarise yourself with our guide to oAuth, the industry standard that we use for authentication and authorization of requests.

Our full oAuth guides are good reading and we would urge people to go through them in detail before building a full integration, but for this tutorial we can make do with a Personal Access Token, or PAT, which can be obtained by following these instructions (opens new window).

The scopes you need for this tutorial are:

mission_control.jobs.rw
mission_control.estimates.rw

This gives you access to the Jobs and Estimates endpoints of Mission Control.

# Technology

We're going to use NodeJS as the environment for this tutorial and assume that you are using any Linux or MacOS style operating system. Any programming language that can make HTTPS requests with at least TLS1.2 encryption is fine - you would just need to convert the commands below into ones that work for your platform.

Our compatibility should cover almost all up to date languages, but very old and unsupported environments such as Windows XP will not work.

# The process

# 1. Setup

Create a new folder, and initialize a new NPM project within it. This will give you a container to put your code inside.

mkdir mission-control-sample
cd mission-control-sample
npm init

Now we can install some dependencies. We're going to use node-fetch for a nice simple way to make HTTP requests.

npm install --save node-fetch@2

And we can make a file to hold our code:

touch get-jobs.js

# 2. Making a request

We need to setup some code in our get-jobs.js file, so open it in a text editor like VS Code (opens new window) and add the following code:

const fetch = require("node-fetch");
const debug = console.debug.bind(console);
const authToken = process.env.AUTH_TOKEN;

if (authToken == null) {
  console.log("Must provide AUTH_TOKEN environment variable");
  process.exit(1);
}

async function main() {
  const response = await fetch("https://mc.sandbox.zaikio.com/api/v1/jobs", {
    headers: {
      "Authorization": `Bearer ${authToken}`,
      "Content-Type": "application/json"
    }
  });
  const data = await response.json();

  debug(data);
};

main();

This code will load your Personal Access Token from an environment variable named AUTH_TOKEN, so you can either add that to your shell environment, or provide it as part of calling the command. We would never advise you to write that secret into the file itself.

You can then load the jobs in your Organisation by running the following:

node get-jobs.js

Which should give a response which looks like:

[]

This is correct, as we haven't loaded any Job specifications yet!

# 3. Adding a Job

We can simply add a Job to Mission Control by making a POST request to the correct API endpoint. To do this, let's add a new file to our project

touch add-job.js

And then add the following content to that file

const fetch = require("node-fetch");
const debug = console.debug.bind(console);
const authToken = process.env.AUTH_TOKEN;

if (authToken == null) {
  console.log("Must provide AUTH_TOKEN environment variable");
  process.exit(1);
}

const payload = {
  job: {
    name: "My first Job",
    kind: "business_card",
    source: "Mission Control Tutorial",
    version: "1",
    quantity: 1,
    due_at: new Date(new Date().getFullYear(), 12, 31, 23, 59),
    parts: [
      {
        colors: [
          {
            system: "CMYK",
            name: "Black",
            coverage: "1.0",
            side: "front"
          }
        ],
        desired_substrate: {
          category: "coated",
          paper_weight: 300,
          paper_weight_unit: "gsm",
          coating: [true],
          grain: "short"
        },
        kind: "business_card",
        content: "single_page",
        pages: 2,
        dimensions_unit: "mm",
        dimensions: { width: 210, height: 297 },
        layout: {
          format: "box",
          version: "1",
          unit: "mm",
          contents: [],
          kind: "page",
          sides: "one",
          dimensions: { width: 210, height: 297 },
          front: {
            page_number: 1,
            orientation: 0
          },
          position: { x: 0, y: 0 },
          bleeds: {
            left: 0,
            top: 0,
            right: 0,
            bottom: 0
          },
          print_free_margins: {
            left: 0,
            top: 0,
            right: 0,
            bottom: 0
          },
          reference: null
        }
      }
    ]
  }
}

async function main() {
  const response = await fetch("https://mc.sandbox.zaikio.com/api/v1/jobs", {
    body: JSON.stringify(payload),
    headers: {
      "Authorization": `Bearer ${authToken}`,
      "Content-Type": "application/json"
    },
    method: "post",
  });
  const data = await response.json();

  debug(data);
};

main();

You should see a response similar to:

{
  id: 'b3fe3154-9e80-4d0b-a15e-73ca328d6229',
  name: 'My first Job',
  kind: 'business_card',
  references: [ 'JO/KX9QZE' ],
  source: 'Mission Control Tutorial',
  version: '1',
  due_at: '2023-01-31T22:59:00.000Z',
  quantity: 1,
  acceptable_quantity_excess: 0,
  acceptable_quantity_underrun: 0,
  owner_id: '51232a2a-318a-4484-be86-db521b747b86',
  created_at: '2022-12-21T10:40:15.413Z',
  updated_at: '2022-12-21T10:40:15.434Z',
  estimated_completed_at: null
}

We can then add a job by running:

node add-job.js

And to check it's there safely, we can use our previous script to list all of the jobs:

node get-jobs.js

Which should return your new Job!

[
  {
    id: 'b3fe3154-9e80-4d0b-a15e-73ca328d6229',
    name: 'My first Job',
    kind: 'business_card',
    references: [ 'JO/KX9QZE' ],
    source: 'Mission Control Tutorial',
    version: '1',
    due_at: '2023-01-31T22:59:00.000Z',
    quantity: 1,
    acceptable_quantity_excess: 0,
    acceptable_quantity_underrun: 0,
    owner_id: '51232a2a-318a-4484-be86-db521b747b86',
    created_at: '2022-12-21T10:40:15.413Z',
    updated_at: '2022-12-21T10:40:15.431Z',
    estimated_completed_at: null
  }
]

### 4. Adding an estimate

Now we have a Job, we might want to add an Estimate for it. We can add a new file to help us achieve this.

touch add-estimate.js

And add the following code

const fetch = require("node-fetch");
const debug = console.debug.bind(console);
const authToken = process.env.AUTH_TOKEN;

const id = process.argv[2];

if (id == null) {
  console.log("Provide a Job ID to add an estimate for - `node add-estimate.js $ID`");
  process.exit(1);
}

if (authToken == null) {
  console.log("Must provide AUTH_TOKEN environment variable");
  process.exit(1);
}

const getPayload = (part_id, organization_id) => ({
  estimate: {
    approach: "quickest",
    currency: "EUR",
    production_costs: 100,
    handling_costs: 100,
    shipping_costs: 100,
    markup_percentage: 0,
    markup_costs: 0,
    net_sales_price: 300,
    gross_sales_price: 360,
    taxes: 60,
    vendor_id: organization_id,
    workstep_estimates: [
      {
        workpiece_type: "Part",
        workpiece_id: part_id,
        kind: "digital_printing",
        description: "printing the business cards",
        internal_labor_costs: 20,
        external_labor_costs: 0,
        duration_for_preparation: 300,
        duration_for_execution: 300,
        duration_for_cleanup: 120,
        material_costs: 80
      }
    ]
  }
});

async function main() {
  const job_resp = await fetch(`https://mc.sandbox.zaikio.com/api/v1/jobs/${id}`, {
    headers: {
      "Authorization": `Bearer ${authToken}`,
      "Content-Type": "application/json"
    },
  });
  const { organization_id, parts: [{ id: part_id }]} = await job_resp.json();

  const payload = getPayload(part_id, organization_id);

  const response = await fetch(`https://mc.sandbox.zaikio.com/api/v1/jobs/${id}/estimates`, {
    body: JSON.stringify(payload),
    headers: {
      "Authorization": `Bearer ${authToken}`,
      "Content-Type": "application/json"
    },
    method: "post",
  });
  const data = await response.json();

  debug(data);
};

main();

Then, you can call this new script, passing your Job ID as an argument to add an estimate to your already-created Job.

node add-estimate.js $YOUR_JOB_ID

To retrieve all of the estimates for a Job, you can query the estimates endpoint for that Job.

touch get-estimates.js

Add the following code:

const fetch = require("node-fetch");
const debug = console.debug.bind(console);
const authToken = process.env.AUTH_TOKEN;

const id = process.argv[2];

if (id == null) {
  console.log("Provide a Job ID to add an estimate for - `node add-estimate.js $ID`");
  process.exit(1);
}

if (authToken == null) {
  console.log("Must provide AUTH_TOKEN environment variable");
  process.exit(1);
}

async function main() {
  const response = await fetch(`https://mc.sandbox.zaikio.com/api/v1/jobs/${id}/estimates`, {
    headers: {
      "Authorization": `Bearer ${authToken}`,
      "Content-Type": "application/json"
    },
  });
  const data = await response.json();

  debug(data);
};

main();

Then you can get a list of all of the estimates for that Job by running your new script:

node get-estimates.js $YOUR_JOB_ID

Resulting in:

[
  {
    id: '1db5e201-fb0c-4e5d-98ad-5a47ffb5951b',
    vendor_id: '51232a2a-318a-4484-be86-db521b747b86',
    job_id: 'b3fe3154-9e80-4d0b-a15e-73ca328d6229',
    approach: 'quickest',
    currency: 'EUR',
    production_costs: 100,
    handling_costs: 100,
    shipping_costs: 100,
    markup_percentage: '0.0',
    markup_costs: '0.0',
    net_sales_price: '300.0',
    gross_sales_price: '360.0',
    taxes: '60.0',
    total_internal_labor_time: 0,
    total_internal_labor_costs: 0,
    total_external_labor_time: 0,
    total_external_labor_costs: 0,
    total_material_costs: 0,
    total_duration: null,
    created_at: '2022-12-21T13:21:59.313Z',
    updated_at: '2022-12-21T13:21:59.313Z',
    workstep_estimates: []
  }
]