8. InferrexAPI
InferrexAPI is plain HTTPS and JSON at https://api.inferrex.com. Everything in this guide is an endpoint. InferrexMCP is generated from the same route definitions, so the two never disagree.
The API description
The full OpenAPI document needs no credentials:
curl https://api.inferrex.com/v1/openapi.json
It lists every endpoint, parameter and response, and the scope each operation needs. You can also download it from Workspace settings, API keys.
Authenticate
Send your API key in the X-API-Key header on every request:
curl https://api.inferrex.com/v1/connections \
-H "X-API-Key: $INFERREX_API_KEY"
Or swap the key for a short-lived token
If your software expects a standard OAuth 2.0 client-credentials flow, swap the key for a bearer token. The key's prefix is the client id. The key is the client secret.
curl -X POST https://api.inferrex.com/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type": "client_credentials", "client_id": "YOUR_KEY_PREFIX", "client_secret": "YOUR_API_KEY"}'
You can also post it as a form, or authenticate with HTTP Basic. Response shape: { access_token, token_type, expires_in, scope }. Send the token as Authorization: Bearer <token> and get a new one when it expires. Add "scope" to ask for fewer permissions than the key has. Errors from this route follow RFC 6749: { error, error_description }.
Scopes
A key carries scopes. Each operation needs one. Scopes read as <resource>:<action>:
| Scope | Lets the key |
|---|---|
connections:read |
Read systems. |
connections:write |
Connect, test, review and change systems. |
connections:delete |
Archive systems. |
mappings:read, mappings:write |
Read and edit mappings. |
pipelines:read, pipelines:write |
Read and run flows. |
golden-records:read, golden-records:write |
Read Golden records and set source roles. |
canonical-proposals:write |
Decide Golden-record changes. |
circuit-breakers:read, circuit-breakers:write |
Read and decide safety stops. |
settings:read, settings:write |
List and create API keys. |
workspace:read, workspace:write |
Read and change workspace settings and environments. |
This is not the full list. The OpenAPI document names the scope for every operation.
When you create a key, three presets save you listing scopes: preset:read, preset:write (read, create and change, no delete) and preset:full.
A key with the wrong scope gets 403 scope_denied, and the message names the scope it lacks. Do not retry. Ask a workspace admin for a key with that scope.
A signed-in person is not limited by key scopes. Their role decides what they can do.
Choose the environment
Send X-Environment-Id to work in one environment. Leave it out to use the workspace default. Chapter 7 has the detail.
Make writes safe to retry
Send an Idempotency-Key header on a write. Use one key per logical operation, and send the same key when you retry that operation. The API replays the first answer and does not apply the write twice.
curl -X POST https://api.inferrex.com/v1/pipelines/PIPELINE_ID/sync \
-H "X-API-Key: $INFERREX_API_KEY" \
-H "Idempotency-Key: nightly-sync-2026-11-11" \
-H "Content-Type: application/json" \
-d '{"syncType": "incremental"}'
| Answer | Meaning |
|---|---|
409 idempotency_key_reused |
The same key was sent with a different request body. Use a new key. |
409 request_in_progress |
A request with this key is still running. Retry shortly. |
409 idempotent_replay_withheld |
The first request succeeded and its answer carried a credential shown only once, so it cannot be replayed. Do not retry. List or rotate the resource. |
Long-running work
Calls that take time return at once with a job id. This covers the first read of a system, a match, a dry run, a sync and turning a flow on.
curl https://api.inferrex.com/v1/jobs/JOB_ID \
-H "X-API-Key: $INFERREX_API_KEY"
Response shape, trimmed:
{
id: string;
kind: string; // for example pipeline.sync
status: string; // queued, running, succeeded, failed, cancelled
progress: number | null;
result: { /* depends on the kind */ } | null;
error: string | null;
createdAt: string;
cancelRequestedAt: string | null;
pipelineId: string | null;
connectionId: string | null;
}
Poll until status is succeeded, failed or cancelled. GET /v1/jobs lists recent jobs. POST /v1/jobs/:id/cancel asks a sync or dry run to stop.
Lists
Lists are paged. Most take limit and offset. Some take a cursor: pass the nextCursor from one page to get the next. Many lists accept filters named after their fields and a text search q. The OpenAPI document shows which.
Errors
Every error has the same body:
{
error: string; // a stable code, such as scope_denied
message: string; // what went wrong, in plain words
retryable: boolean; // true when sending the same request again could succeed
docs_url: string;
details?: unknown;
requestId?: string;
}
Branch on error, not on message. Quote requestId when you ask for help.
| Status | Code | What to do |
|---|---|---|
| 400 | validation_error |
Fix the field named in details. |
| 401 | unauthorized |
The key is missing, wrong or revoked. |
| 403 | scope_denied |
The key lacks the scope named in the message. |
| 403 | forbidden |
Your role lacks the permission. |
| 403 | ip_not_permitted |
Your address is not on the workspace's IP allowlist. |
| 404 | not_found |
No such record in your workspace. An id from another workspace also answers 404. |
| 409 | conflict and route-specific codes |
The record is not in a state that allows this. The message says why. |
| 429 | rate_limited |
Wait for the time in the Retry-After header, then retry. |
| 501 | not_implemented |
The operation is not available. Do not retry. |
| 503 | service_unavailable |
Retry shortly. |
Route-specific codes this guide relies on:
| Code | Route | Meaning |
|---|---|---|
connection_not_proven (409) |
POST /v1/connections/:id/approve |
No test has read data from the system yet. Run POST /v1/connections/:id/test. |
connection_paused (409) |
Turning on a flow | One of the flow's systems is paused. Resume it first. |
reading_open (409) |
POST /v1/connections/:id/reinfer |
A new reading is already running or waiting for review. Approve or discard it first. |
Outbound webhooks
To have your own software told when things change, register an address:
curl -X POST https://api.inferrex.com/v1/webhooks/subscriptions \
-H "X-API-Key: $INFERREX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://hooks.example.com/inferrex", "event_types": ["pipelines.created"]}'
Leave event_types empty to receive every event.
- Get the signing secret:
POST /v1/webhooks/subscriptions/:id/secret. It is returned once. Calling it again makes a new secret, and the old one stops working straight away. - Send a test:
POST /v1/webhooks/subscriptions/:id/test. If your system answers with success, the webhook is marked as verified. - Check every delivery against the signing secret before you trust it. Every delivery is signed.
In the app: Workspace settings, Outbound webhooks.
Send records to Inferrex yourself
A system whose change feed is set to push takes records from your own code:
- Set the mode:
PUT /v1/connections/:id/change-feedwith{ "mode": "push" }. If the system has no ingest token yet, one is issued and returned once, asingestToken. - Post records:
POST /v1/connections/:id/ingestwith{ "records": [...] }, signed with the ingest token as a Bearer token or in theX-Inferrex-Ingest-Tokenheader. Records are accepted at once (202) and flows are fed from the system's inbound log. - See what arrived:
GET /v1/connections/:id/inbound-events. It returns metadata only.
Rotate the token with POST /v1/connections/:id/change-feed/secret. The old one is refused from that moment.
Next: InferrexMCP.