Skip to main content

Base URL

Every customer has their own tenant, so there is no single shared host. Yours is issued when the tenant is created:
Examples in these docs write $BASE. Set it once and the rest copies and runs:
Two path prefixes:
Never hard-code the host. A client that will be handed to someone on a different tenant should take it as configuration, alongside the credentials.

Authentication

Bearer token. Exchange your email and password for a JWT, then send it on every call.
There are no API keys today. Details and token lifetime in Authentication.

Everything is asynchronous

Nothing blocks and nothing streams. Every long-running operation follows the same shape:
1

Create

POST the thing. You get a key back, plus signed URLs where files are expected.
2

Upload

PUT each file straight to its signed URL. This does not go through the API.
3

Start

POST to start, where the resource has a separate start step.
4

Poll

GET .../progress until the state is terminal.
5

Collect

GET the result. Download URLs are short-lived and signed.
Training and prediction have no separate start: creating them starts them.

Uploading files

When a create response carries uploadTargets, each entry is a place to PUT one file.
Three rules, and breaking any of them gives 403 SignatureDoesNotMatch:
  1. Send Content-Type: text/csv.
  2. Send the header named in requiredHeader, split on the first colon. It may be null, in which case send nothing extra.
  3. Do not send an Authorization header. The signature covers the request. Your bearer token does not belong here and will break it.
Signed URLs expire 60 minutes after the create call. There is no re-sign endpoint: if the window closes, create the resource again.

Polling

Poll .../progress and stop when the state is terminal. Training progress returns nextPollAfterSeconds. Honour it. When it is absent, the job has finished and there is nothing left to wait for. Sensible intervals elsewhere: 15 to 30 seconds for datasets and predictions, 30 to 60 seconds for a refinement, which runs for tens of minutes or longer. Refinement progress also carries progressCompleted and progressTotal. The unit is internal and has no standalone meaning, so rely on the ratio of the two and never on the raw numbers.

Errors

Standard HTTP status codes. The body carries a message written for a person. A 409 on POST /datasets/{key}/clean has two distinct causes, and the message tells them apart: an input file has not arrived yet, or the dataset was already cleaned. The second is usually harmless.

Limits

Conventions

  • Keys are UUIDs and opaque. Pass them back exactly as given.
  • List endpoints require offset and limit. They are not optional. limit is capped at 100 on refinements.
  • Timestamps are ISO-8601 UTC, for example 2026-09-14T16:27:03.028Z.
  • A null metric means undefined, not zero. A test slice with no positive cases leaves recall undefined. Treat it as absent; reporting 0 says something different and wrong.
  • Multipart uploads use a part named _file. The underscore is not a typo. It is the only name the server binds.

Next

Authentication

Tokens, lifetime, and handling expiry.

Recipes

Complete curl flows for both products.

Build an agent or CLI

The full contract in one page, written to be read by a machine.

Endpoint reference

Every endpoint, generated from the spec.