Authentication
Integration requests authenticate with an organization API key (sk-org-…) in the Authorization: Bearer header. The key opens two doors, each limited by the key's scopes:
| Door | Scope |
|---|---|
OpenAI-compatible API: POST /v1/chat/completions, GET /v1/models | chat:write |
MCP server at /mcp/: reads | tools:read |
MCP server at /mcp/: write calls and repl_execute | tools:write |
The key goes only in Authorization: Bearer; an x-api-key header is not read, and a request carrying only that header gets 401 AUTH_HEADER_MISSING.
The native /api/v1 is the internal API of the Samreshuuu apps: it takes a signed-in user's token, answers a key with 401 AUTH_TOKEN_INVALID and is not an integration contract. The /v1 endpoints are the other way round: they take a key only and answer a user token with the same code.
Create a key and send your first request
- Sign in to Samreshuuu and select the organization you want to use.
- Open Settings → API keys and choose Create key. Organization owners and administrators can create keys.
- Enter a name, such as
My integration. Under Access, keep Full access: it is selected by default and includeschat:write. AI apps only and View only open MCP but not the chat endpoint. - Choose an expiration period and create the key.
- Copy and save the
sk-org-…key. The full secret is shown only once.
If the create button is absent, contact your organization owner or administrator.
Store the key in an environment variable on your server or computer:
First check authentication by listing the agents you can talk to, without starting one:
Successful authentication returns a JSON list of agents. Then send a message to one of them by its handle; this request uses your available quota:
Read the answer from choices[0].message.content. A 401 means the key was not accepted; a 403 means the key lacks chat:write; a 404 means model names no agent you can reach. For Python and Node.js examples, see OpenAI-compatible API.
Organization Context
A key is bound to the organization that issued it and to the member who created it, and it is an organization credential, not a personal one. It reaches the agents that member can reach there and the organization's shared connections open to that member. It never reaches the creator's memory, the creator's personal connections or the creator's devices: an agent answering a key starts without memory, and a connection only the creator can see is not connected for the key.
A key works only while its creator is an owner or administrator of a live organization. This is checked on every request: when the creator leaves or is removed, loses the role, or the organization is deleted, the next request with the key gets 401 AUTH_INVALID_CREDENTIALS.
Keep keys on your server; do not embed them in browser or mobile bundles. Key management happens in Settings → API keys or with the signed-in user's token ($ADMIN_TOKEN below): owners and administrators create and revoke keys, any member can list them.
Token Format
API keys are prefixed with sk-org-. The full secret is shown only once, at creation: store it securely. List and revoke endpoints only ever return the key prefix, never the secret. The sk-org- prefix lets a secret scanner find a leaked key: add the pattern to your pre-commit hook and log search.
Scopes
A key carries a list of scopes, one at least: tools:read, tools:write, chat:write, sessions:read, sessions:write. Each is resource:action. A request that needs a scope the key lacks fails with 403 AUTH_PERMISSION_DENIED. A key created through the API without scopes gets tools:write, chat:write, sessions:write; an empty list and any other word (write:tools, chat, read:tools, admin included) are rejected with 422.
| Scope | Grants |
|---|---|
chat:write | POST /v1/chat/completions and GET /v1/models |
tools:read | Reads over MCP: list_services, describe_service, read calls of connector_execute |
tools:write | Write calls of connector_execute and every repl_execute over MCP; includes tools:read |
sessions:read | Reserved: no operation asks it yet |
sessions:write | Reserved: no operation asks it yet; includes sessions:read |
The access levels in Settings map to scope sets: Full access is tools:write, chat:write, sessions:write, the same set a key created through the API without scopes gets; AI apps only is tools:write; View only is tools:read. Only Full access opens the chat endpoint.
Managing API Keys
Keys are issued, listed, and revoked per organization. Each key expires after expires_in_days: 90 by default, from 1 to 365; an explicit null creates a non-expiring key.
Revocation takes effect immediately, over HTTP and MCP. A member's keys are revoked automatically when they leave the organization or lose the owner or administrator role, and all keys of an organization are revoked when it is deleted. An unknown, revoked or expired key, and a key whose creator no longer holds a key (see Organization Context), gets 401 AUTH_INVALID_CREDENTIALS.
Rotation without downtime. Create a new key, deploy it, confirm through last_used_at that the old key is no longer used, then revoke the old one. Requests to /v1/* and to MCP both set the stamp, at most once every 10 minutes: the key has gone quiet when its last_used_at is older than that window and stops moving. Revoke a key that reached a repository, log or chat right away, even with no sign of use. Keep separate keys for separate environments (development, production).
Rate Limits and Browser Calls
Request rate is limited per key, per minute, by the organization's plan:
| Plan | Requests per minute, per key |
|---|---|
| Pro | 180 |
| Max | 360 |
Exceeding it returns 429 RATE_LIMIT_EXCEEDED with a Retry-After header in seconds. Model spend is a separate weekly limit, see Errors & Rate Limits.
Calls from a browser page on another origin are cut by CORS: the API does not answer cross-origin requests with a key. Call it from your own server, which also keeps the key out of the page.
Authentication Errors
A /v1 refusal arrives in the public error object: branch on error.type and error.code, not on the text. Every 401 carries the header WWW-Authenticate: Bearer realm="samreshuuu". Status, code and the retry flag below come from the server's error registry; the text of a key refusal is the key copy shown after the table.
| HTTP | Code | Meaning | Retry |
|---|---|---|---|
| 401 | AUTH_HEADER_MISSING | Missing authorization header. | no |
| 401 | AUTH_TOKEN_INVALID | Invalid authorization token. | no |
| 401 | AUTH_TOKEN_EXPIRED | Token has expired. | no |
| 401 | AUTH_INVALID_CREDENTIALS | We couldn't verify the sign-in. Try again. | no |
| 403 | AUTH_PERMISSION_DENIED | Insufficient permissions for this operation. | no |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests. Please wait a moment. | yes |
AUTH_HEADER_MISSING: noAuthorizationheader. AddBearer.AUTH_TOKEN_INVALID: notBearer, a malformed token, or an organization key on the native/api/v1. Call/v1or MCP instead.AUTH_TOKEN_EXPIRED: a user token has expired. Keys do not expire this way: an expired key isAUTH_INVALID_CREDENTIALS.AUTH_INVALID_CREDENTIALS: the key is unknown, revoked or expired, or its creator is no longer an owner or administrator of the organization. The message reads "Invalid, revoked or expired API key. Create a new key in the organization settings."AUTH_PERMISSION_DENIED: the key lacks the scope the operation asks; the message names it. Do not retry: create a key with the scope.RATE_LIMIT_EXCEEDED: the key's rate limit. WaitRetry-Afterseconds.
MCP answers an authentication failure before any MCP message is read, with HTTP 401, the same WWW-Authenticate header and a {"detail": {…}} body (code, message, message_en); see MCP. The native /api/v1 (key management) answers in the same detail body.
Frequently asked questions
How do I authenticate a request?
Send an organization API key as Authorization: Bearer sk-org-... It opens the OpenAI-compatible /v1 endpoints and the MCP server, limited by the key's scopes.
Which organization does a request run in?
The one that issued the key. A key is an organization credential created by one member: it reaches the organization's shared connections, never the creator's memory or personal connections, and it works only while the creator is still an owner or administrator there. To work in another organization, create a key there.
What happens if my key lacks a required scope?
The request fails with 403 AUTH_PERMISSION_DENIED, and the error message names the missing scope. chat:write opens /v1/chat/completions and /v1/models, tools:read opens reads over MCP, tools:write opens write calls and repl_execute over MCP and includes tools:read. sessions:read and sessions:write are reserved: no operation asks them yet. Every key holds at least one scope; a key created without scopes gets tools:write, chat:write and sessions:write.
Can I retrieve a key's secret after creating it?
No. The full secret is shown only once, at creation. List and revoke endpoints return only the key prefix, never the secret. A key expires after expires_in_days, see Managing API keys; an explicit null creates a non-expiring key.