Documentation

Going to production

The list of things that break when the integration stops being an experiment.

None of this is required for the API to work. All of it is what separates an integration that works from one that is still working at three in the morning on a Tuesday.

Secrets

  • The client_secret belongs in a secret manager or a server environment variable. Never in the repository, a frontend, a mobile app or a URL.
  • One credential per integration, not one shared across several. When something leaks, you want to revoke that and not everything.
  • Ask only for the scopes you use. It is the difference between a bounded incident and one that is not.
  • To swap secrets with no downtime, create a parallel credential and revoke the old one once traffic has moved. Rotating is the emergency path: the new secret is generated by the rotation, so there is a 401 window until you deploy it.
  • Do not log Authorization or client_secret. If your framework logs headers, filter them explicitly.

Tokens

  • Cache the access token and refresh it 60 seconds before expires_in. A token expiring mid-flight causes an avoidable 401.
  • On a 401, request a fresh token and retry once. If it repeats, it is not the token: it is the credential, the user or the company.
  • With multiple processes, share the token instead of each requesting its own: the client_id bucket is shared.
  • Do not parse the JWT. Its claims are an internal detail; if you need to know whether it is still valid, use introspect.

Turns

  • Generate the Idempotency-Key outside the retry loop, and persist it alongside the job. If your queue re-enqueues, the key has to survive that.
  • Raise your HTTP client's read timeout above 30 minutes, or use the stream. Almost every client's default is too short for a real turn.
  • One chat per conversation. The one-API-turn-per-chat limit is not about volume: it is what prevents cancelling one from cancelling the other.
  • Cancel explicitly. Closing the connection cancels nothing: the turn keeps running and keeps billing until it finishes or expires.

Errors

  • Branch on message_code, never on message.
  • Retry 429, 500, 502, 503 and 504 with exponential backoff and jitter. Do not retry contract 4xx: insisting does not help.
  • Honor Retry-After when it is present.
  • A turn that failed with 502 or 504 already consumed its key: to try again, generate a new one.
  • Never retry an interaction that returned 409: applying the same approval twice is worse than not knowing whether it applied.

Observability

  • Store every response's X-Request-Id — success and error — in your logs. It is what to quote so we can trace one of your requests on our side.
  • Use metadata to tie each turn to a record of yours. It comes back in the response and in the message listing, so you do not need a mapping table.
  • Monitor X-RateLimit-Remaining and throttle before hitting zero.
  • Alert on turn usage: a prompt change that doubles the tokens breaks nothing, which is exactly why nobody notices.

Usage and license

Each turn draws from the niucredits pool of the credential's owning user's license. When it runs out, the send is rejected even if you have request quota to spare.

  • Watch usage with Analytics before it becomes an incident.
  • Deleting a chat does not refund usage: the delete is logical and the spend already happened.
  • If the owning user leaves the company, their credential stops working. For long-lived integrations, use an organization credential or a dedicated service account.

Contract changes

The version travels in the URL (/api/v1). Within v1, changes are forward compatible: new fields can appear in responses and new values in an enum, but no field disappears and no existing field changes meaning.

  • Ignore fields you do not know instead of failing to deserialize them.
  • Do not assume an enum is closed: steps[].type and error code values can grow.
  • For requests it is the opposite: bodies are strict, and a field the API does not know returns 422. Send only what is documented.