Authentication
Status: The public REST API is live at
https://api.eyalla.net/v1. It is available to stores on the Elite plan; owners generate a key from their store admin (see Issuing tokens).Tenant API keys and scope enforcement are shipped. OAuth apps and the webhook-subscription dashboard are not yet built — the sections below say so where it applies.
Token types
| Type | Audience | Scope |
|---|---|---|
| Tenant API key | One specific store | Only that store's data, limited to the scopes its owner granted |
| Developer API token (not yet available) | Your developer account | Across every store you integrate with |
| OAuth app token (not yet available) | Third-party app authorized by a tenant's owner | Granular scopes chosen at install time |
Issuing tokens
- Tenant API key — this is the one to use today. The store owner generates it in their admin at Settings → API keys (
/admin/api-keys), picks the scopes, and copies the key. The key is shown exactly once, immediately after creation; it is stored hashed and cannot be retrieved again. Requires the Elite plan. - Developer token (not yet available) — a single credential spanning every tenant you integrate with.
- OAuth tokens (not yet available) — install-time authorization for third-party apps.
Do not confuse Settings → API keys (
/admin/api-keys, this API) with Bookings → Access API keys (/admin/access-api-keys). The latter mints credentials for gym door-access hardware, a separate API with its own scopes; a key from that page will not authenticate against/v1. That API is documented in Access Control API.
Sending the token
GET /v1/orders HTTP/1.1
Host: api.eyalla.net
Authorization: Bearer <your key>
Accept: application/json
Every request goes to api.eyalla.net — not to the store's own domain. The key identifies which store you are calling, so there is no tenant id or subdomain in the URL.
Send as Authorization: Bearer .... We don't accept tokens via query string — too easy to leak into server logs.
Rate limits
| Token type | Limit |
|---|---|
| Developer | 100 req/min/token, 10k req/day |
| Tenant | 60 req/min/token, 5k req/day |
| OAuth | 60 req/min/app, 5k req/day |
Exceeding returns 429 with Retry-After header in seconds. Hits don't carry over.
Scopes
Every key carries an explicit scope list, chosen by the store owner when they create it. A request outside those scopes is refused with 403 insufficient_scope — enforcement happens before the endpoint runs, so a missing scope never partially applies.
These are the scopes that exist:
| Scope | Grants |
|---|---|
orders:read |
List and read orders |
orders:write |
Update order fulfilment |
products:read |
List and read products |
products:write |
Create and edit products |
customers:read |
List and read customers |
Ask for the minimum you need — the owner sees exactly what they are granting, and a key that asks for write access it never uses is one an owner is right to refuse.
⚠️ These names changed. An earlier version of this page listed the form
read_orders/write_products, and also listedread_inventory,write_inventory,read_analyticsandmanage_webhooks. Those names were never implemented: the delimiter is a colon and the resource comes first. If you built against the old list, every request would have failedinsufficient_scope. The four extra scopes do not exist in any form yet.
Errors
{
"error": {
"code": "invalid_token",
"message": "Token has been revoked.",
"documentation_url": "https://developers.eyalla.net/errors/invalid_token"
}
}
| HTTP | code | Meaning |
|---|---|---|
| 401 | invalid_token |
Token unknown / revoked |
| 401 | expired_token |
OAuth token past its TTL; refresh |
| 403 | insufficient_scope |
Token valid but lacks the required scope |
| 429 | rate_limited |
Too many requests; see Retry-After |