Sari la conținut
Pagini APIAuthentication

Documentație API

Această documentație este disponibilă doar în limba engleză.

Authentication

Every route needs a credential. There are two kinds, and one header that decides which client company or firm a request acts on.

Two doors

Credential Sent as Who uses it Organization
Syllevo API key X-Api-Key: syl_live_... or Authorization: Bearer syl_live_... Your server, scripts, integrations Fixed. The key belongs to one organization
WorkOS session token Authorization: Bearer <jwt> The Syllevo web app Chosen per request with X-Organization-Id

Both headers can carry a bearer token, and the key prefix is what tells them apart. A token starting with syl_live_ or syl_test_ is treated as an API key. Anything else is verified as a WorkOS session token.

If you are building an integration, use an API key. Session tokens are issued by the sign-in flow in the web app and are not something you can mint.

API keys

Keys are created in the Syllevo web app under Settings, then API keys, by a member with the Admin role or higher. They can also be created through the API itself. See API keys.

What you need to know:

  • The full key is shown once, at creation. Syllevo stores only a hash, so a lost key cannot be recovered. Create a new one and revoke the old one.
  • syl_live_ keys are minted in production. syl_test_ keys are minted everywhere else.
  • A key can carry an expiry date. An expired key stops working at that moment.
  • A key carries scopes: a set of permissions, each optionally pinned to one client company. A key can never be given a permission the person creating it does not already have.
  • A key belongs to exactly one organization and cannot act outside it.
  • Revocation takes effect on the next request.
  • When the person who created a key is removed from the organization, Syllevo revokes their keys at the same moment. Create integration keys from an account that will stay with the firm.

An unknown key, a revoked key, and an expired key all answer the same way:

{
  "status": 401,
  "code": "api_key_invalid",
  "messageKey": "web.errors.api_key_invalid",
  "detail": null
}

That is deliberate. The response does not say which of the three it was, because saying so would tell anyone holding a guessed key whether it ever existed.

The organization header

X-Organization-Id names the organization a session request acts on.

  • With an API key: do not send it. The key already names its organization. Sending the header has no effect on which organization you reach.
  • With a session token: send it on every organization-scoped route. A person can belong to several organizations, and the token does not say which one they mean.

If a session request reaches an organization-scoped route without naming an organization, the answer is 403:

{
  "status": 403,
  "code": "organization_required",
  "messageKey": "web.errors.organization_required",
  "detail": null
}

If the header names an organization the caller is not a member of, the answer is also 403, with a different message key:

{
  "status": 403,
  "code": "forbidden",
  "messageKey": "web.errors.organization_access_denied",
  "detail": null
}

Membership is checked before any handler runs, so a non-member never reaches the data.

Routes that are not organization-scoped

A handful of routes answer without an organization, because they exist to find out which organizations you have:

Route Why
GET /v1/users/me, POST and DELETE /v1/users/me/avatar The person, not any organization
GET and POST /v1/organizations Listing and creating organizations
GET /v1/me/invitations and the accept or decline routes Invitations you hold, before you are a member
POST /v1/onboarding/session The first call after sign-in, which bootstraps the rest
GET /v1/status Says what your credential is, whatever it is
GET /v1/registry/company A public company lookup, not organization data

Everything else is organization-scoped.

A wrong path answers 401, not 404

This one surprises people, so it is worth stating plainly.

Syllevo's authorization is default deny: a request must be authenticated before it reaches the routing table's answer. A path that matches no route still goes through that check, so an unauthenticated request to a misspelled path answers 401, not 404.

GET /v1/invoicez HTTP/1.1
Host: api.syllevo.com
{ "status": 401, "title": "Unauthorized" }

If you are getting 401 and you are sure the credential is good, check the path before you check the credential. Send the same request with a valid credential: if the path is wrong you will then get a 404 and know which problem you have.

Note that this particular 401 comes from the framework, not from a Syllevo handler, so its body is an RFC 9457 problem document rather than the usual ErrorResponse. See Conventions.

Roles and permissions

There are two axes. Both are enforced at one place inside the API, the same way for session tokens, API keys, and MCP, so a key can never do something the person holding it could not.

Organization roles

Role Value Can do
Member 0 Whatever the per-client grants allow, and nothing at the firm level
Admin 1 Everything a member can, plus team, invitations, API keys, firm settings, and exports
Owner 2 Everything an admin can, plus billing, affiliates, ownership transfer, and two-factor enforcement

Roles serialize as those numbers, not as names. See Conventions.

There is exactly one owner at a time. Ownership moves with POST /v1/members/{memberId}/transfer-ownership.

Per-client permissions

Access to one client company is a set of permissions, granted per member or per API key scope.

Permission Value Lets the caller
View 0 Read the client, its documents, invoices, suppliers, and status
ManageDocuments 1 Upload, delete, restore documents, and decide review items
ManageSources 2 Connect, retag, sync, and disconnect sources, and merge suppliers
SendReminders 3 Pause, resume, and send reminders, and manage client contacts
ManageSettings 4 Change the client's own details and its reminder overrides
TransmitInvoices 5 Reserved for sending sales invoices on. Grantable to an API key, checked by no route yet

A member can also hold organization-wide access, which grants every permission on every client in the organization, including ones created later.

An Admin or Owner role does not silently grant per-client permissions. There is no admin fast path. What an admin gets instead is the firm-level routes: team, invitations, keys, settings, and exports.

Each endpoint on the resource pages names the role or permission it needs.

Checking what a credential can see

GET /v1/status answers with the actor type, the organization the request resolved to, and the correlation id. It is the fastest way to tell a scope problem from a credential problem. See Status and month-end completeness.