Getting started with the ARCEL APIs
This page is for teams building apps on ARCEL's products: the Platform API, the Vault API, the Crewspace API, the Codeworks API and, for Arcel Konnect, the Daily Dose API. It covers what applies to every call: sessions, organisations, uploads, errors, pages, limits, retries, versions, live updates and push. Each operation's request, reply, errors and examples are in its API reference, and you can try them there with Sign in and Test Request. This page doesn't repeat them.
Environments
| Environment | Base URL | State |
|---|---|---|
| Staging | https://staging.arcelintelligence.com | Live, with test data. Every path starts with /v1. |
| Production | none yet | Not live. Its address will be announced before launch. |
Send Content-Type: application/json on every request with a body. Times are ISO 8601 in UTC (2026-11-06T09:12:00.000Z). Optional values that are missing are null, not left out.
On staging, the database sleeps when nobody has used it for a while. The first call after a quiet spell can take about 15 to 20 seconds, or answer 503. Try again after a few seconds. Background work runs every day from 05:00 to 24:00 India time, including notification delivery and scheduled reminders. Work queued overnight waits for the morning.
Sign in and sessions
There is one ARCEL account and one session for every product. A person signed in to one product is signed in to all of them.
- Call
listSignInProviders(GET /v1/auth/providers?platform=web|ios|android) and show the methods it lists. - Sign in. The email code is the simplest method:
requestEmailCode(POST /v1/auth/email/request-code), thenverifyEmailCode(POST /v1/auth/email/verify). Google, Apple and email-and-password sign-in give the same session. See Sign-in for app developers. - Keep the
tokenfrom the reply in secure storage (the Keychain on iOS, the Keystore on Android). Send it on every call asAuthorization: Bearer <token>. - Call
getAccount(GET /v1/auth/account) to show who is signed in.signOut(POST /v1/auth/logout) ends the session.
The products need a signed-in account. A guest session (startGuestSession) is enough only for reading Arcel Konnect.
Bearer token or cookie. Every sign-in also sets the HTTP-only cookie arcel_session. It is the same session as the token. The cookie is only for the web apps ARCEL serves on its own host (/app/, /vault/, /crewspace/, /codeworks/). Browsers never send it to another site, and native apps don't keep it. Your app uses the bearer token.
Apps on another web address (CORS). iOS, Android and desktop apps aren't affected by CORS: call the API directly with the bearer token. A web app served from a different address can't call the API from the browser yet. The staging API doesn't allow cross-origin requests today, so a browser stops them before they are sent. If you need this, ask ARCEL and give your app's exact address (for example https://app.example.com). Until then, call the API from your own server, or build a native app.
Session end. A 401 on any call means the session has ended. Sign in again. A session lasts up to a year and ends after 90 days without use.
Organisations
The products work inside an organisation (a company or one of its client organisations).
- The product switcher.
listProducts(GET /v1/products/available) lists the products the person can open. For each organisation they belong to, it gives itsshortName, their role and the products switched on there with their role in each. - Product calls name the organisation. Every product operation has the organisation's
shortNamein its address:/v1/vault/orgs/{org}/…,/v1/crewspace/orgs/{org}/…,/v1/codeworks/orgs/{org}/…. The platform's organisation calls use/v1/orgs/{org}/…. Start with the product's home call (getVaultHome,getCrewspaceHome,getCodeworksHome). It says whether the product is switched on for the organisation and which roles the person holds. - Scope. The server checks every call against the organisation in its address, so a person only ever sees that organisation's data. An organisation the person doesn't belong to answers
404, exactly as one that doesn't exist. A role that doesn't allow the action answers403. When the product is switched off for the organisation, its home call still answers (marked off) and its other calls answer404.
File uploads
Files belong to an organisation and a product. Upload in three steps:
createUpload(POST /v1/orgs/{org}/files) withproduct(for examplevault),name,contentTypeand the exactsizein bytes. The reply has the file'sidand anuploadwith aurland formfields, valid for 15 minutes.- Send the file there as
multipart/form-data: every field fromfields, then the file as the last field, namedfile. The address accepts only that content type and exactly that size. completeUpload(POST /v1/orgs/{org}/files/{fileId}/complete). The file ispendinguntil its malware scan has finished, thenclean. Then register it with the product, for example Vault'screateDocument.
An upload that would take the organisation past its storage limit is refused before any bytes are sent. Upload from the device. A browser can only upload from ARCEL's own web address.
Errors
Every error has the same body:
{
"code": "VALIDATION_ERROR",
"message": "Check the highlighted fields.",
"fieldErrors": { "name": "Enter a name." },
"requestId": "9d4c2b7a-6e15-4f3b-8a90-1b7e5c3d2f07"
}
- Branch on
code, never onmessage.messageis safe to show to people. fieldErrorsmaps each invalid field to its message. It is present on validation errors.requestIdis also in thex-request-idresponse header. Quote it when you report a problem.
| Status | Common codes | What to do |
|---|---|---|
| 400 | VALIDATION_ERROR | Fix the fields in fieldErrors. |
| 401 | UNAUTHENTICATED | Sign in again. |
| 403 | FORBIDDEN | The person's role doesn't allow this. Hide or disable the action. |
| 404 | NOT_FOUND | It doesn't exist, or the person can't see it. |
| 409 | CONFLICT and operation codes | The state changed. Reload and try again. |
| 422 | operation codes | The request is valid but can't be done. Show message. |
| 429 | RATE_LIMITED | Wait the seconds in Retry-After, then retry. |
| 5xx | INTERNAL_ERROR | Retry later with backoff. See Retries. |
Each operation lists its own codes in the reference.
Pages
Lists use one of two styles. Each operation's reference says which one.
- Numbered pages (Vault, Crewspace, Codeworks, Organisations and Notifications). Send
page(from 1) andlimitwhere the operation takes one. The reply hasitemsandtotal. Show numbered pages, or stop when you have readtotalitems. Some lists have a fixed page size, given in their description. - Cursors (Daily Dose). Send
limit(usually 1 to 50, default 20) and, after the first page,cursor, set to the previous reply'snextCursor. AnextCursorofnullmeans the end. Treat the cursor as opaque: never build or change it.
The Files list takes either page or cursor, not both.
Rate limits
Every operation has a request limit per signed-in person, or per network address before sign-in. Reads are generous (Vault's home allows 600 a minute per person, for example). Sign-in codes, invitations and sending are much stricter. Over the limit, the API answers 429 RATE_LIMITED with a Retry-After header in seconds. Wait that long. Don't retry in a tight loop.
Retries
Reads (GET) are always safe to retry. For writes, only these operations deduplicate a retry today. Send a new key per action and the same key when you retry it:
| API | Operation | How |
|---|---|---|
| Daily Dose | createComment, createExploreItemComment, submitFeedback, requestConnection | An Idempotency-Key header (a UUID), remembered for 24 hours |
| Daily Dose | sendMessage | The body's clientId (a UUID) |
| Daily Dose (billing) | createCheckoutSession | An Idempotency-Key header (a UUID), remembered for 24 hours |
No Platform, Vault, Crewspace or Codeworks operation takes an idempotency key yet. If a creating call (POST) loses its reply, read the list before you send it again, or a retry can create a second record. Calls that set a value (PUT, for example registerDevice or updateNotificationSetting) give the same result when repeated. Retry 5xx and network errors with backoff (for example 1, 2, then 4 seconds). Never retry 4xx errors other than 429.
Versions
Each API document has a version, shown at the top of its reference, and every path starts with /v1.
Before launch (now). The APIs are still changing. A change that could break a client raises the document's major version, but the paths stay under /v1. Vault and Crewspace, for example, are at version 2.0.0 and are served under /v1. Check the version at the top of each reference when you update your app.
After launch. A breaking change gets a new major version and a new path prefix (/v2/…) for the operations it affects. The old version keeps running until apps have moved. Additive changes keep the version and can arrive at any time: a new operation, a new optional input, a new field in a reply. Ignore reply fields you don't know.
Live updates
The API has no WebSocket on staging. Screens that must stay current use long-polling: a read that waits on the server until something changes.
- Crewspace chat:
listChatChannelsandgetChatChanges. Codeworks answers:getConversationChanges. Send the lastcursoryou received assince=<cursor>, andwait=25. - The request waits up to 25 seconds. A reply with
changed: falseafter 25 seconds is normal. Ask again at once. - After a change, merge the
itemsbyid, keep the newcursorand ask again. After an error, back off before you ask again. - Keep one waiting request per screen, and set your HTTP client's timeout above 30 seconds.
Arcel Konnect's messaging works the same way, with waits of up to 20 seconds (see the Daily Dose API).
Push notifications
Call registerDevice (PUT /v1/auth/devices/{installationId}) after sign-in, and again whenever the push token changes. Each account signed in on a device registers on its own.
- iOS (APNs): delivered. A push waits for the person's quiet hours, and most kinds stop after 10 pushes a day.
- Android (FCM): not delivered yet. The API accepts and stores Android tokens, so register them now, but it doesn't send pushes to them. Show the in-app inbox instead.
- In-app inbox (every platform):
listInbox,getInboxCounts,markInboxReadandmarkAllInboxRead. People choose email, push and in-app per kind withlistNotificationSettingsandupdateNotificationSetting.