KasarKasar Docs
API Reference

Authentication

Integrations, their keys, and the rights that decide which objects and fields each one can read and write.

The REST API is called by an integration: a machine identity that belongs to exactly one workspace. An integration is not a member. It has no account, no seat and no role; it can do what its rights say, and nothing else.

Creating an integration

  1. In Kasar, open Settings → API and webhooks. The Integrations section is shown to workspace admins.
  2. Click New integration, give it a name (unique in the workspace), tick its rights, and choose an expiration: never, 30 days, 90 days or 1 year.
  3. Copy the key. It is shown once and never stored in clear: to get another one, create a new key on the integration.

Sending the key

Keys start with ksr_svc_. Send them as a bearer token:

curl https://platform.kasar.app/api/v1/objects \
  -H "Authorization: Bearer ksr_svc_eyJhbGciOiJIUzI1NiJ9..."

The scheme is Bearer followed by one space. A personal key that starts with ksr_ but not ksr_svc_ belongs to the MCP connector and is refused by the REST API (401 INVALID_TOKEN).

One integration, one workspace

The key decides the workspace; nothing in the request can change it. The X-Kasar-Organization header is refused, not ignored:

{
  "error": {
    "code": "ORGANIZATION_HEADER_NOT_SUPPORTED",
    "message": "'x-kasar-organization' is not accepted: an integration belongs to exactly one workspace.",
    "suggestion": "Remove the header. To reach another workspace, create an integration there."
  }
}

The status is 400. To work with several workspaces, create one integration in each.

Keys, rotation and revocation

  • An integration can hold several active keys. New key creates another one and leaves the current one working: switch your configuration, then Close this key on the old one. The list shows when each key was last used.
  • Revoke stops the integration and every one of its keys immediately.
  • Rights belong to the integration, not to a key. A new key changes nothing else: same rights, same rate limits, same idempotency keys.
  • Rights, revocation and expiration are read again on every request: a change applies to the next call.

Rights

Rights are deny by default: anything not ticked is refused, including an object created after the integration.

For each object, an integration can be granted:

RightAllows
Read ({object}:read)GET .../records, GET .../records/{id}, GET .../deleted; the object appears in GET /objects
Write ({object}:write)POST and PUT .../records, PATCH .../records/{id}
Delete ({object}:delete)DELETE .../records/{id}

And two general rights:

RightLabel in SettingsAllows
schema:readRead the data modelGET /objects and GET /objects/{object}
webhooks:manageManage webhook destinationsEverything under /webhooks/destinations, for the destinations attached to the integration

Automations and email sequences are not managed through the API: they are built and run by the workspace's members, in the app.

What a right covers:

  • An integration that reads an object reads all its records. The visibility rules of roles (own records, team records) do not apply to a machine.
  • Write without Read is allowed. The write happens, and its response is { "data": null }: an integration does not receive what it cannot read.
  • The objects you can grant are the ones the API serves: standard and custom CRM objects. List entries and the platform's internal objects cannot be granted.

A request outside the rights is refused with 403 FORBIDDEN_GRANT, which names the missing right:

{
  "error": {
    "code": "FORBIDDEN_GRANT",
    "message": "This integration is not granted 'contacts:write'.",
    "suggestion": "A workspace admin can grant it in Settings → API, on the integration 'ERP sync'."
  }
}

On the record routes, the right is checked before the object is looked up: an object the integration was not granted answers 403 FORBIDDEN_GRANT, whether it exists or not. The schema routes answer 404 INVALID_OBJECT instead (see Objects).

Choosing fields

For each object it reads, an integration sees either:

  • All fields, including those created later. This is the default.
  • A list of fields. Only those, and nothing created later. A pipeline's status (status) is chosen like a field.

Either way, a field the workspace marked confidential is never part of it: Settings shows it under a lock, and a list cannot name it.

With a list:

  • Records carry only the chosen keys, plus id: in GET responses, in the record returned by a write, and in webhook deliveries to a destination attached to the integration.
  • GET /objects/{object} describes only the chosen keys, and field_count counts only them.
  • Writing a key outside the list is refused with 422 UNKNOWN_FIELD, like a key the object does not have.
  • Filtering, sorting or grouping on a field outside the list is refused with 400 INVALID_QUERY_FIELD, like a field that does not exist.
  • A composite (an address, a name, an amount) is chosen as a whole. Choosing a pipeline gives its two columns (pipeline_id, pipeline_step_id) and its status; the status can also be chosen alone, and is read-only either way.
  • A chosen field later deleted from the data model, or later marked confidential, simply disappears from the output, without an error.

Authentication errors

The checks run in this order, and the first one that fails answers:

  1. the per-IP rate limit (429);
  2. the X-Kasar-Organization header (400 ORGANIZATION_HEADER_NOT_SUPPORTED);
  3. the presence and format of the key (401);
  4. the per-integration burst limit (429);
  5. the key itself: known, not closed, not expired, its integration not revoked (401, or 503 if it cannot be checked);
  6. the workspace (403 WORKSPACE_INACCESSIBLE);
  7. the per-minute rate limits (429);
  8. the rights of the route (403 FORBIDDEN_GRANT).
StatusCodeWhen
401UNAUTHENTICATEDNo Authorization: Bearer ... header
401INVALID_TOKENThe key is malformed, unknown, closed or expired, or its integration was revoked. One code for all of them, on purpose: the response does not say which.
400ORGANIZATION_HEADER_NOT_SUPPORTEDThe request carries X-Kasar-Organization
403WORKSPACE_INACCESSIBLEThe integration's workspace no longer exists
403FORBIDDEN_GRANTThe integration lacks the right the route needs; the message names it
403PERMISSION_DENIEDA write touches a field the integration reads but cannot write (a pipeline whose status alone was chosen)
503SERVICE_UNAVAILABLEKasar could not check the key because its database is unavailable. Comes with Retry-After: 5.

A 503 is not a verdict on your key: its message says "Kasar is temporarily unavailable. Your key is still valid." Retry after Retry-After; do not disable the integration or alert on a revoked key. Only 401 INVALID_TOKEN means the key does not work.

All codes: Errors.

On this page