Calling the API
The Integration API is the surface your integration reads and writes merchant data through. It is one base URL, one envelope and 464 endpoints.
| Environment | Base URL |
|---|---|
| Production | https://api.bito.uz/integration-api/integration/api/v2/ |
| Dev | https://api.systematicdev.uz/integration-api/integration/api/v2/ |
The full endpoint list, with request and response schemas for each, is the API reference.
Two ways to authenticate
Both reach the same endpoints and the same data. Pick by how many merchants you serve.
| API key | OAuth 2.0 | |
|---|---|---|
| Header | api-key: <username>:<secret> | Authorization: Bearer <access_token> |
| Serves | One account — yours | Many accounts |
| Expires | Never | Access token 24h, refresh 90d |
| Setup | Copy it from the integration | Merchant installs and approves |
| Use for | Your own back office, scripts, one-merchant integrations | Marketplace integrations |
API key
Send your api_key in the api-key header. No token exchange, no expiry.
POST https://api.bito.uz/integration-api/integration/api/v2/product/get-paging
api-key: mycompany:9ad41c0e7b3f28d5610ac94e7f1b26d8
Content-Type: application/json
{ "page": 1, "limit": 20 }OAuth 2.0
Each merchant's install produces its own token pair, and the token carries the account context — so every call is automatically scoped to that merchant's data and you never pass an account id.
POST https://api.bito.uz/integration-api/integration/api/v2/product/get-paging
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{ "page": 1, "limit": 20 }Getting that token is its own chapter: OAuth 2.0 overview.
Conventions you have to know
HTTP methods
The method is part of each endpoint's contract:
| Method | Used for | Example |
|---|---|---|
POST | Create a record, and every list or filter query | POST /product/create, POST /product/get-paging |
PUT | Update a record, or change its state | PUT /product/update, PUT /production-operation/set-state |
GET | Read one record by id, and id-only reads | GET /product/get-by-id/{id}, GET /product/get-deleted |
DELETE | Delete a record | DELETE /product/delete/{id} |
Lists are POST because their filters are a JSON body, not a query string. Every endpoint page in the API reference states its own method.
WARNING
The Bito admin API — the one the web panel talks to — is POST-only. The Integration API is not. Do not carry that assumption across.
Request headers
| Header | Required | Description |
|---|---|---|
api-key or Authorization | Yes | One of the two auth methods above |
Content-Type | Yes | application/json |
Accept-Language | No | uz, uz_cyrillic, ru, en, kk, tg, ky. Default uz. Sets the language of message. |
organization_id | No | Target organization inside the account. Used only when the integration's settings (fields) include the organization_id field — otherwise the header is ignored. When the header is absent, that field's value is used. |
warehouse_id | No | Target warehouse. Used only when the integration's settings (fields) include the warehouse_id field — otherwise the header is ignored. When the header is absent, that field's value is used. |
price_id | No | Price list to read prices from. Used only when the integration's settings (fields) include the price_id field — otherwise the header is ignored. When the header is absent, that field's value is used. |
role_id | No | The role the request runs with. Used only when the integration's settings (fields) include the role_id field — otherwise the header is ignored. When the header is absent, that field's value is used. |
user_id | No | Run the request as this user. The user must belong to this account and not be blocked, otherwise the request is refused. When absent, the request runs as the account owner. |
The response envelope
Every response, success or failure, has the same shape.
{
"code": 0,
"message": "Success",
"status_code": 200,
"messages": { "uz": "Muvaffaqiyatli", "ru": "Успешно", "en": "Successful" },
"data": { },
"time": "2025-05-01T12:00:00Z"
}| Field | Meaning |
|---|---|
code | 0 on success, an error code otherwise. Branch on this. |
message | Human text in the Accept-Language language. Do not parse it. |
messages | The same text in uz, ru and en. |
status_code | HTTP status. |
data | The payload. Absent on errors. |
time | Server time, ISO 8601. |
Pagination
Every get-paging endpoint takes page and limit and returns a total alongside the rows.
Request
{ "page": 1, "limit": 50 }| Field | Type | Default | Limits |
|---|---|---|---|
page | number | 1 | ≥ 1 |
limit | number | 20 | 1 – 200 |
Response
{
"code": 0,
"message": "Success",
"status_code": 200,
"data": {
"total": 1043,
"data": [ { "_id": "6712f0a9c4d1e87b3a0f9911", "name": "Espresso" } ]
},
"time": "2025-05-01T12:00:00Z"
}Note the nesting: the rows are at data.data, the count at data.total. Page until page * limit >= total.
TIP
Most get-paging endpoints also accept filters next to page/limit — updated_at in particular lets you pull only what changed since your last sync. Check the endpoint in the API reference.
Deletion is always soft
Bito never physically deletes a record; a delete call marks it deleted. This matters for you in two ways: a get-deleted endpoint exists for most resources, and an id you cached can come back as deleted rather than disappearing.
Identifiers
Every _id is a 24-character MongoDB ObjectId, for example 6712f0a9c4d1e87b3a0f9911. Treat it as an opaque string.
Errors
An error response carries a non-zero code and no data.
{
"code": 401,
"message": "Unauthorized user",
"status_code": 401,
"messages": { "uz": "...", "ru": "...", "en": "Unauthorized user" },
"time": "2025-05-01T12:00:00Z"
}| HTTP | What went wrong | What to do |
|---|---|---|
| 400 | Validation failed, or a referenced record does not exist | Read message; fix the body |
| 401 | Missing, malformed or expired credentials | Re-check the header; refresh the token |
| 403 | The integration lacks the permission for this action | The message names the permission key it wanted; add it to required_permissions |
| 404 | No such endpoint | Check the path against the API reference |
| 429 | Rate limited | Back off and retry |
| 500 | Bito-side failure | Retry with backoff; if it persists, contact support |
WARNING
Do not retry a 400 unchanged and do not retry a write blindly — most Bito write endpoints are not idempotent, so a repeated create creates a second record.
Next
- Custom widgets — run your own app inside the Bito admin panel
- Data webhooks — get told when data changes instead of polling
- API reference — all 464 endpoints