Inferrex Developers

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.

  1. 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.
  2. Send a test: POST /v1/webhooks/subscriptions/:id/test. If your system answers with success, the webhook is marked as verified.
  3. 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:

  1. Set the mode: PUT /v1/connections/:id/change-feed with { "mode": "push" }. If the system has no ingest token yet, one is issued and returned once, as ingestToken.
  2. Post records: POST /v1/connections/:id/ingest with { "records": [...] }, signed with the ingest token as a Bearer token or in the X-Inferrex-Ingest-Token header. Records are accepted at once (202) and flows are fed from the system's inbound log.
  3. 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.