Skip to main content

Authentication

There are two ways to authenticate against the Open API (/v1/open-api/**). Both end with the same thing — a token sent in the X-Open-Api-Token header on every request. What differs is who obtains it, and for whom.

PAT — personal access tokenOAuth 2.0 — authorization code
Built forOne company integrating with itselfAn app used by many companies
Who obtains itA company employee, from the UYSOT UIEach company grants your app consent
Token prefixuysot_pat_…uysot_at_… (access), uysotrt_… (refresh)
LifetimeChosen when issued, up to 365 daysAccess — 1 hour, refresh — 30 days
RenewalNone — issue a new one before it expiresgrant_type=refresh_token
PermissionsChosen when the application is set upWhatever the company approved on the consent screen

:::info Which one do I need? Writing a script or integration for your own company — use a PAT, described below. Distributing your app to other companies — use OAuth 2.0. :::

On this page:


1. Using the token​

Whatever its kind — PAT or OAuth access token — the header is the same:

GET https://api.service.app.uysot.uz/v1/open-api/contract/1234
X-Open-Api-Token: uysot_pat_436767a14e657166b7f455ee8b8dbe5f...
  • An unknown, revoked or expired token returns 401, and so does a token whose company connection was revoked.
  • A valid token without the required grant returns 403.
  • The budget is 60 requests per minute per token; exceeding it returns 429 (Rate limits).
  • If the company's UYSOT account is blocked, requests return 401 even with a healthy token.

:::note Every 401 looks identical The 401 body is a fixed English message with no error code, and it is the same whether the header was missing, the token was revoked, it expired, the connection was disconnected or the company is blocked:

{ "message": "Invalid or expired Open API token", "accept": false, "errors": null, "data": null }

GET /v1/open-api/token/info narrows it down: a 200 there means the token, the connection and the company are all healthy, so the failing call had a different problem; a 401 there confirms the credential itself is dead and needs refreshing or reissuing. Details in Errors § 1.1. :::

:::warning Authorization: Bearer does not work OAuth access tokens are also sent in X-Open-Api-Token when calling API endpoints. Authorization: Bearer … belongs to UYSOT's own product API — the Open API ignores it. :::


2. Grant format​

A grant is a (permission, scope) pair. In an OAuth scope string they are written as PERMISSION:SCOPE, separated by spaces:

PERMISSION_OPEN_API_LEAD:READ PERMISSION_OPEN_API_CONTRACT:READ

Permissions:

ValueDomain
PERMISSION_OPEN_API_LEADLeads
PERMISSION_OPEN_API_LEAD_NOTELead notes
PERMISSION_OPEN_API_LEAD_TASKLead tasks
PERMISSION_OPEN_API_CONTRACTContracts
PERMISSION_OPEN_API_CONTRACT_PAYMENTContract payments
PERMISSION_OPEN_API_CALLCalls

Scopes: READ, SAVE (create/update), DELETE.

Each endpoint's reference page states the grant it requires.

:::note Permissions are attached to the connection, not to the token The token itself carries no permissions. They belong to the (application ↔ company) connection, so when a company widens or narrows what your integration may do, your existing token reflects the change immediately — no re-issue needed. :::


3. PAT — personal access tokens​

A PAT is for an integration a company builds for its own data: a sync script, a report job, an internal service.

3.1 How to get one​

  1. In UYSOT, an employee with Open API configuration rights creates an application for the integration and selects the grants it needs.
  2. They issue a token for it and choose an expiry date.
  3. The token is displayed in clear text exactly once:
uysot_pat_436767a14e657166b7f455ee8b8dbe5ff1d54bafd24259c8600a02aa8ccd8420

:::danger The token is shown once It is never displayed again. Copy it straight into a secret manager or an environment variable — if you lose it, issue a new one. :::

Hand the value to your integration through configuration; it does not belong in source control.

3.2 Rules to plan around​

  • Maximum lifetime: 365 days.
  • Rotation: issuing a new PAT for an application revokes the previously active one — an application has exactly one working PAT at a time. Plan the swap together with a deploy.
  • Shortly before a PAT expires the API starts flagging it in every response (see 5.1), so monitoring can pick it up and you can rotate ahead of time. expiresInDays in token/info is the value to watch.
  • A PAT can be revoked at any time from the UYSOT UI; requests then return 401.

4. OAuth 2.0 in one paragraph​

A third-party app registers with UYSOT, receives a client_id and client_secret, and sends each company's user to a consent page. After approval your backend exchanges the returned authorization code for an access token (1 hour) and a refresh token (30 days), and calls the API with the access token in X-Open-Api-Token.

→ Full walkthrough: OAuth 2.0 — authorization code flow


5. Inspecting a token​

To find out who a token belongs to, when it expires and what it may do — no grant required:

GET https://api.service.app.uysot.uz/v1/open-api/token/info
X-Open-Api-Token: uysot_pat_…
{
"accept": true,
"message": null,
"errors": null,
"data": {
"application": { "id": 12, "name": "Acme CRM sync", "type": "PRIVATE" },
"company": { "id": 34, "name": "Uysot Demo" },
"kind": "PAT",
"expiresAt": 1798070399,
"expiresInDays": 118,
"permissions": [
{ "permission": "PERMISSION_OPEN_API_CONTRACT", "scope": "READ" },
{ "permission": "PERMISSION_OPEN_API_LEAD", "scope": "READ" }
]
}
}
  • kind — PAT or ACCESS (an OAuth access token).
  • expiresAt — epoch seconds; null means no expiry date (only revocation ends it).
  • The token value is never echoed back.

This makes a convenient deployment-time health check ("is the integration configured correctly?").

5.1 The expiry warning​

Once a token is within 7 days of expiring, the platform starts nudging you through the responses themselves: on every successful call, the envelope's message is replaced with an English warning instead of "Success".

{
"data": { },
"message": "Token will expire in 5 days. Please renew it.",
"accept": true,
"errors": []
}
  • Wording: "Token will expire in N days. Please renew it.", "Token will expire in 1 day. …", or "Token expires today. Please renew it." on the last day.
  • It is not an error: accept stays true, the HTTP status stays 200, and data is untouched.
  • It appears only on tokens that have an expiry, and only on successful responses.
  • There is no header for this — it lives in the body, so a client that logs message will see it, and a client that compares message == "Success" will break on it.

Treat it as a free monitoring signal: if your integration logs a non-"Success" message on a 200, that is your cue to rotate the credential (a PAT) or check the refresh flow (OAuth).


6. Errors​

The full list of status codes and message codes is in Errors; OAuth-flow errors are in OAuth § errors.

StatusCause
401Missing header, unknown/expired/revoked token, revoked connection, or a blocked company
403Valid token, but the required (permission, scope) is missing
429More than 60 requests per minute on this token

7. Security recommendations​

  • Keep PATs and client_secret on the backend. Never ship them in a frontend bundle, a mobile app or a repository.
  • Never log tokens. If you must, log the last 4 characters only.
  • HTTPS only.
  • If a credential leaks, revoke it and issue a new one — a leaked token grants everything its connection allows until it is revoked.
  • Least privilege: request only the grants you actually use.
  • Rotate PATs on a schedule you control, not on the day they expire.

8. FAQ​

Can I send the token as Authorization: Bearer? No. The Open API only reads X-Open-Api-Token (section 1).

Can a PAT be refreshed? No, PATs have no refresh flow. Issue a new one before the old expires — note that issuing revokes the previous PAT.

I issued a new PAT and the old token stopped working. That is by design: an application has one active PAT at a time (3.2).

Permissions changed — do I need a new token? No. They live on the connection, so the change takes effect immediately. Check the current state with GET /v1/open-api/token/info.

How do I tell 401 and 403 apart? 401 is a token problem (missing, expired, revoked, blocked company); 403 means the token is fine but lacks a grant. On 403, check permissions in token/info.

One company uses two of my integrations — do the tokens collide? No. Each (application, company) pair is its own connection with its own tokens.

How is the rate limit counted? Per token — 60 requests per minute. Several instances sharing one token share the budget.