Authentication & keys
One header authenticates every call — and a key pair keeps the credentials you send unreadable to everyone but us
Two different things are protected here, and they use different mechanisms. Your application proves who it is with a secret in a header. The end user’s credentials, which travel inside the request, can be encrypted with a public key so that not even an intercepted body reveals them.
The application secret
Every call carries it:
The secret belongs on your server and nowhere else. It can act for any of your customers and read every record extracted under your application. It must never reach a browser, a mobile binary, a front-end bundle or anything a user can open — there is no client-side use of these APIs, by design.
Secrets are issued per application in the console, and an application can hold more than one. That is what makes rotation uneventful: mint the new secret, deploy it, then revoke the old one. Revoking a secret never touches the application, its sessions, its executions or its data. Security & keys is the screen.
When authentication fails, the answer is an HTTP status and a stable detail code — branch on the code, show your own message:
Sandbox and production
The application decides how far a run can reach; the engine you name decides where this one goes. There is no flag on the request: the engine is the switch.
So a sandbox application can never reach a real person, whatever it asks for, and a production one can still run the same rehearsal it was built on — to reproduce a case, or to check a release of your own against data that cannot hurt anyone. A rehearsal says so wherever it shows: the execution is flagged sandbox, and its session token starts with st_test_ instead of st_live_.
The engine catalogue follows the same rule, one environment per answer. List Engines lists your application’s environment unless you pass environment: a production application sends environment=sandbox to see the engines it can rehearse with, and a sandbox application that asks for production is refused with 403 production_not_enabled_for_this_app.
Direct executions in production
Direct executions run in sandbox from the first minute. Moving the application to production asks which products it will use — choose Direct Executions — and stored credentials need Tokenized access on top: without it, a production run that asks for them answers 403 with insufficient_capabilities@login:tokenized_access.
Base URLs
clients.infonite.io is the address this API is moving to. It is not available yet; when it is, clients.infonite.tech becomes deprecated and is retired after a migration window we will announce here and in the changelog. Nothing else changes — same paths, same secrets, same payloads — so keeping the host in configuration rather than in code is all the preparation you need.
The explorer beside each endpoint in the reference lets you pick a server, so you can try a call without leaving this documentation.
Encrypting the credentials you send
Everything below is optional — the API accepts plain JSON over TLS — and it is worth doing anyway. TLS protects the connection; this protects the value, from the moment it leaves your process until it is used inside ours.
Each application has an RSA key pair whose private half is generated inside the platform and never leaves it. You get the public key. Encrypt with it and nobody downstream can read what you sent: not an intermediary, not a proxy log, not your own process afterwards.
That asymmetry is the whole point, and it is why this is the right envelope for somebody else’s password: a shared key would mean whoever can encrypt can also decrypt, and both sides holding the same secret is exactly what you do not want here.
Get your public key
In the console, under your application’s keys: a PEM public key, and an X.509 certificate carrying the same key for stacks that expect one. The certificate is self-signed — it is a container with a validity window, not a chain of trust; the key inside it does the work.
Encrypt, and say so in the value
An encrypted value is self-describing: the scheme, ::, and the Base64 of the encrypted bytes.
The byte layout of each envelope and working code in Node.js, Python and Java are on the Payload Encryption guide.
The same envelope works for Resume an Execution — which is where one-time codes travel, and where it matters most.
A payload that cannot be decrypted is rejected at the door, not halfway through. The call answers 422 naming the field that failed, with error_decrypting_value — no execution is created and nothing is charged. It is almost always one of three things: the wrong key, rsa:: on a payload too large for it, or Base64 mangled in transit.
A certificate renewal is not a key rotation
Worth knowing before it happens, because the words sound alarming and the event is not. Reissuing the certificate re-signs the same key pair: everything you have already encrypted still decrypts, and the certificate you installed keeps working until you choose to replace it. Generating a new pair is the destructive one — anything encrypted against the old public key becomes unreadable — which is why it is refused for an application that already has one.
Two key pairs exist, and confusing them costs an afternoon. The inbound pair is the one on this page: we generate it, we hold the private half, and you encrypt towards us with its public key. An outbound pair is the mirror — your own public key, whose private half we never hold — used when the platform encrypts something towards you. Different direction, different key, different problem.
Not storing the credentials at all
The most robust protection is not to hold the value. If your application has tokenization enabled, one execution can hand you a token that stands in for those credentials from then on — scoped to one engine, one customer and one set of features, revocable at any moment.
Every response carries
Read your budget from the response, do not hardcode it. A client that watches those headers keeps working when a limit is tuned; one built around numbers copied from a document does not. Exceeding a limit answers 429 with a detail naming which limit you hit, so a retry can back off against the right one.