Skip to content
Sursa Developers

Authentication

Every request to the Sursa API carries an API key, or an OAuth access token of an application, in the Authorization header:

Authorization: Bearer kb_3f9c…

The key identifies the organization and decides what the request can see and change: its role, its scopes, its data profile and its collections. There are no sessions or cookies on the API address. Each request is authenticated on its own, so you can send requests in parallel and from several servers with the same key.

curl https://api.example.com/v1/me \
  -H "Authorization: Bearer $SURSA_API_KEY"

Earlier integrations may send the key in an X-API-Key header instead. It is still accepted, but new code should use Authorization: Bearer.

Kinds of credentials

CredentialLooks likeWhere it works
Organization API keykb_…Every endpoint of the API, within its role, scopes, data profile and collections.
Custom source keykbsrc_…Only the push endpoints of its own custom source (/v1/push/sources/{source_id}/…).
OAuth access tokenkbat_…The endpoints of the API reference, within the scopes of the token. A token from POST /oauth/token with an authorization code acts on behalf of the employee who gave consent; a client_credentials token acts for the organization, like an API key. It is valid for 1 hour.

All of them are sent the same way. A custom source key cannot read, search or change anything outside its source; use it where the key is stored by a third party, such as an integration platform.

Authentication errors

Status and codeWhat it meansWhat to do
401 auth.not_authenticatedNo key, a mistyped key, or a revoked key.Check the header and the key value.
401 api_keys.expiredThe key has passed its expiry date.Create a new key and replace the old one.
401 sources.push_key_invalidA custom source key is wrong, revoked or belongs to another source.Check the key and the source ID in the path.
401 oauth.token_expiredThe OAuth access token has expired.Get a new one with the refresh token.
403 api_keys.scopeThe key has no scope for this operation.Add the scope, or use a key that has it.
403 api_keys.feature_disabledThe organization's plan does not include API keys.Contact the organization's administrator.
403 api_keys.ip_not_allowedThe request comes from an address outside the allowed addresses of the key.Call from an allowed network, or change the key's addresses.
403 api_keys.mcp_onlyA personal MCP key was used outside the /mcp endpoint.Use an organization API key for the API.
403 oauth.operation_not_allowedThe operation is not part of the public API, so an OAuth token cannot call it.Use an operation from the API reference.
403 org.suspendedThe organization is suspended. Its data is kept.Contact the organization's administrator.

403 means the request was authenticated but is not allowed. An object the key is not allowed to see answers 404, the same as an object that does not exist, so a key cannot learn what lies outside its access.

Acting as a data profile

A key with the admin role can check what another group of people would see: the X-View-As header runs a request as a data profile and, optionally, a role.

curl "https://api.example.com/v1/cards?limit=20" \
  -H "Authorization: Bearer $SURSA_ADMIN_KEY" \
  -H "X-View-As: employee:viewer"

Requests in this mode only read: any change returns 403 with the code view_as.read_only. An OAuth token, or a key without the admin role, cannot use X-View-As: it answers 403 with the code view_as.admin_key_required. A header that names no existing profile answers 400 with the code view_as.invalid_header.

Browser applications

The API allows requests from any web origin (Access-Control-Allow-Origin: *) and never uses cookies, so a page can call it with fetch. The key then lives in the page and is visible to whoever uses it. Call the API from the browser only with a key you are willing to show to those users, such as a viewer key limited to public collections, or put your own server between the browser and Sursa.

What only an employee can do

An organization API key acts for the organization, not for a person. Two parts of the API belong to people, so they work only with a token that acts on behalf of an employee: a session in Sursa or an OAuth access token issued with the employee's consent.

Conversations belong to a person. An organization API key sees in GET /v1/conversations only the conversations that it started itself. The public API has no operation that starts a conversation, so for a key the list is normally empty, and the conversations of employees are never shown to it. Questions without a conversation, with POST /v1/ask or POST /v1/chat, work with any key that has the ask scope. To list the conversations of an employee and read the history of one with GET /v1/conversations/{conv_id}, call the API with an OAuth token on behalf of that employee. The token sees only that employee's own conversations; any other conversation answers 404 with the code conversations.not_found.

Only an employee verifies a card. Verification confirms that a person checked the content, so POST /v1/cards/{card_id}/verification/verify and POST /v1/cards/{card_id}/verify need a session or an OAuth token on behalf of an employee who may verify the card. With an organization API key, or a client_credentials token, they answer 400 with the code cards.verify_user_account_required. The usual checks come first: a card the key cannot see answers 404, and a key that is not allowed to verify it answers 403.