Contents
Partner
GETWho this key belongs toCustomers
GETYour customersPOSTAdd a customer (charged first)GETOne customerPATCHRename, or change the contact emailPOSTChange a workspace's plan or add-onsPOSTAdd another paid workspacePOSTStop paying for a workspacePOSTHand the customer over (it goes direct)POSTCancel the customerPOSTSend a resold customer's set-up link againGETDownload the customer's dataModels
GETThe customer's modelsPOSTCreate a modelGETOne model and its versionsPATCHRename or describe a modelDELETEDelete a modelPOSTWhich columns say something about the answerPOSTSend the training dataPOSTChoose the columns, after sending a fileGETThe data-quality findingsPOSTMerge categories, leave some out, or remove duplicatesPOSTStart trainingGETTraining progress, then the reportPOSTMake a trained version livePredictions
POSTAsk the published model, one record or manyPOSTAsk the published model one record, flat answerPOSTStart a batch fillGETFill progress, then the answersGETDownload the filled fileReview Queue
GETAnswers waiting for a personPOSTAnswer onePOSTRetrain with the confirmed answersReference
AuthenticationError codesRate limitingSchemasStayCharted AI Model Trainer Partner API
Version 1.0.0 · Base URL https://amt.staycharted.com · OpenAPI 3.0
For solution partners: software companies that build StayCharted AI Model Trainer (AMT) into their own product under a Solution Partner Agreement. One partner key reaches every customer the partner manages, and nothing else.
What a partner can do by key
- Add customers. Each is its own StayCharted account with its own data area and one workspace on the plan you choose. You pay first: the card on your partner account is charged before the customer exists, and a declined card creates nothing.
- Build, train, test and publish each customer's models, send it rows to classify one at a time or as a batch fill, and work its Review Queue from inside your product.
- Change a customer's plan, add a workspace, hand the customer over so it deals with StayCharted directly, or cancel it.
Two kinds of customer. access: api (the default) is a customer that uses AMT only through your product: no login, and your key does everything. access: login is a resold customer whose own people sign in to AMT: your key manages its plan and workspaces, and never its models or data (partner.customer_signs_in).
The key. Authorization: Bearer amt_partner_…. StayCharted issues it; your account Owner receives a one-time link and sees it once. Up to two keys at a time, so you can replace one without downtime; either can be limited to IP addresses and revoked at once from your Partner page. Keep it in a secrets manager, on your servers only.
Limits. 600 calls a minute per key, and 30 new customers a minute per partner, then 429 with Retry-After. Each customer also keeps its own plan's allowances and rate limit, exactly as a direct customer has.
Errors. JSON with a stable code. Branch on code, never on the error text, which is written for people and may be reworded. A customer, model or job that is not yours answers 404, the same as one that does not exist.
Changes. Additive changes (a new field, a new endpoint) can come at any time, so ignore fields you do not know. A breaking change to a documented endpoint or field comes with 60 days' notice, as the Solution Partner Agreement says.
Activity. Everything done by key appears in the customer's Activity as "via <partner> (Partner API: <key name>)", and every prediction records it.
Questions: partners@staycharted.com.
Authentication
Authorization: Bearer amt_partner_…. Issued by StayCharted; up to two live at once.
GET /api/v1/partner HTTP/1.1
Host: amt.staycharted.com
Authorization: Bearer amt_partner_…
Endpoints
Partner
GET /api/v1/partner— Who this key belongs to
Customers
GET /api/v1/customers— Your customersPOST /api/v1/customers— Add a customer (charged first)GET /api/v1/customers/{customerId}— One customerPATCH /api/v1/customers/{customerId}— Rename, or change the contact emailPOST /api/v1/customers/{customerId}/plan— Change a workspace's plan or add-onsPOST /api/v1/customers/{customerId}/workspaces— Add another paid workspacePOST /api/v1/customers/{customerId}/workspaces/{workspaceId}/remove— Stop paying for a workspacePOST /api/v1/customers/{customerId}/hand-over— Hand the customer over (it goes direct)POST /api/v1/customers/{customerId}/cancel— Cancel the customerPOST /api/v1/customers/{customerId}/resend-link— Send a resold customer's set-up link againGET /api/v1/customers/{customerId}/export— Download the customer's data
Models
GET /api/v1/customers/{customerId}/models— The customer's modelsPOST /api/v1/customers/{customerId}/models— Create a modelGET /api/v1/customers/{customerId}/models/{modelId}— One model and its versionsPATCH /api/v1/customers/{customerId}/models/{modelId}— Rename or describe a modelDELETE /api/v1/customers/{customerId}/models/{modelId}— Delete a modelPOST /api/v1/customers/{customerId}/models/{modelId}/columns— Which columns say something about the answerPOST /api/v1/customers/{customerId}/models/{modelId}/data— Send the training dataPOST /api/v1/customers/{customerId}/models/{modelId}/mapping— Choose the columns, after sending a fileGET /api/v1/customers/{customerId}/models/{modelId}/quality— The data-quality findingsPOST /api/v1/customers/{customerId}/models/{modelId}/quality— Merge categories, leave some out, or remove duplicatesPOST /api/v1/customers/{customerId}/models/{modelId}/train— Start trainingGET /api/v1/customers/{customerId}/models/{modelId}/jobs/{jobId}— Training progress, then the reportPOST /api/v1/customers/{customerId}/models/{modelId}/publish— Make a trained version live
Predictions
POST /api/v1/customers/{customerId}/models/{modelId}/predict— Ask the published model, one record or manyPOST /api/v1/customers/{customerId}/models/{modelId}/classify— Ask the published model one record, flat answerPOST /api/v1/customers/{customerId}/models/{modelId}/fills— Start a batch fillGET /api/v1/customers/{customerId}/models/{modelId}/fills/{fillId}— Fill progress, then the answersGET /api/v1/customers/{customerId}/models/{modelId}/fills/{fillId}/file— Download the filled file
Review Queue
GET /api/v1/customers/{customerId}/models/{modelId}/review— Answers waiting for a personPOST /api/v1/customers/{customerId}/models/{modelId}/review/answer— Answer onePOST /api/v1/customers/{customerId}/models/{modelId}/review/retrain— Retrain with the confirmed answers
Partner
Who the key belongs to.
GET /api/v1/partner
Who this key belongs to
Cheap, and touches no customer, so it is the call to check a key with.
Responses
200 — The partner and this key.
| Field | Type | Required | Notes |
|---|---|---|---|
| partner | object | no | |
| partner.id | string (uuid) | no | |
| partner.name | string | no | |
| partner.discountPercent | number | null | no | |
| key | object | no | |
| key.name | string | no | |
| key.prefix | string | no | The key's first characters, to tell your two keys apart. |
| customers | integer | no | How many customers you manage. |
| billing | object | no | |
| billing.status | string | null | no | |
| billing.paidUntil | string (date-time) | null | no |
{
"partner": {
"id": "5b1f0c3e-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
"name": "Acme Helpdesk",
"discountPercent": 20
},
"key": {
"name": "Production",
"prefix": "amt_partner_7Qk2"
},
"customers": 37,
"billing": {
"status": "active",
"paidUntil": "2026-11-26T00:00:00.000Z"
}
}
Errors: 401, 403, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
Customers
Add, change, hand over and cancel the customers you manage.
GET /api/v1/customers
Your customers
Responses
200 — Every customer you manage, with this month's usage (counts only, never content).
| Field | Type | Required | Notes |
|---|---|---|---|
| customers | array of object | yes | |
| customers[].id | string (uuid) | yes | |
| customers[].name | string | yes | |
| customers[].contactEmail | string | no | |
| customers[].access | string | yes | (one of api, login) |
| customers[].joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| customers[].status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| customers[].plan | string | null | no | The first workspace's plan. |
| customers[].pendingPlan | string | null | no | |
| customers[].addOns | array of string | no | |
| customers[].endsAt | string (date-time) | null | no | |
| customers[].createdAt | string (date-time) | no | |
| customers[].usage | object | null | no | This billing month's counts. Never content. |
| customers[].usage.cycleStart | string (date-time) | null | no | |
| customers[].usage.predictions | integer | no | |
| customers[].usage.predictionsLimit | integer | null | no | |
| customers[].usage.pictures | integer | no | |
| customers[].usage.picturesLimit | integer | null | no | |
| customers[].workspaces | array of object | no | |
| customers[].workspaces[].id | string (uuid) | no | |
| customers[].workspaces[].name | string | no | |
| customers[].workspaces[].plan | string | no | |
| customers[].workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| customers[].workspaces[].changesAt | string (date-time) | null | no | |
| customers[].workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| customers[].workspaces[].archived | boolean | no | |
| customers[].workspaces[].primary | boolean | no | The customer's first workspace. |
| customers[].workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| customers[].workspaces[].addOns | array of string | no | |
| customers[].workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| customers[].workspaces[].usage.cycleStart | string (date-time) | null | no | |
| customers[].workspaces[].usage.predictions | integer | no | |
| customers[].workspaces[].usage.predictionsLimit | integer | null | no | |
| customers[].workspaces[].usage.pictures | integer | no | |
| customers[].workspaces[].usage.picturesLimit | integer | null | no | |
| customers[].ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Errors: 401, 403, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers
Add a customer (charged first)
Charges your card for the rest of this month on the chosen plan and add-ons, at your discount, and only then creates the customer's account and its first workspace. A declined card creates nothing (402).
For access: api (the default) the plan must include the API: Essentials or Business. With login: true the customer is resold: its contact becomes the account's Owner and gets a link to set a password (or, if the address already signs in to StayCharted, the account appears in their workspace switcher).
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | |
| plan | string | yes | (one of essentials, business) |
| addOns | array of string | no | Add-on ids. vision reads pictures; byom is Your AI Models. What a plan offers is on the pricing page. |
| contactEmail | string (email) | yes | The customer's contact. For access: api, the address that gets a login link if the customer is ever handed over; nothing is sent before then. For a resold customer (login: true), the account's Owner, mailed at once. |
| login | boolean | no | True for a resold customer whose own people sign in to AMT. |
{
"name": "Northwind Traders",
"plan": "essentials",
"addOns": [
"vision"
],
"contactEmail": "it@northwind.example"
}
Responses
201 — Paid for and created.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| name | string | yes | |
| contactEmail | string | no | |
| access | string | yes | (one of api, login) |
| joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| plan | string | null | no | The first workspace's plan. |
| pendingPlan | string | null | no | |
| addOns | array of string | no | |
| endsAt | string (date-time) | null | no | |
| createdAt | string (date-time) | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no | |
| workspaces | array of object | no | |
| workspaces[].id | string (uuid) | no | |
| workspaces[].name | string | no | |
| workspaces[].plan | string | no | |
| workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| workspaces[].changesAt | string (date-time) | null | no | |
| workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| workspaces[].archived | boolean | no | |
| workspaces[].primary | boolean | no | The customer's first workspace. |
| workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| workspaces[].addOns | array of string | no | |
| workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| workspaces[].usage.cycleStart | string (date-time) | null | no | |
| workspaces[].usage.predictions | integer | no | |
| workspaces[].usage.predictionsLimit | integer | null | no | |
| workspaces[].usage.pictures | integer | no | |
| workspaces[].usage.picturesLimit | integer | null | no | |
| ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Errors: 400, 402, 409, 401, 403, 429, 502
400 — Something in the request is missing or not offered.
Example — name
{
"error": "Give the customer a name.",
"code": "partner.customer_name"
}
Example — contact
{
"error": "Give the customer contact’s email address.",
"code": "partner.contact_email"
}
Example — plan
{
"error": "Choose a plan for the customer: \"essentials\" or \"business\".",
"code": "partner.plan"
}
Example — plan_no_api
{
"error": "That plan does not include the API, so a partner's product cannot use it.",
"code": "partner.plan_no_api"
}
Example — addon
{
"error": "The faces add-on cannot be added: there is no such add-on.",
"code": "partner.addon"
}
402 — Your card was not charged, so nothing was created or changed.
Example — declined
{
"error": "Your card was not charged, so nothing was created or changed. Update the card on your Partner page in StayCharted, then try again.",
"code": "partner.payment_declined"
}
Example — no_card
{
"error": "There is no card on your partner account yet. Add one on your Partner page in StayCharted, then try again.",
"code": "partner.card_required"
}
409 — Another change to your bill is going through. Retry in a minute.
{
"error": "Another change to this partner’s bill is still going through. Try again in a minute.",
"code": "partner.busy"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
502 — The payment processor could not be reached or refused the change for another reason. Nothing was changed; retry later.
{
"error": "Stripe refused the change: …",
"code": "partner.billing_unavailable"
}
GET /api/v1/customers/{customerId}
One customer
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Responses
200 — The customer.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| name | string | yes | |
| contactEmail | string | no | |
| access | string | yes | (one of api, login) |
| joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| plan | string | null | no | The first workspace's plan. |
| pendingPlan | string | null | no | |
| addOns | array of string | no | |
| endsAt | string (date-time) | null | no | |
| createdAt | string (date-time) | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no | |
| workspaces | array of object | no | |
| workspaces[].id | string (uuid) | no | |
| workspaces[].name | string | no | |
| workspaces[].plan | string | no | |
| workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| workspaces[].changesAt | string (date-time) | null | no | |
| workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| workspaces[].archived | boolean | no | |
| workspaces[].primary | boolean | no | The customer's first workspace. |
| workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| workspaces[].addOns | array of string | no | |
| workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| workspaces[].usage.cycleStart | string (date-time) | null | no | |
| workspaces[].usage.predictions | integer | no | |
| workspaces[].usage.predictionsLimit | integer | null | no | |
| workspaces[].usage.pictures | integer | no | |
| workspaces[].usage.picturesLimit | integer | null | no | |
| ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Errors: 401, 403, 404, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
PATCH /api/v1/customers/{customerId}
Rename, or change the contact email
A resold customer names its own account (409 partner.customer_names_itself); its contact email can still change.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | no | |
| contactEmail | string (email) | no |
Responses
200 — The customer, changed.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| name | string | yes | |
| contactEmail | string | no | |
| access | string | yes | (one of api, login) |
| joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| plan | string | null | no | The first workspace's plan. |
| pendingPlan | string | null | no | |
| addOns | array of string | no | |
| endsAt | string (date-time) | null | no | |
| createdAt | string (date-time) | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no | |
| workspaces | array of object | no | |
| workspaces[].id | string (uuid) | no | |
| workspaces[].name | string | no | |
| workspaces[].plan | string | no | |
| workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| workspaces[].changesAt | string (date-time) | null | no | |
| workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| workspaces[].archived | boolean | no | |
| workspaces[].primary | boolean | no | The customer's first workspace. |
| workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| workspaces[].addOns | array of string | no | |
| workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| workspaces[].usage.cycleStart | string (date-time) | null | no | |
| workspaces[].usage.predictions | integer | no | |
| workspaces[].usage.predictionsLimit | integer | null | no | |
| workspaces[].usage.pictures | integer | no | |
| workspaces[].usage.picturesLimit | integer | null | no | |
| ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Errors: 400, 409, 401, 403, 404, 429
400 — An empty name or an address that is not one.
{
"error": "That is not an email address.",
"code": "partner.contact_email"
}
409 — A resold customer names its own account.
{
"error": "This customer signs in to StayCharted and names its own account.",
"code": "partner.customer_names_itself"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/plan
Change a workspace's plan or add-ons
An upgrade is charged at once and takes effect at once; a downgrade takes effect at the end of the paid month (pendingPlan and changesAt say when). Without workspaceId, the customer's first workspace.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| plan | string | yes | (one of essentials, business) |
| addOns | array of string | no | Add-on ids. vision reads pictures; byom is Your AI Models. What a plan offers is on the pricing page. |
| workspaceId | string (uuid) | no |
{
"plan": "business",
"addOns": []
}
Responses
200 — The customer, with the change made or scheduled.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| name | string | yes | |
| contactEmail | string | no | |
| access | string | yes | (one of api, login) |
| joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| plan | string | null | no | The first workspace's plan. |
| pendingPlan | string | null | no | |
| addOns | array of string | no | |
| endsAt | string (date-time) | null | no | |
| createdAt | string (date-time) | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no | |
| workspaces | array of object | no | |
| workspaces[].id | string (uuid) | no | |
| workspaces[].name | string | no | |
| workspaces[].plan | string | no | |
| workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| workspaces[].changesAt | string (date-time) | null | no | |
| workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| workspaces[].archived | boolean | no | |
| workspaces[].primary | boolean | no | The customer's first workspace. |
| workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| workspaces[].addOns | array of string | no | |
| workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| workspaces[].usage.cycleStart | string (date-time) | null | no | |
| workspaces[].usage.predictions | integer | no | |
| workspaces[].usage.predictionsLimit | integer | null | no | |
| workspaces[].usage.pictures | integer | no | |
| workspaces[].usage.picturesLimit | integer | null | no | |
| ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Errors: 400, 402, 404, 409, 401, 403, 429, 502
400 — The plan or an add-on is not offered.
{
"error": "Choose a plan for the customer: \"essentials\" or \"business\".",
"code": "partner.plan"
}
402 — Your card was not charged, so nothing was created or changed.
Example — declined
{
"error": "Your card was not charged, so nothing was created or changed. Update the card on your Partner page in StayCharted, then try again.",
"code": "partner.payment_declined"
}
Example — no_card
{
"error": "There is no card on your partner account yet. Add one on your Partner page in StayCharted, then try again.",
"code": "partner.card_required"
}
404 — No such customer, or no such workspace of it.
{
"error": "No such workspace for this customer.",
"code": "partner.workspace_not_found"
}
409 — The customer or the workspace is already ending, or another change to your bill is going through.
Example — customer_ending
{
"error": "That customer is being cancelled, so its plan cannot change.",
"code": "partner.customer_ending"
}
Example — workspace_ending
{
"error": "That workspace is already ending at the end of the paid month.",
"code": "partner.workspace_ending"
}
Example — busy
{
"error": "Another change to this partner’s bill is still going through. Try again in a minute.",
"code": "partner.busy"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
502 — The payment processor could not be reached or refused the change for another reason. Nothing was changed; retry later.
{
"error": "Stripe refused the change: …",
"code": "partner.billing_unavailable"
}
POST /api/v1/customers/{customerId}/workspaces
Add another paid workspace
Charged first, like adding a customer. The name must be new for this customer.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | |
| plan | string | yes | (one of essentials, business) |
| addOns | array of string | no | Add-on ids. vision reads pictures; byom is Your AI Models. What a plan offers is on the pricing page. |
{
"name": "Finance",
"plan": "essentials"
}
Responses
201 — The customer, with the new workspace.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| name | string | yes | |
| contactEmail | string | no | |
| access | string | yes | (one of api, login) |
| joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| plan | string | null | no | The first workspace's plan. |
| pendingPlan | string | null | no | |
| addOns | array of string | no | |
| endsAt | string (date-time) | null | no | |
| createdAt | string (date-time) | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no | |
| workspaces | array of object | no | |
| workspaces[].id | string (uuid) | no | |
| workspaces[].name | string | no | |
| workspaces[].plan | string | no | |
| workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| workspaces[].changesAt | string (date-time) | null | no | |
| workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| workspaces[].archived | boolean | no | |
| workspaces[].primary | boolean | no | The customer's first workspace. |
| workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| workspaces[].addOns | array of string | no | |
| workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| workspaces[].usage.cycleStart | string (date-time) | null | no | |
| workspaces[].usage.predictions | integer | no | |
| workspaces[].usage.predictionsLimit | integer | null | no | |
| workspaces[].usage.pictures | integer | no | |
| workspaces[].usage.picturesLimit | integer | null | no | |
| ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Errors: 400, 402, 409, 401, 403, 404, 429, 502
400 — No name, or a plan or add-on that is not offered.
{
"error": "Give the workspace a name.",
"code": "partner.workspace_name"
}
402 — Your card was not charged, so nothing was created or changed.
Example — declined
{
"error": "Your card was not charged, so nothing was created or changed. Update the card on your Partner page in StayCharted, then try again.",
"code": "partner.payment_declined"
}
Example — no_card
{
"error": "There is no card on your partner account yet. Add one on your Partner page in StayCharted, then try again.",
"code": "partner.card_required"
}
409 — The name is taken, the customer is ending, or another change to your bill is going through.
{
"error": "This customer already has a workspace called \"Finance\".",
"code": "partner.workspace_name_taken"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
502 — The payment processor could not be reached or refused the change for another reason. Nothing was changed; retry later.
{
"error": "Stripe refused the change: …",
"code": "partner.billing_unavailable"
}
POST /api/v1/customers/{customerId}/workspaces/{workspaceId}/remove
Stop paying for a workspace
The workspace runs to the end of the paid month, then is archived. The customer's first workspace cannot be removed this way: cancel the customer instead (partner.workspace_primary).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| workspaceId | string (uuid) | yes |
Responses
200 — The customer, with the workspace's endsAt set.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| name | string | yes | |
| contactEmail | string | no | |
| access | string | yes | (one of api, login) |
| joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| plan | string | null | no | The first workspace's plan. |
| pendingPlan | string | null | no | |
| addOns | array of string | no | |
| endsAt | string (date-time) | null | no | |
| createdAt | string (date-time) | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no | |
| workspaces | array of object | no | |
| workspaces[].id | string (uuid) | no | |
| workspaces[].name | string | no | |
| workspaces[].plan | string | no | |
| workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| workspaces[].changesAt | string (date-time) | null | no | |
| workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| workspaces[].archived | boolean | no | |
| workspaces[].primary | boolean | no | The customer's first workspace. |
| workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| workspaces[].addOns | array of string | no | |
| workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| workspaces[].usage.cycleStart | string (date-time) | null | no | |
| workspaces[].usage.predictions | integer | no | |
| workspaces[].usage.predictionsLimit | integer | null | no | |
| workspaces[].usage.pictures | integer | no | |
| workspaces[].usage.picturesLimit | integer | null | no | |
| ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Errors: 404, 409, 401, 403, 429
404 — No such customer, or no such workspace of it.
{
"error": "No such workspace for this customer.",
"code": "partner.workspace_not_found"
}
409 — It is the first workspace, or it is already ending.
{
"error": "That is the customer’s first workspace. To stop paying for it, cancel the customer.",
"code": "partner.workspace_primary"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/hand-over
Hand the customer over (it goes direct)
Your key stops reaching the account at once and the customer leaves your list. The plan runs to the end of the month you paid for; then the customer pays StayCharted itself. An access: api customer's contact email (the one on file) gets a link to set up a login. A resold customer keeps its login and is told billing is now theirs.
If the contact's address belongs to a StayCharted login that never confirmed it, nothing changes (409 partner.contact_unconfirmed): the address is asked to confirm first, then you call this again.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Responses
200 — Handed over.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| status | string | yes | (one of handed_over) |
| contactEmail | string | no | |
| paidUntil | string (date-time) | null | no |
Errors: 409, 401, 403, 404, 429
409 — The contact has not confirmed the address, or another change to your bill is going through.
{
"error": "The contact’s address belongs to a StayCharted login that has not confirmed it.",
"code": "partner.contact_unconfirmed"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/cancel
Cancel the customer
Every workspace runs to the end of the paid month, and your bill drops from the next invoice. For 30 days after that your key can still download the customer's export, and nothing else; then the account is closed and its data deleted.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Responses
200 — The customer, now cancelling, with endsAt.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| name | string | yes | |
| contactEmail | string | no | |
| access | string | yes | (one of api, login) |
| joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| plan | string | null | no | The first workspace's plan. |
| pendingPlan | string | null | no | |
| addOns | array of string | no | |
| endsAt | string (date-time) | null | no | |
| createdAt | string (date-time) | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no | |
| workspaces | array of object | no | |
| workspaces[].id | string (uuid) | no | |
| workspaces[].name | string | no | |
| workspaces[].plan | string | no | |
| workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| workspaces[].changesAt | string (date-time) | null | no | |
| workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| workspaces[].archived | boolean | no | |
| workspaces[].primary | boolean | no | The customer's first workspace. |
| workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| workspaces[].addOns | array of string | no | |
| workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| workspaces[].usage.cycleStart | string (date-time) | null | no | |
| workspaces[].usage.predictions | integer | no | |
| workspaces[].usage.predictionsLimit | integer | null | no | |
| workspaces[].usage.pictures | integer | no | |
| workspaces[].usage.picturesLimit | integer | null | no | |
| ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Errors: 409, 401, 403, 404, 429
409 — Already being cancelled, or another change to your bill is going through.
{
"error": "That customer is already being cancelled.",
"code": "partner.already_cancelling"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/resend-link
Send a resold customer's set-up link again
Only while the customer is active and nobody has signed in as its Owner yet.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Responses
200 — Sent to the contact email on file.
| Field | Type | Required | Notes |
|---|---|---|---|
| sent | boolean | no | |
| to | string | no | |
| kind | string | no | Which email was sent. |
Errors: 409, 401, 403, 404, 429
409 — Not a resold customer that is still active, or its Owner has signed in already.
Example — no_link
{
"error": "Only a resold customer that is still active has a set-up link.",
"code": "partner.no_setup_link"
}
Example — signed_in
{
"error": "Someone has already signed in as this customer’s Owner, so there is no set-up link to send.",
"code": "partner.owner_signed_in"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
GET /api/v1/customers/{customerId}/export
Download the customer's data
The same export an account Owner downloads in the app: models, training data, filled files and Activity, as a ZIP. Available while you manage the customer and for 30 days after a cancellation ends. Not for a resold customer, whose Owner exports it.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Responses
200 — The export.
A file: application/zip.
Errors: 401, 403, 404, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
Models
Build, train, test and publish a customer's models.
GET /api/v1/customers/{customerId}/models
The customer's models
Every model, published or not.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Responses
200 — The models.
| Field | Type | Required | Notes |
|---|---|---|---|
| models | array of object | yes | |
| models[].id | string (uuid) | no | |
| models[].name | string | no | |
| models[].description | string | no | |
| models[].modality | string | no | (one of text, image) |
| models[].status | string | no | Where the model is, as the app's Models screen says it. |
| models[].published | boolean | no | |
| models[].liveVersion | string (uuid) | null | no | |
| models[].latestVersion | string (uuid) | null | no | |
| models[].accuracy | number | null | no | The latest version's accuracy on held-out rows, 0 to 1. |
Errors: 401, 403, 404, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models
Create a model
Then send its training data (/data), check it (/quality), train (/train), read the report (/jobs/{jobId}) and publish (/publish).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | |
| description | string | no | |
| modality | string | no | image for a model that reads pictures (the customer's plan needs Vision). (one of text, image) |
{
"name": "Ticket routing",
"description": "Which team a new ticket goes to.",
"modality": "text"
}
Responses
201 — Created, with no data yet.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | no | |
| name | string | no | |
| description | string | no | |
| modality | string | no | (one of text, image) |
| status | string | no | Where the model is, as the app's Models screen says it. |
| published | boolean | no | |
| liveVersion | string (uuid) | null | no | |
| latestVersion | string (uuid) | null | no | |
| accuracy | number | null | no | The latest version's accuracy on held-out rows, 0 to 1. |
Errors: 400, 402, 401, 403, 404, 429
400 — No name.
{
"error": "Give the model a name.",
"code": "partner.model_name"
}
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No customer of yours with that id.
{
"error": "No such customer of this partner.",
"code": "partner.customer_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
GET /api/v1/customers/{customerId}/models/{modelId}
One model and its versions
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Responses
200 — The model, with every training run.
A Model, with every training run.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | no | |
| name | string | no | |
| description | string | no | |
| modality | string | no | (one of text, image) |
| status | string | no | |
| published | boolean | no | |
| liveVersion | string (uuid) | null | no | |
| latestVersion | string (uuid) | null | no | |
| accuracy | number | null | no | |
| versions | array of object | no | |
| versions[].id | string (uuid) | no | |
| versions[].status | string | no | |
| versions[].engine | string | null | no | |
| versions[].accuracy | number | null | no | |
| versions[].startedAt | string (date-time) | null | no | |
| versions[].live | boolean | no |
Errors: 401, 403, 404, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
PATCH /api/v1/customers/{customerId}/models/{modelId}
Rename or describe a model
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | no | |
| description | string | no |
Responses
200 — The model, changed.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | no | |
| name | string | no | |
| description | string | no | |
| modality | string | no | (one of text, image) |
| status | string | no | Where the model is, as the app's Models screen says it. |
| published | boolean | no | |
| liveVersion | string (uuid) | null | no | |
| latestVersion | string (uuid) | null | no | |
| accuracy | number | null | no | The latest version's accuracy on held-out rows, 0 to 1. |
Errors: 401, 403, 404, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
DELETE /api/v1/customers/{customerId}/models/{modelId}
Delete a model
The model, its versions and its training data. It cannot be undone.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Responses
200 — Deleted.
| Field | Type | Required | Notes |
|---|---|---|---|
| deleted | boolean | no | |
| id | string (uuid) | no |
Errors: 401, 403, 404, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models/{modelId}/columns
Which columns say something about the answer
Optional, before sending data. Measures each column against the answers on up to 2,000 rows that have one, and recommends which ones the model should read. Nothing is stored.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| columns | array of string | yes | The column names, unique, up to 200. |
| rows | array of array of string | yes | Rows of values, each with one value per column, in the order of columns. Values are read as text. |
| labelColumn | string | yes | The column that holds the answer. |
Responses
200 — A verdict per column, and the recommended set.
| Field | Type | Required | Notes |
|---|---|---|---|
| labelColumn | string | no | |
| rowsMeasured | integer | no | |
| recommended | array of string | no | |
| columns | array of object | no | |
| columns[].column | string | no | |
| columns[].verdict | string | no | |
| columns[].reason | string | no |
Errors: 400, 401, 403, 404, 429
400 — The rows or columns are not usable.
Example — rows
{
"error": "There are no rows to send.",
"code": "partner.rows"
}
Example — label
{
"error": "Choose the column that holds the answers.",
"code": "partner.label_column"
}
Example — inputs
{
"error": "Choose at least one column for the model to read.",
"code": "partner.input_columns"
}
Example — answers
{
"error": "No row has an answer in that column yet.",
"code": "partner.no_answers"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models/{modelId}/data
Send the training data
Two ways:
- JSON rows (
application/json): the columns, the rows, which columns the model reads and which holds the answer, in one call. The answer is the data-quality summary. - A file (
multipart/form-data, fieldfile): a CSV or a spreadsheet, or for a picture model a ZIP of folders named by category or a spreadsheet of picture links. Then choose the columns with/mapping, as the app does in two steps.
Sending data again replaces the model's training data.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| columns | array of string | yes | The column names, unique, up to 200. |
| rows | array of array of string | yes | Rows of values, each with one value per column, in the order of columns. Values are read as text. |
| inputColumns | array of string | yes | The columns the model reads. |
| labelColumn | string | yes | The column that holds the answer. |
{
"columns": [
"Subject",
"Body",
"Team"
],
"rows": [
[
"Charged twice",
"My card shows two payments for one order.",
"Billing"
],
[
"Cannot sign in",
"The reset link says it has expired.",
"Account access"
]
],
"inputColumns": [
"Subject",
"Body"
],
"labelColumn": "Team"
}
Or a file, as multipart/form-data with the field file.
Responses
200 — For JSON rows, the data-quality summary. For a file, its columns, ready for /mapping.
JSON rows: rowsSent plus the Quality fields. A file: uploaded, columns, rows, and imageColumns for a picture file.
| Field | Type | Required | Notes |
|---|---|---|---|
| rowsSent | integer | no | |
| uploaded | boolean | no | |
| columns | array of string | no | |
| rows | integer | null | no | |
| imageColumns | array of string | no | |
| usableRows | integer | null | no | |
| categoryCount | integer | null | no | |
| distribution | array of object | no | |
| duplicateCount | integer | no | |
| rareCategoryCount | integer | no | |
| verdict | string | null | no | |
| reasons | array of object | no |
Errors: 400, 402, 401, 403, 404, 429
400 — The rows or columns are not usable.
Example — rows
{
"error": "There are no rows to send.",
"code": "partner.rows"
}
Example — label
{
"error": "Choose the column that holds the answers.",
"code": "partner.label_column"
}
Example — inputs
{
"error": "Choose at least one column for the model to read.",
"code": "partner.input_columns"
}
Example — answers
{
"error": "No row has an answer in that column yet.",
"code": "partner.no_answers"
}
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models/{modelId}/mapping
Choose the columns, after sending a file
A text model: inputColumns and labelColumn. A picture model: imageColumn, and where the category comes from (labelColumn, or a labelRule such as the folder name), plus any textColumns it should read with each picture. Picture data is then imported in the background (importing: true); read /quality when it is done.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| inputColumns | array of string | no | |
| labelColumn | string | no | |
| imageColumn | string | no | |
| labelRule | object | no | |
| textColumns | array of string | no |
Responses
200 — A text model's quality summary, or a picture model's import status.
| Field | Type | Required | Notes |
|---|---|---|---|
| accepted | boolean | no | |
| status | string | null | no | |
| importing | boolean | no | |
| usableRows | integer | null | no | |
| categoryCount | integer | null | no | |
| verdict | string | null | no |
Errors: 401, 403, 404, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
GET /api/v1/customers/{customerId}/models/{modelId}/quality
The data-quality findings
The same findings as the app's Check data step. Pass version back with a fix, so a fix is never applied to data that has changed since.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Responses
200 — The findings.
| Field | Type | Required | Notes |
|---|---|---|---|
| version | string | null | no | Pass back with a fix. |
| usableRows | integer | null | no | |
| categoryCount | integer | null | no | |
| distribution | array of object | no | Rows per category. |
| duplicateCount | integer | no | |
| rareCategoryCount | integer | no | |
| verdict | string | null | no | Whether the data is ready to train, as the app's Check data step says. |
| reasons | array of object | no | |
| duplicates | array of object | no |
Errors: 401, 403, 404, 429
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models/{modelId}/quality
Merge categories, leave some out, or remove duplicates
Send exactly one of mergeLabels, excludeCategories or removeDuplicates, with the version from GET.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| version | string | no | |
| mergeLabels | array of object | no | Categories that are the same thing, folded into one. |
| mergeLabels[].canonical | string | yes | |
| mergeLabels[].variants | array of string | yes | |
| excludeCategories | array of string | no | Categories to leave out of training, every row of them. |
| removeDuplicates | array of integer | no | Indexes of duplicate rows to remove, as GET lists them. |
{
"version": "2026-10-26T09:07:12.418Z",
"mergeLabels": [
{
"canonical": "Billing",
"variants": [
"billing",
"Invoices"
]
}
]
}
Responses
200 — The quality summary after the change.
| Field | Type | Required | Notes |
|---|---|---|---|
| version | string | null | no | Pass back with a fix. |
| usableRows | integer | null | no | |
| categoryCount | integer | null | no | |
| distribution | array of object | no | Rows per category. |
| duplicateCount | integer | no | |
| rareCategoryCount | integer | no | |
| verdict | string | null | no | Whether the data is ready to train, as the app's Check data step says. |
| reasons | array of object | no | |
| duplicates | array of object | no |
Errors: 400, 401, 403, 404, 409, 429
400 — None of the three was sent.
{
"error": "Send mergeLabels, excludeCategories or removeDuplicates.",
"code": "partner.quality_action"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
409 — The data changed since version; read it again.
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models/{modelId}/train
Start training
202 with a job id; training runs on a queue. Poll /jobs/{jobId} every 15 to 60 seconds.
Engines, by what the customer's plan includes:
- text:
classifier(words only),ai_classifier(reads meaning; Essentials and up),dedicated(a Dedicated AI Model fine-tuned on a GPU; Business) - image:
ai_image_classifier(Vision),dedicated(Business with Vision)
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| engine | string | yes | (one of classifier, ai_classifier, ai_image_classifier, dedicated) |
{
"engine": "ai_classifier"
}
Responses
202 — Queued.
| Field | Type | Required | Notes |
|---|---|---|---|
| jobId | string (uuid) | null | no | |
| status | string | no | |
| engine | string | no |
Errors: 400, 402, 401, 403, 404, 429
400 — An engine this model cannot use, or no Dedicated training for this customer.
Example — engine
{
"error": "Choose the engine: classifier, ai_classifier, dedicated.",
"code": "partner.engine"
}
Example — dedicated
{
"error": "Dedicated AI training is not available for this customer.",
"code": "partner.dedicated_unavailable"
}
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
GET /api/v1/customers/{customerId}/models/{modelId}/jobs/{jobId}
Training progress, then the report
When status is completed, report holds the test on rows the model never trained on.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes | |
| jobId | string (uuid) | yes |
Responses
200 — The run.
| Field | Type | Required | Notes |
|---|---|---|---|
| jobId | string (uuid) | no | |
| status | string | no | queued, running, completed, failed or cancelled. |
| stage | string | null | no | What it is doing now, in words. |
| failure | string | null | no | |
| report | object | null | no | The test on held-out rows, once completed. |
| report.versionId | string (uuid) | no | |
| report.isLive | boolean | no | |
| report.accuracy | number | null | no | |
| report.baseline | number | null | no | Always guessing the commonest category. |
| report.testedOn | integer | null | no | |
| report.trainedOn | integer | null | no | |
| report.perCategory | array of object | no | |
| report.perCategory[].category | string | no | |
| report.perCategory[].accuracy | number | no | |
| report.perCategory[].correct | integer | no | |
| report.perCategory[].total | integer | no |
Errors: 404, 401, 403, 429
404 — No such run for this model.
{
"error": "No such training run.",
"code": "partner.job_not_found"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models/{modelId}/publish
Make a trained version live
Without jobId, the latest completed version. The previous live version stops answering.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| jobId | string (uuid) | no |
Responses
200 — Live.
| Field | Type | Required | Notes |
|---|---|---|---|
| published | boolean | no | |
| jobId | string (uuid) | null | no |
Errors: 402, 401, 403, 404, 429
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
Predictions
Ask a customer's published model, one record or a batch.
POST /api/v1/customers/{customerId}/models/{modelId}/predict
Ask the published model, one record or many
As the Prediction API's predict (openapi.yaml), under the customer's path. input for one record, inputs for up to 100. Each record is a string, an object of the fields the model reads, or for a picture model a link or {"imageBase64": "..."}. Counted against the customer's monthly predictions; the whole request is checked first, so it is refused whole rather than half served.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
Exactly one of input or inputs; the server enforces it.
| Field | Type | Required | Notes |
|---|---|---|---|
| input | any | no | One record. A string, an object of the fields the model reads, or for a picture model a link or {"imageBase64":"..."}. |
| inputs | array of any | no | Up to 100 records, each as input takes one (up to 20 pictures). (minItems: 1, maxItems: 100) |
{
"inputs": [
"My card was charged twice for the same order",
"The parcel arrived damaged"
]
}
Responses
200 — One prediction per record, in the order sent.
| Field | Type | Required | Notes |
|---|---|---|---|
| model | object | no | |
| model.id | string (uuid) | no | |
| model.name | string | no | |
| predictions | array of object | no | |
| predictions[].input | any | no | The record, echoed back. |
| predictions[].label | string | null | no | |
| predictions[].confidence | number | null | no | 0 to 1. |
| predictions[].needsReview | boolean | no | Below the model's review cutoff; the answer went to the Review Queue. |
| predictions[].labels | array of string | no | For a model whose answer is a list. |
| predictions[].fields | object | no | For a model whose answer has several columns. |
| predictions[].error | string | no | A picture that could not be used, as a code. |
| predictions[].message | string | no | |
| usage | object | no | |
| usage.predictions | integer | no | Records counted by this request. |
Errors: 400, 402, 409, 401, 403, 404, 429, 503
400 — The records are missing or not the shape the model reads.
{
"error": "Send \"input\" with one string, or \"inputs\" with an array of them.",
"code": "api.input_required"
}
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
409 — The model is not published, or needs retraining.
{
"error": "That model is not deployed yet.",
"code": "api.model_not_deployed"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
503 — A service the model depends on is restarting. Nothing was counted; retry after a short wait.
{
"error": "This model is temporarily unable to answer. Try again in a few minutes.",
"code": "api.model_unavailable"
}
POST /api/v1/customers/{customerId}/models/{modelId}/classify
Ask the published model one record, flat answer
One record, and every value of the answer a top-level key, for tools that bind fields from a list.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| input | any | yes | A string, an object of the fields the model reads, or for a picture model a link or {"imageBase64":"..."} (with "text" for a model that also reads text). |
{
"input": "My card was charged twice for the same order"
}
Responses
200 — The answer.
| Field | Type | Required | Notes |
|---|---|---|---|
| label | string | null | no | |
| confidence | number | null | no | |
| needsReview | boolean | no | |
| labels | array of string | no | |
| fields | object | no | |
| modelId | string (uuid) | no | |
| modelName | string | no | |
| error | string | no | |
| message | string | no |
{
"label": "Billing",
"confidence": 0.94,
"needsReview": false,
"modelId": "8f14e45f-ceea-467a-9b2c-1d5c2b0e7a11",
"modelName": "Ticket routing"
}
Errors: 400, 402, 409, 401, 403, 404, 429, 503
400 — No input.
{
"error": "Send \"input\" with the text to classify.",
"code": "api.input_missing"
}
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
409 — The model is not published, or needs retraining.
{
"error": "That model is not deployed yet.",
"code": "api.model_not_deployed"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
503 — A service the model depends on is restarting. Nothing was counted; retry after a short wait.
{
"error": "This model is temporarily unable to answer. Try again in a few minutes.",
"code": "api.model_unavailable"
}
POST /api/v1/customers/{customerId}/models/{modelId}/fills
Start a batch fill
For many records at once: 202 with a fill id, then poll /fills/{fillId}. Send JSON rows (each an object of the columns the model reads), or a file (multipart/form-data, field file): a CSV, a spreadsheet, or for a picture model a ZIP of pictures. A file can say which column to write the answer into with ?targetColumn=; the default is "StayCharted category". Counted against the customer's monthly predictions, like a fill in the app.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| targetColumn | string | no | For a file, the name of the answer column. JSON rows always use "StayCharted category". |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| rows | array of object | yes |
{
"rows": [
{
"Subject": "Charged twice",
"Body": "My card shows two payments for one order."
}
]
}
Or a file, as multipart/form-data with the field file.
Responses
202 — Queued.
| Field | Type | Required | Notes |
|---|---|---|---|
| fillId | string (uuid) | null | no | |
| status | string | no | |
| rows | integer | no |
Errors: 400, 402, 401, 403, 404, 429
400 — No rows, or rows that are not records.
{
"error": "Send rows: a list of records, each one the columns the model reads.",
"code": "partner.fill_rows"
}
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
GET /api/v1/customers/{customerId}/models/{modelId}/fills/{fillId}
Fill progress, then the answers
When status is completed, answers holds one per row in the order sent, and file the path of the filled file.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes | |
| fillId | string (uuid) | yes |
Responses
200 — The fill.
| Field | Type | Required | Notes |
|---|---|---|---|
| fillId | string (uuid) | no | |
| status | string | no | queued, running, completed, failed or cancelled. |
| filled | integer | null | no | |
| total | integer | null | no | |
| failure | string | null | no | |
| answers | array of object | no | Once completed, one per row, in the order sent. |
| answers[].category | string | null | no | |
| answers[].confidence | number | null | no | |
| file | string | no | Once completed, the path of the filled file. |
Errors: 404, 401, 403, 429
404 — No such fill for this model.
{
"error": "No such fill.",
"code": "partner.fill_not_found"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
GET /api/v1/customers/{customerId}/models/{modelId}/fills/{fillId}/file
Download the filled file
The rows as sent, with the answer, its confidence and whether it went for review in new columns, in the format sent.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes | |
| fillId | string (uuid) | yes |
Responses
200 — The filled file.
A file: application/octet-stream.
Errors: 404, 401, 403, 429
404 — No such fill, or it is not finished.
{
"error": "No such fill.",
"code": "partner.fill_not_found"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
Review Queue
Answers the model was unsure of, for a person to confirm.
GET /api/v1/customers/{customerId}/models/{modelId}/review
Answers waiting for a person
Answers below the model's review cutoff, from every channel (API, fills), with the same question grouped once. Least confident first.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| state | string | no | |
| offset | integer | no | |
| limit | integer | no |
Responses
200 — A page of the queue.
| Field | Type | Required | Notes |
|---|---|---|---|
| open | boolean | null | no | Whether the customer's plan has the Review Queue. |
| cutoff | number | null | no | Answers below this confidence come here. |
| counts | object | no | |
| total | integer | no | |
| categories | array of string | no | |
| items | array of object | no | |
| items[].groupKey | string | no | Pass back to answer it. |
| items[].itemId | string | no | |
| items[].size | integer | no | How many times this same question was asked. |
| items[].confidence | number | null | no | |
| items[].predictedLabel | string | null | no | |
| items[].reviewedLabel | string | null | no | |
| items[].sources | array of string | no | The channels it came from. |
| items[].text | string | null | no | |
| items[].inputText | string | null | no | |
| items[].imageHash | string | null | no | |
| items[].firstAt | string (date-time) | no | |
| items[].alternatives | array of object | null | no | The model's next candidates. |
Errors: 402, 401, 403, 404, 429
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models/{modelId}/review/answer
Answer one
The right category in label (pass the model's predictedLabel too, so a correction is recorded as one), or action: skip or action: unsure. A confirmed answer is used the next time the model is retrained.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Request body (application/json)
| Field | Type | Required | Notes |
|---|---|---|---|
| groupKey | string | yes | From the queue's items. |
| label | string | no | |
| predictedLabel | string | no | |
| action | string | no | (one of skip, unsure) |
{
"groupKey": "7d1c0a2e9b",
"label": "Billing",
"predictedLabel": "Account access"
}
Responses
200 — How many rows the answer covered, and the queue's counts.
| Field | Type | Required | Notes |
|---|---|---|---|
| changed | integer | no | |
| counts | object | no |
Errors: 400, 409, 401, 403, 404, 429
400 — No group, or no category.
{
"error": "Choose the right category, or skip it.",
"code": "review.label_required"
}
409 — Someone answered it already.
{
"error": "That answer was already given, or is already in a training run. Reload to see where it is.",
"code": "review.already_answered"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
POST /api/v1/customers/{customerId}/models/{modelId}/review/retrain
Retrain with the confirmed answers
Adds the confirmed answers to the training data and starts a new version (202), on the same engine. Publishing it is a separate call, after you have read its report.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string (uuid) | yes | The customer's id, from GET /api/v1/customers. |
| modelId | string (uuid) | yes |
Responses
200 — Nothing to train on after all; the answers were settled.
202 — Training started.
| Field | Type | Required | Notes |
|---|---|---|---|
| jobId | string (uuid) | no | |
| status | string | no |
Errors: 400, 402, 401, 403, 404, 429
400 — No confirmed answers yet, or the model was never trained.
{
"error": "No reviewed answers are waiting to be trained on.",
"code": "review.nothing_ready"
}
402 — The customer's plan does not allow this, or a monthly allowance is spent (resetsAt says when it refills).
{
"error": "This needs 40 predictions and 12 remain this billing period.",
"code": "plan.prediction_limit",
"entitlement": "predictionsPerMonth",
"limit": 10000,
"used": 9988,
"resetsAt": "2026-11-26T00:00:00.000Z"
}
401 — No partner key, or not a valid one. One answer for every kind of bad key; an address that keeps sending bad keys is told to wait (429 partner.too_many_refusals).
Example — missing
{
"error": "Send your partner key as: Authorization: Bearer amt_partner_….",
"code": "partner.key_missing"
}
Example — invalid
{
"error": "That partner key is not valid.",
"code": "partner.key_invalid"
}
403 — The partner is suspended, the call came from an address the key does not allow, or the customer is resold and signs in itself.
Example — suspended
{
"error": "This partner’s access is suspended. Contact partners@staycharted.com.",
"code": "partner.suspended"
}
Example — address
{
"error": "This key is not allowed from this address.",
"code": "partner.address_not_allowed"
}
Example — signs_in
{
"error": "This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only.",
"code": "partner.customer_signs_in"
}
404 — No such customer of yours, or no such model of that customer.
{
"error": "No such model for this customer.",
"code": "partner.model_not_found"
}
429 — Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | Seconds to wait. |
Example — key
{
"error": "A partner key may make 600 calls a minute. Slow down and retry.",
"code": "partner.rate_limited",
"retryAfter": 12
}
Example — refusals
{
"error": "Too many requests with a missing or invalid partner key from this address. Wait a minute.",
"code": "partner.too_many_refusals",
"retryAfter": 60
}
Error codes
Every error is JSON with a stable code. Branch on the code; the error sentence is for people and may be reworded.
| HTTP | Code | What it means |
|---|---|---|
| 400 | api.input_missing | Send "input" with the text to classify. |
| 400 | api.input_required | Send "input" with one string, or "inputs" with an array of them. |
| 400 | partner.addon | The faces add-on cannot be added: there is no such add-on. |
| 400 | partner.contact_email | Give the customer contact’s email address. |
| 400 | partner.customer_name | Give the customer a name. |
| 400 | partner.dedicated_unavailable | Dedicated AI training is not available for this customer. |
| 400 | partner.engine | Choose the engine: classifier, ai_classifier, dedicated. |
| 400 | partner.fill_rows | Send rows: a list of records, each one the columns the model reads. |
| 400 | partner.input_columns | Choose at least one column for the model to read. |
| 400 | partner.label_column | Choose the column that holds the answers. |
| 400 | partner.model_name | Give the model a name. |
| 400 | partner.no_answers | No row has an answer in that column yet. |
| 400 | partner.plan | Choose a plan for the customer: "essentials" or "business". |
| 400 | partner.plan_no_api | That plan does not include the API, so a partner's product cannot use it. |
| 400 | partner.quality_action | Send mergeLabels, excludeCategories or removeDuplicates. |
| 400 | partner.rows | There are no rows to send. |
| 400 | partner.workspace_name | Give the workspace a name. |
| 400 | review.label_required | Choose the right category, or skip it. |
| 400 | review.nothing_ready | No reviewed answers are waiting to be trained on. |
| 401 | partner.key_invalid | That partner key is not valid. |
| 401 | partner.key_missing | Send your partner key as: Authorization: Bearer amt_partner_…. |
| 402 | partner.card_required | There is no card on your partner account yet. Add one on your Partner page in StayCharted, then try again. |
| 402 | partner.payment_declined | Your card was not charged, so nothing was created or changed. Update the card on your Partner page in StayCharted, then try again. |
| 402 | plan.prediction_limit | This needs 40 predictions and 12 remain this billing period. |
| 403 | partner.address_not_allowed | This key is not allowed from this address. |
| 403 | partner.customer_signs_in | This customer’s own people sign in and use its models, so a partner key reaches its plan and workspaces only. |
| 403 | partner.suspended | This partner’s access is suspended. Contact partners@staycharted.com. |
| 404 | partner.customer_not_found | No such customer of this partner. |
| 404 | partner.fill_not_found | No such fill. |
| 404 | partner.job_not_found | No such training run. |
| 404 | partner.model_not_found | No such model for this customer. |
| 404 | partner.workspace_not_found | No such workspace for this customer. |
| 409 | api.model_not_deployed | That model is not deployed yet. |
| 409 | partner.already_cancelling | That customer is already being cancelled. |
| 409 | partner.busy | Another change to this partner’s bill is still going through. Try again in a minute. |
| 409 | partner.contact_unconfirmed | The contact’s address belongs to a StayCharted login that has not confirmed it. |
| 409 | partner.customer_ending | That customer is being cancelled, so its plan cannot change. |
| 409 | partner.customer_names_itself | This customer signs in to StayCharted and names its own account. |
| 409 | partner.no_setup_link | Only a resold customer that is still active has a set-up link. |
| 409 | partner.owner_signed_in | Someone has already signed in as this customer’s Owner, so there is no set-up link to send. |
| 409 | partner.workspace_ending | That workspace is already ending at the end of the paid month. |
| 409 | partner.workspace_name_taken | This customer already has a workspace called "Finance". |
| 409 | partner.workspace_primary | That is the customer’s first workspace. To stop paying for it, cancel the customer. |
| 409 | review.already_answered | That answer was already given, or is already in a training run. Reload to see where it is. |
| 429 | partner.rate_limited | A partner key may make 600 calls a minute. Slow down and retry. |
| 429 | partner.too_many_refusals | Too many requests with a missing or invalid partner key from this address. Wait a minute. |
| 502 | partner.billing_unavailable | Stripe refused the change: … |
| 503 | api.model_unavailable | This model is temporarily unable to answer. Try again in a few minutes. |
Rate limiting
Too many calls. Wait Retry-After seconds.
| Header | Meaning |
|---|---|
| Retry-After | On a 429: seconds until enough allowance has refilled for this request. |
Schemas
Error
| Field | Type | Required | Notes |
|---|---|---|---|
| error | string | yes | For a person to read. May be reworded; do not match on it. |
| code | string | yes | Stable. Branch on this. |
| reasons | array of object | no | Present when the refusal has several causes. |
PlanError
An Error caused by the customer's plan, with the limit that refused it.
| Field | Type | Required | Notes |
|---|---|---|---|
| error | string | yes | |
| code | string | yes | |
| entitlement | string | null | no | Which plan limit refused this. |
| limit | integer | null | no | |
| used | integer | null | no | |
| resetsAt | string (date-time) | null | no | When a monthly allowance refills; null when waiting will not help. |
RateLimitError
| Field | Type | Required | Notes |
|---|---|---|---|
| error | string | yes | |
| code | string | yes | |
| retryAfter | integer | no | Seconds to wait. |
| retryAfterSeconds | integer | no | The same, on a customer's own prediction limit. |
Partner
| Field | Type | Required | Notes |
|---|---|---|---|
| partner | object | no | |
| partner.id | string (uuid) | no | |
| partner.name | string | no | |
| partner.discountPercent | number | null | no | |
| key | object | no | |
| key.name | string | no | |
| key.prefix | string | no | The key's first characters, to tell your two keys apart. |
| customers | integer | no | How many customers you manage. |
| billing | object | no | |
| billing.status | string | null | no | |
| billing.paidUntil | string (date-time) | null | no |
AddOns
Add-on ids. vision reads pictures; byom is Your AI Models. What a plan offers is on the pricing page.
NewCustomer
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | |
| plan | string | yes | (one of essentials, business) |
| addOns | array of string | no | Add-on ids. vision reads pictures; byom is Your AI Models. What a plan offers is on the pricing page. |
| contactEmail | string (email) | yes | The customer's contact. For access: api, the address that gets a login link if the customer is ever handed over; nothing is sent before then. For a resold customer (login: true), the account's Owner, mailed at once. |
| login | boolean | no | True for a resold customer whose own people sign in to AMT. |
Usage
This billing month's counts. Never content.
| Field | Type | Required | Notes |
|---|---|---|---|
| cycleStart | string (date-time) | null | no | |
| predictions | integer | no | |
| predictionsLimit | integer | null | no | |
| pictures | integer | no | |
| picturesLimit | integer | null | no |
Workspace
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | no | |
| name | string | no | |
| plan | string | no | |
| pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| changesAt | string (date-time) | null | no | |
| endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| archived | boolean | no | |
| primary | boolean | no | The customer's first workspace. |
| joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| addOns | array of string | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no |
Customer
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | yes | |
| name | string | yes | |
| contactEmail | string | no | |
| access | string | yes | (one of api, login) |
| joinedFromDirect | boolean | no | The customer already paid StayCharted itself and asked to be billed through you. Its account was its own before you, so cancelling it moves it back to direct billing rather than closing it. |
| status | string | yes | (one of active, cancelling, cancelled, handed_over) |
| plan | string | null | no | The first workspace's plan. |
| pendingPlan | string | null | no | |
| addOns | array of string | no | |
| endsAt | string (date-time) | null | no | |
| createdAt | string (date-time) | no | |
| usage | object | null | no | This billing month's counts. Never content. |
| usage.cycleStart | string (date-time) | null | no | |
| usage.predictions | integer | no | |
| usage.predictionsLimit | integer | null | no | |
| usage.pictures | integer | no | |
| usage.picturesLimit | integer | null | no | |
| workspaces | array of object | no | |
| workspaces[].id | string (uuid) | no | |
| workspaces[].name | string | no | |
| workspaces[].plan | string | no | |
| workspaces[].pendingPlan | string | null | no | A downgrade waiting for the end of the paid month. |
| workspaces[].changesAt | string (date-time) | null | no | |
| workspaces[].endsAt | string (date-time) | null | no | Set when you stopped paying for it. |
| workspaces[].archived | boolean | no | |
| workspaces[].primary | boolean | no | The customer's first workspace. |
| workspaces[].joinsAt | string (date-time) | null | no | For a customer that joined you from its own billing: when this workspace moves to your bill, at the end of the month its Owner already paid for. Until then it is not on your bill and its plan cannot be changed (partner.workspace_joining). |
| workspaces[].addOns | array of string | no | |
| workspaces[].usage | object | null | no | This billing month's counts. Never content. |
| workspaces[].usage.cycleStart | string (date-time) | null | no | |
| workspaces[].usage.predictions | integer | no | |
| workspaces[].usage.predictionsLimit | integer | null | no | |
| workspaces[].usage.pictures | integer | no | |
| workspaces[].usage.picturesLimit | integer | null | no | |
| ownerSignedInAt | string (date-time) | null | no | A resold customer only. When its Owner last signed in; null until they have. |
Model
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | no | |
| name | string | no | |
| description | string | no | |
| modality | string | no | (one of text, image) |
| status | string | no | Where the model is, as the app's Models screen says it. |
| published | boolean | no | |
| liveVersion | string (uuid) | null | no | |
| latestVersion | string (uuid) | null | no | |
| accuracy | number | null | no | The latest version's accuracy on held-out rows, 0 to 1. |
ModelDetail
A Model, with every training run.
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string (uuid) | no | |
| name | string | no | |
| description | string | no | |
| modality | string | no | (one of text, image) |
| status | string | no | |
| published | boolean | no | |
| liveVersion | string (uuid) | null | no | |
| latestVersion | string (uuid) | null | no | |
| accuracy | number | null | no | |
| versions | array of object | no | |
| versions[].id | string (uuid) | no | |
| versions[].status | string | no | |
| versions[].engine | string | null | no | |
| versions[].accuracy | number | null | no | |
| versions[].startedAt | string (date-time) | null | no | |
| versions[].live | boolean | no |
Columns
The column names, unique, up to 200.
Rows
Rows of values, each with one value per column, in the order of columns. Values are read as text.
Quality
| Field | Type | Required | Notes |
|---|---|---|---|
| version | string | null | no | Pass back with a fix. |
| usableRows | integer | null | no | |
| categoryCount | integer | null | no | |
| distribution | array of object | no | Rows per category. |
| duplicateCount | integer | no | |
| rareCategoryCount | integer | no | |
| verdict | string | null | no | Whether the data is ready to train, as the app's Check data step says. |
| reasons | array of object | no | |
| duplicates | array of object | no |
TrainingJob
| Field | Type | Required | Notes |
|---|---|---|---|
| jobId | string (uuid) | no | |
| status | string | no | queued, running, completed, failed or cancelled. |
| stage | string | null | no | What it is doing now, in words. |
| failure | string | null | no | |
| report | object | null | no | The test on held-out rows, once completed. |
| report.versionId | string (uuid) | no | |
| report.isLive | boolean | no | |
| report.accuracy | number | null | no | |
| report.baseline | number | null | no | Always guessing the commonest category. |
| report.testedOn | integer | null | no | |
| report.trainedOn | integer | null | no | |
| report.perCategory | array of object | no | |
| report.perCategory[].category | string | no | |
| report.perCategory[].accuracy | number | no | |
| report.perCategory[].correct | integer | no | |
| report.perCategory[].total | integer | no |
PredictRequest
Exactly one of input or inputs; the server enforces it.
| Field | Type | Required | Notes |
|---|---|---|---|
| input | any | no | One record. A string, an object of the fields the model reads, or for a picture model a link or {"imageBase64":"..."}. |
| inputs | array of any | no | Up to 100 records, each as input takes one (up to 20 pictures). (minItems: 1, maxItems: 100) |
Prediction
| Field | Type | Required | Notes |
|---|---|---|---|
| input | any | no | The record, echoed back. |
| label | string | null | no | |
| confidence | number | null | no | 0 to 1. |
| needsReview | boolean | no | Below the model's review cutoff; the answer went to the Review Queue. |
| labels | array of string | no | For a model whose answer is a list. |
| fields | object | no | For a model whose answer has several columns. |
| error | string | no | A picture that could not be used, as a code. |
| message | string | no |
PredictResponse
| Field | Type | Required | Notes |
|---|---|---|---|
| model | object | no | |
| model.id | string (uuid) | no | |
| model.name | string | no | |
| predictions | array of object | no | |
| predictions[].input | any | no | The record, echoed back. |
| predictions[].label | string | null | no | |
| predictions[].confidence | number | null | no | 0 to 1. |
| predictions[].needsReview | boolean | no | Below the model's review cutoff; the answer went to the Review Queue. |
| predictions[].labels | array of string | no | For a model whose answer is a list. |
| predictions[].fields | object | no | For a model whose answer has several columns. |
| predictions[].error | string | no | A picture that could not be used, as a code. |
| predictions[].message | string | no | |
| usage | object | no | |
| usage.predictions | integer | no | Records counted by this request. |
ClassifyResponse
| Field | Type | Required | Notes |
|---|---|---|---|
| label | string | null | no | |
| confidence | number | null | no | |
| needsReview | boolean | no | |
| labels | array of string | no | |
| fields | object | no | |
| modelId | string (uuid) | no | |
| modelName | string | no | |
| error | string | no | |
| message | string | no |
Fill
| Field | Type | Required | Notes |
|---|---|---|---|
| fillId | string (uuid) | no | |
| status | string | no | queued, running, completed, failed or cancelled. |
| filled | integer | null | no | |
| total | integer | null | no | |
| failure | string | null | no | |
| answers | array of object | no | Once completed, one per row, in the order sent. |
| answers[].category | string | null | no | |
| answers[].confidence | number | null | no | |
| file | string | no | Once completed, the path of the filled file. |
ReviewPage
| Field | Type | Required | Notes |
|---|---|---|---|
| open | boolean | null | no | Whether the customer's plan has the Review Queue. |
| cutoff | number | null | no | Answers below this confidence come here. |
| counts | object | no | |
| total | integer | no | |
| categories | array of string | no | |
| items | array of object | no | |
| items[].groupKey | string | no | Pass back to answer it. |
| items[].itemId | string | no | |
| items[].size | integer | no | How many times this same question was asked. |
| items[].confidence | number | null | no | |
| items[].predictedLabel | string | null | no | |
| items[].reviewedLabel | string | null | no | |
| items[].sources | array of string | no | The channels it came from. |
| items[].text | string | null | no | |
| items[].inputText | string | null | no | |
| items[].imageHash | string | null | no | |
| items[].firstAt | string (date-time) | no | |
| items[].alternatives | array of object | null | no | The model's next candidates. |
Generated from backend/openapi-partner.yaml by scripts/build-api-reference.py. Do not edit by hand.