Authentication

Every request carries an organization's API key as a bearer token. The key decides which organization, which mode and which operations.

API keys

Owners and admins create keys under Settings → Connections → API keys. A key belongs to the organization, acts with the permissions it was given, and is shown in full exactly once. We store only a hash of it, so a lost key cannot be recovered: revoke it and create another.

Header
Authorization: Bearer ctk_live_3J9fX...
  • ctk_test_ keys run in test mode and work as soon as they are created. ctk_live_ keys act on real claims once Contents.team approves them; until then every call returns 403 live_key_pending_approval.
  • A key can expire on a date you choose, or never. An organization can hold up to 50 active keys.
  • A key stops working the moment it is revoked, when it expires, or when the member who created it leaves the organization or resets their password. Create keys for an integration from an account that will stay.
  • Every request is logged against the key, and Settings shows when each key was last used. Use one key per integration, so you can revoke one without breaking the others.

Scopes

A key carries a set of scopes, and each operation lists the scopes it needs in the API reference. A write scope never implies the matching read scope: a key that creates claims and reads them back needs both claims:write and claims:read. Give each key only what its integration uses.

ScopeAllows
claims:readList and read claims
claims:writeCreate and update claims
photos:readList and read photos
photos:writeAdd photos to claims
items:readRead inventory items and prices
exports:writeGenerate report exports
webhooks:manageManage webhook endpoints
items:writeEdit, add, delete, approve and reject items

A request without a needed scope fails with a 403 that names what is missing:

403 response
{
  "error": {
    "type": "permission_error",
    "code": "insufficient_scope",
    "message": "This API key is missing a required scope: claims:read.",
    "details": {
      "required": [
        "claims:read"
      ]
    },
    "requestId": "req_5e0c1f7a2b9d44c08a61e3f2"
  }
}

Test and live mode

The mode is part of the key, so the same code runs against either. Claims a test key creates are test claims: they run the canned pipeline and are never billed. A test key sees only test claims and a live key only live claims; the other mode's ids are a 404. See Test mode for what the canned pipeline returns.

Keeping keys safe

  • Keep keys on your server. Never ship one in a browser, a mobile app or a public repository.
  • Store keys in a secrets manager or environment variables, not in source.
  • To rotate, create the new key, deploy it, then revoke the old one. Both work in the meantime. Webhook endpoints stay with the key that registered them: register them again with the new key, then delete the old ones in Settings.
  • If a key may have leaked, revoke it in Settings straight away and tell us at integrations@contents.team.

OAuth apps for partners

API keys suit an organization connecting its own systems. A platform that connects many Contents.team organizations will use an OAuth app instead: each organization approves your app once, and you receive a token scoped to that organization, revocable from their Settings. OAuth access tokens start with cto_ and are sent the same way, as a bearer token, so code written against API keys carries over.

An app registered in Settings gets live access once Contents.team approves it, as a live key does: organizations can authorize it straight away, but until it is approved its tokens return 403 oauth_app_pending_approval. Assistants that register themselves when you connect them to the MCP server (Claude, ChatGPT, Cursor) act only for the organization that approves them and need no approval.

Until OAuth apps are open

Partners integrate with a key each customer organization creates for them. Write to integrations@contents.team to join the OAuth preview and set up a partner agreement.

NextReview and approveEdit the priced items, accept replacement offers and approve them from your own product.