The full design specification for the API that ships with the product in October 2026. Resource catalog, authentication, idempotency, pagination, errors, rate limits — everything you need to start integrating against the sandbox in August 2026.
| Environment | Base URL | Purpose |
|---|---|---|
| Sandbox | https://sandbox-api.hibr.ai | Free, pre-populated with sample UAE SMB data. No production data ever flows here. |
| Production | https://api.hibr.ai | Live customer data. Requires authenticated requests with valid API keys. |
All endpoints require HTTPS. HTTP requests are rejected at the load balancer with no redirect. TLS 1.3 is the minimum supported version; TLS 1.2 is supported for legacy bank-feed callbacks only.
HIBR supports two authentication models. Pick based on who is making the call:
Generate a key in Settings → Developers → API Keys. Pass it as a Bearer token:
Authorization: Bearer hibr_live_xxxxxxxxxxxxxxxxxxxx
Key types:
hibr_live_* — production environmenthibr_test_* — sandbox environmentKeys are scoped at creation. Available scopes:
read:invoices, write:invoicesread:customers, write:customersread:payments, write:paymentsread:vat, write:vatread:payroll, write:payrollread:reports* — full access (use with care)Keys are revocable per-key without affecting other keys. Revoked keys take effect within 60 seconds.
Authorization Code flow with PKCE. Use this when you're building an application that HIBR customers will install. Endpoints:
GET | https://app.hibr.ai/oauth/authorize | User consent page |
POST | https://api.hibr.ai/oauth/token | Code → token exchange |
POST | https://api.hibr.ai/oauth/revoke | Revoke a token |
POST | https://api.hibr.ai/oauth/introspect | Validate / inspect a token |
Register your application in Settings → Developers → OAuth Apps to get a client ID and client secret. Apply for partner status to publish your app to the HIBR App Directory.
sandbox-app.hibr.ai, generate a hibr_test_* key, start building.
API version is pinned per-request via the Hibr-Version header. The version is a date string. The launch version is 2026-10-01.
Hibr-Version: 2026-10-01
If no version is specified, requests use the account's default version (set at account creation; can be changed in Settings → Developers → API Version).
Versioning rules:
Deprecation notices are sent via the hibr.api.deprecation webhook event and via email to all developer account contacts at least 12 months before sunset.
All POST, PATCH, and DELETE requests use JSON. Set Content-Type: application/json.
# Standard request shape POST /v1/invoices HTTP/1.1 Host: api.hibr.ai Authorization: Bearer hibr_live_xxx Content-Type: application/json Idempotency-Key: 9f8e7d6c-5b4a-3210-fedc-ba9876543210 Hibr-Version: 2026-10-01 { "customer_id": "cust_01HFQA...", "lines": [ ... ] }
GET requests do not have a request body. Filter and sort using query parameters (see §11).
Successful responses return the resource directly (no wrapping envelope). HTTP 2xx for success, 4xx for client error, 5xx for server error.
# Single resource — 200 OK { "id": "inv_01HFQB...", "object": "invoice", "invoice_no": "INV-2026-001234", ... } # List response — 200 OK { "object": "list", "data": [ ... ], "pagination": { "next_cursor": "eyJ0IjoxNzAw...", "has_more": true } }
Every resource includes an object field naming the type. This makes generic deserialization easy in typed languages.
Amounts are integers in minor currency units. For AED, that means fils (1 AED = 100 fils). So 525000 means AED 5,250.00.
5250.00 as a JSON number triggers a 400 Bad Request. Floating-point representation drifts; integer minor units don't. Every UAE accounting product that uses floats has had a year-end reconciliation issue because of it. We're not going to repeat that.
Multi-currency: every monetary field has a paired _currency field. Internal storage is always AED-equivalent at the transaction-date FX rate; the original currency is preserved alongside.
invoice_date): ISO 8601 date format. "2026-10-15".created_at): RFC 3339 with explicit timezone, always UTC. "2026-10-15T09:32:14Z".The customer's local timezone is stored at the account level (Asia/Dubai by default for UAE customers). The API converts datetimes to UTC on input and returns UTC on output; client-side display formatting is your responsibility.
All resource IDs are prefixed with a 3–5 character type identifier, followed by an underscore, followed by a 26-character ULID. Example: inv_01HFQB9XTRP3K2Q5HW7Z3V8YJN.
ID prefixes:
cust_ | Customer |
supp_ | Supplier |
inv_ | Invoice (sales) |
bill_ | Bill (purchase invoice) |
cn_ | Credit note |
pay_ | Payment |
je_ | Journal entry |
item_ | Item (product or service) |
acct_ | Account (chart of accounts) |
emp_ | Employee |
vat_ | VAT return |
ct_ | Corporate tax return |
wps_ | WPS payroll run |
wh_ | Webhook endpoint |
Every state-changing request supports an optional Idempotency-Key header. Send a unique key per logical operation. HIBR stores the response under that key for 24 hours. Replaying the same request with the same key returns the cached response — no duplicate invoice, no duplicate payment.
Idempotency-Key: 9f8e7d6c-5b4a-3210-fedc-ba9876543210
Use a UUID v4 per logical operation, not per HTTP retry. The library SDKs handle this automatically.
List endpoints use cursor-based pagination. Pass ?limit=N&cursor=XYZ. Default limit is 50; maximum is 200.
GET /v1/invoices?limit=50&cursor=eyJ0IjoxNzAw...
The next cursor is in the response: pagination.next_cursor. When has_more is false, you've reached the end.
List endpoints accept filter and sort parameters:
GET /v1/invoices?status=paid&invoice_date.gte=2026-01-01&sort=invoice_date:desc
Filter operators (suffixed with a dot):
.eq — equal (default if no operator).gte, .lte, .gt, .lt — comparisons.in — one of (comma-separated values).contains — substring match (string fields only)Error responses use a stable structure:
# 400 Bad Request { "error": { "code": "invalid_request_error", "message": "The 'amount' field must be a positive integer in fils.", "field": "lines[0].unit_price", "docs_url": "https://hibr.ai/developers/api/#money", "request_id": "req_01HFQB..." } }
| HTTP status | Error code (sample) | Meaning |
|---|---|---|
| 400 | invalid_request_error | Request body or query parameter is malformed. |
| 401 | authentication_error | API key missing, malformed, or revoked. |
| 403 | permission_error | API key valid but lacks the required scope. |
| 404 | not_found | Resource doesn't exist or you don't have access. |
| 409 | conflict_error | State conflict (e.g., trying to delete a posted invoice). |
| 422 | validation_error | Business rule violation (e.g., negative VAT amount). |
| 429 | rate_limit_error | Rate limit exceeded. Retry after the Retry-After seconds. |
| 500 | api_error | Internal error. Include the request_id if you contact support. |
| 503 | service_unavailable | Temporary unavailability. Retry with exponential backoff. |
Per-tier limits, applied per API key:
| Tier | Requests / minute | Concurrent | Bursts allowed |
|---|---|---|---|
| Lite | 60 | 5 | 2× for 10 seconds |
| Pro | 300 | 20 | 3× for 10 seconds |
| Enterprise | 1,500 | 50 | Negotiable |
| Sandbox | 30 | 3 | None |
Rate-limit headers on every response:
X-RateLimit-Limit: 300 X-RateLimit-Remaining: 247 X-RateLimit-Reset: 1729000080
When you hit a 429, the Retry-After header tells you how many seconds to wait. The SDK clients implement automatic exponential backoff respecting this header.
The 16 resources available at launch. Each supports the standard verbs unless noted.
Each resource follows a predictable verb pattern:
| Verb | Path | Action |
|---|---|---|
| GET | /v1/{resource} | List with filters |
| GET | /v1/{resource}/{id} | Retrieve one |
| POST | /v1/{resource} | Create |
| PATCH | /v1/{resource}/{id} | Partial update |
| DELETE | /v1/{resource}/{id} | Delete (where allowed by business rules) |
| POST | /v1/{resource}/{id}/{action} | State transitions (e.g., post, void, send) |
Every API change is documented at https://api.hibr.ai/changelog with the date, version, type of change (additive / behavior / breaking), and which endpoints are affected.
Sandbox opens in August 2026. Reserve a beta seat to get notified when the first sandbox keys are issued.
Reserve founder slot →