Documentation
Authentication
Server-to-server calls use an API key. Applications acting on behalf of another Easarc customer use OAuth. There is no third option, and there is no way to authenticate from a browser.
API keys
Send the key as a bearer token on every request. Keys are created in the dashboard under Settings → API keys and are shown exactly once, at creation.
curl https://api.easarctech.com/v1/orders \
-H "Authorization: Bearer esk_live_7f3a9c2e8b14d05a" \
-H "Easarc-Version: 2026-08-01"import { Easarc } from '@easarc/sdk'
// Read the key from the environment. Never from a file in the repo.
const easarc = new Easarc({
apiKey: process.env.EASARC_API_KEY,
apiVersion: '2026-08-01',
})
const orders = await easarc.orders.list({ status: 'in_production', limit: 50 })Rules that are not negotiable
- Keys are secrets. Never put one in front-end code, a mobile app, a public repository or a URL query string. A key in a browser is a key belonging to everybody.
- Read them from the environment. If a key ever reaches a commit, revoke it first and rewrite history second — the revocation is what actually protects you.
- We scan public code hosts for leaked
esk_live_keys and revoke any we find, then email your account owner. This is a courtesy, not a safety net. - A key inherits the scopes you grant it and nothing more. Create a separate key per integration so you can revoke one without breaking the others.
Scopes
Grant the narrowest set that does the job. A request outside a key’s scopes returns 403 with insufficient_scope and names the scope that was missing.
| Scope | Grants |
|---|---|
| orders:read | Read orders, work orders, line items and stage history |
| orders:write | Create and update orders, and advance production stages |
| invoices:read | Read invoices, IRNs, e-way bills and payment status |
| invoices:write | Generate e-invoices and e-way bills, and issue credit notes |
| dispatch:write | Record dispatch, vehicle details and delivery confirmation |
| cameras:read | Read camera configuration and health |
| defects:read | Read defect events, inspection sessions and QC reports |
| defects:write | Confirm, reclassify or dismiss a defect event |
| webhooks:manage | Create, update and delete webhook endpoints |
Rotating a key without downtime
Both keys work during the overlap, so nothing has to be deployed at the same moment as the rotation. We recommend rotating every 90 days, and immediately on any suspicion of exposure.
# 1. Create the replacement, with the same scopes
easarc keys create --name "billing-worker" --scopes invoices:read,invoices:write
# 2. Deploy it. Both keys are live during the overlap.
# 3. Confirm the old key has stopped being used:
easarc keys usage --key esk_live_7f3a9c2e8b14d05a --since 24h
# 4. Revoke. Takes effect within 30 seconds, globally.
easarc keys revoke --key esk_live_7f3a9c2e8b14d05aOAuth for partner applications
If you are building something that other Easarc customers will connect their own account to — an accounting integration, a buyer portal — use OAuth rather than asking them for an API key. Register at Settings → OAuth applications to get a client ID and secret.
2. Exchange the code for tokens
curl -X POST https://auth.easarctech.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=ac_01J9ZM3F5T8K2Q" \
-d "redirect_uri=https://yourapp.example/callback" \
-d "client_id=eoa_9f2c71b4" \
-d "client_secret=eos_4d81f6a02c93e7b5" \
-d "code_verifier=dBjftJeZ4CVPmB92K27uhbUJU1p1r_wW1gFWFOEjXk"{
"access_token": "eat_01J9ZM4B7X…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "ert_01J9ZM4B7X…",
"scope": "orders:read invoices:read",
"account_id": "acc_01J8S9K2"
}3. Refresh before expiry
Access tokens last one hour. Refresh tokens are single-use and rotate on every exchange — store the new one each time. If a refresh token is presented twice we revoke the whole grant, on the assumption that it has been stolen, and the customer will have to reconnect.
curl -X POST https://auth.easarctech.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=ert_01J9ZM4B7X…" \
-d "client_id=eoa_9f2c71b4" \
-d "client_secret=eos_4d81f6a02c93e7b5"What authentication failures look like
| Status | Code | Cause |
|---|---|---|
| 401 | missing_credentials | No Authorization header was sent |
| 401 | invalid_api_key | The key does not exist, or was revoked |
| 401 | expired_token | The OAuth access token is past its hour |
| 403 | insufficient_scope | Valid credentials, but the scope was not granted |
| 403 | environment_mismatch | A test key was used against production, or the reverse |
| 403 | account_suspended | The account is suspended — usually non-payment |