Authentication
Every API call carries a credential. An integration uses an API key. An AI assistant that connects to the MCP server uses OAuth, and the MCP server calls the API with that token for it.
API keys
An API key belongs to one organization. It reaches the companies of that organization, and nothing else.
GET /api/organizations/ HTTP/1.1
Authorization: Bearer osk_live_...
- Create a key in the Oscar app, in the settings of your organization,
under API keys. You need the permission
api_keys.manage(anownerhas it). Give the key a name, its scopes, and an optional expiry date. - The full key is shown once, when you create it. Oscar stores only a hash of it. Keep it in a secret store, never in your code or in a log.
- A key starts with
osk_, for exampleosk_live_..., so a secret scanner can find it. - A key acts for the person who created it. It has the permissions of that person's role in the organization, narrowed by the scopes of the key and by what Oscar allows the clients of each company. When that person leaves the organization or is deactivated, the key is revoked.
- An owner sees every key of the organization in the settings, and can revoke
one at any time. An unknown, revoked or expired key gets 401
authentication_failed.
Scopes
| Scope | Allows |
|---|---|
read | Every read: the organization, the books, the documents |
write | Every change that the role allows: record and issue invoices, create parties, upload documents |
A key needs read to read and write to change something. No key can
manage the organization, its members or its API keys: only a person signed in
to the app can do that.
A call that the role allows but the scopes of the key do not gets 403
insufficient_scope. A call that the role does not allow gets 403
permission_denied.
Which permissions does my key have?
GET /api/companies/{company_id}/ returns permissions: the effective
permissions of the caller in that company. Each operation of the
API reference names the permission it needs.
OAuth
Oscar is an OAuth 2.1 authorization server for the MCP server. An MCP client such as Claude or ChatGPT signs the user in, the user approves the connection on a consent page and chooses one organization, and the client gets an access token for that organization.
- The authorization code flow with PKCE
S256, and nothing else. - The metadata is at
/.well-known/oauth-authorization-server. The authorization endpoint is/oauth/authorizeand the token endpoint is/oauth/token. - Each request names the MCP server as its
resource(RFC 8707). - The scopes are the same as for an API key:
readandwrite. A request that names noscopegetsreadonly; ask forread writeto write. - An access token lives for one hour. Refresh tokens rotate.
- The user sees every connection under "Connected apps" in the account settings, and can revoke one there.
An integration that is not an MCP client uses an API key. The details of the flow are in Connect an AI assistant.
Requests without a session
A request with an API key or an OAuth token sends no cookie, so it needs no
CSRF token. Send JSON with Content-Type: application/json, and a file upload
as multipart/form-data.
Every response carries an X-Request-Id header. Give it to us when you report
a problem. You can also send your own X-Request-Id, and the API keeps it
when it is well formed.