Skip to content

Calling the CoCoCo API ​

The CoCoCo API is one GraphQL endpoint on your tenant. Any language that can send an HTTPS POST with a JSON body can call it. The language guides in this section all run the same two operations, list jobs and create a job, with that language's standard HTTP client.

Get an API token ​

Every request carries a bearer token. You create tokens in the console:

  • For an integration, use a service account. Open Service accounts, create one with a descriptive name (for example Nightly ERP sync) and attach an IAM policy that grants only the permissions the integration needs. Then open the service account and create a token in its API Tokens section. A service account cannot sign in, and the integration keeps working when the person who set it up leaves.
  • For personal scripts and experiments, use a personal token. Open the user menu, then API Tokens (/#/api-tokens). A personal token carries all of your permissions, so don't put it in a long-running deployment.

The console shows a new token only once, so copy it straight away. If you leave the expiration empty, the token stays valid until you revoke it.

The examples need these permissions: job:list to list jobs and job:write to create one.

Send a request ​

Method and URLPOST https://<your-tenant-host>/graphql (the host you use to open the console)
AuthorizationBearer <API token>
Content-Typeapplication/json
Body{"query": "<GraphQL document>", "variables": { ... }}

The language guides read the host and token from two environment variables:

bash
export COCOCO_URL="https://<your-tenant-host>"
export COCOCO_TOKEN="<API token>"

A quick check that the token works:

graphql
query { listJobs(first: 1) { totalCount } }
bash
curl -sS "$COCOCO_URL/graphql" \
  -H "Authorization: Bearer $COCOCO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query":"query { listJobs(first: 1) { totalCount } }"}'

The two example operations ​

List jobs, one page at a time:

graphql
query ListJobs($first: Int, $after: String) {
  listJobs(first: $first, after: $after) {
    totalCount
    pageInfo { hasNextPage endCursor }
    edges { node { id name quantity status dueAt } }
  }
}

With the variables {"first": 2} the response looks like this:

json
{
  "data": {
    "listJobs": {
      "totalCount": 10,
      "pageInfo": { "hasNextPage": true, "endCursor": "eyJpZCI6ImpvYl8wMU0w..." },
      "edges": [
        { "node": { "id": "job_01M0SYJHB7FX6BKYVZZ7EAG4Y8", "name": "Business cards", "quantity": 5000, "status": "CONFIRMED", "dueAt": null } },
        { "node": { "id": "job_01M0R249JMETNBM1Z7466MXGZD", "name": "Flyer A5", "quantity": 1, "status": "DRAFT", "dueAt": null } }
      ]
    }
  }
}

Create a job:

graphql
mutation CreateJob($input: CreateJobInput!) {
  createJob(input: $input) {
    job { id name status }
    errors { path message }
  }
}

with variables such as:

json
{ "input": { "name": "Business cards", "quantity": 500, "externalId": "ERP-10042" } }

name and quantity are required. externalId is optional and must be unique in your tenant, so it is a good place for the ID the job has in your own system. See CreateJobInput for the other fields.

Conventions to handle in your code ​

  • Lists are connections. A list query returns edges { node }, pageInfo and totalCount. Ask for at most 100 items with first (the default is 25). To get the next page, pass pageInfo.endCursor as after. Stop when hasNextPage is false.
  • IDs are typed, prefixed strings such as job_01M0SYJHB7FX6BKYVZZ7EAG4Y8. In a GraphQL document they have their own scalar types (JobID!, CustomerID, …); in JSON variables you send them as plain strings.
  • Mutations report validation problems in the payload. createJob returns the created job and a list of errors, each with a path and a message. An empty errors list means the change was saved.
  • Everything else comes back as top-level errors. A missing or invalid token (Authentication required), a missing permission (Access denied: not authorized to perform '<action>' on '<resource>') and an invalid document all appear in the errors array next to data, and the HTTP status is still 200. Check that array on every response. A 400 status means the request itself was rejected, for example because the body had no query.

These guides cover queries and mutations over HTTP. Subscriptions are not covered here.

Explore the schema ​

  • The schema reference on this site lists every query, mutation and type.
  • In the console, the GraphQL playground (/#/graphql-playground) runs queries with your own session, and /#/docs has the in-app API guides.
  • GET https://<your-tenant-host>/graphql/schema returns the schema as SDL, which code generators can read.

Language guides ​

Connect machines, automate workflows, and build custom apps for print production.