Skip to content

Batch scoring

API reference · POST /v1/score

Score records in real-time using a trained model.

Once a model is trained, this is the call an integration or an agent makes in normal operation. It scores up to 1000 records per call and returns one row per input record, in order.

Request

endpoint
POST https://api.ax1om.ai/v1/score

Authorize with your API key. Keys are minted in the app and the format is documented on authentication.

Parameters

NameInTypeRequired
authorizationheaderstringNo

Body

ScoreRequest, required. JSON.

FieldTypeRequiredDescription
explainbooleanNoOpt in to per-record drivers and top_reason_1..3 strings. Adds a few ms; off by default.
model_idstringYesThe trained model to score against (mdl_...).
recordsarray<object>YesUp to 1000 records. Each is a flat object of your CRM field values. Extra fields are allowed; unknown fields are ignored by the model.

Response

StatusBodyWhen
200V1ScoreResponseRecords scored.
400V1ErrorBad request (code: bad_request), or more than 1000 records in one batch (code: record_limit_exceeded).
401V1ErrorMissing or invalid API key (code: invalid_api_key).
402V1ErrorThe org's trial ended and it has no active subscription, so it is in read-only mode (code: expired_read_only). Read access to existing scores, models, and factors is unaffected; API scoring resumes on upgrade. Unlike a 429 quota, this does not clear at the next billing period, so do not retry on a timer.
403V1ErrorLive API is turned off for the score that owns this model (code: api_disabled). Turn Live API on in that score's row under Activate. Retrying will not clear it.
404V1ErrorModel not found (code: model_not_found).
409V1ErrorYour org's deploy policy is set to block, and this model has not passed its validation gate (code: deploy_blocked). The message names the gate and the override path. Retrying will not clear it: either the model clears its gate as its predictions mature, or an admin lifts the refusal.
422V1ErrorMalformed request body (code: bad_request).
429V1ErrorRate limited (code: rate_limited), or monthly scored-record quota exhausted past the backstop, including plans without API scoring (code: quota_exceeded).
500V1ErrorInternal error (code: internal_error).

V1ScoreResponse

Batch scoring response.

FieldTypeAlways presentDescription
cache_hitsintegerNoHow many records matched your existing scored data.
model_idstringYes
records_scoredintegerNoCount of records scored in this call.
scoresarray<V1ScoreRow>Yes
testbooleanNoPresent and true only for test keys (ax1m_sk_test_...). Never billed.
usageV1UsageYes
validationV1ValidationYes

V1ScoreRow

One scored record. Order matches the request `records` array.

FieldTypeAlways presentDescription
conversion_likelihoodnumber (float)YesModel conversion likelihood, 0-1 (4 dp).
crm_idstringNoEchoed back when supplied on the input record.
deltaintegerNoscore minus previous_score, when a previous score exists.
driversarray<object>NoPer-record feature contributions. Present only when explain=true.
enrichedbooleanYestrue only when the record matched your existing scored data. false = thin score from the fields you sent (cold record).
previous_scoreintegerNoPrior score for this crm_id, when one exists.
scoreintegerYesFit score, 0-100.
top_reason_1string | nullNoTop driver string. Present only when explain=true.
top_reason_2string | nullNoSecond driver. Present only when explain=true.
top_reason_3string | nullNoThird driver. Present only when explain=true.
warningsarray<string>NoPresent only when the record trips the recency age guard. Metadata only; the score is not changed.

V1Usage

Monthly metered usage for the API key's org. The live monthly cap is a soft cap: paid live keys keep scoring past `limit` in a grace band until a hard abuse backstop; test keys and plans without API scoring keep a hard cap.

FieldTypeAlways presentDescription
backstopinteger | nullYesHard stop for this billing month. Scoring pauses (429, code quota_exceeded) once usage reaches it. null for test keys.
currentintegerYesRecords scored so far this billing month, including this call.
in_gracebooleanYestrue once the org is scoring past its included monthly limit, in the grace band.
limitintegerYesMonthly included scored-record limit for the plan (test keys meter into a separate free bucket).
remainingintegerYesRecords left this month. Goes negative in the grace band once usage passes the included limit.

V1Validation

Whether this model has earned the act, computed server-side from the same validation readout the check-in renders. Present on every batch-scoring response. Surfacing only by default: your org's deploy policy decides whether a not-passed model is refused (409 deploy_blocked) or scored with this object attached.

FieldTypeAlways presentDescription
failing_gate"predictions_recorded" | "cohort_reconciles" | "matured_cohort" | "outcomes_observed" | "rate_rises_with_band" | "top_band_lift" | "null" | nullYesThe gate that was not cleared. Null when state is passed, unresolved or not_applicable.
state"passed" | "failed" | "too_early_to_grade" | "unresolved" | "not_applicable"Yespassed: every gate cleared. failed: a gate was reached and did not clear. too_early_to_grade: a gate could not be reached yet - a young model, not a bad one. unresolved: the state could not be read on our side; nothing is claimed about the model. not_applicable: this model family is not graded by the forward-cohort gates.
summarystringYesOne human sentence naming the state and the gate.

Example

The same call in three clients. Pick one and the choice follows you across every panel on the documentation that offers it.

POST /v1/score
curl -X POST "https://api.ax1om.ai/v1/score" \
-H "Authorization: Bearer ax1m_sk_your_key" \
-H "Content-Type: application/json" \
-d '{
"model_id": "mdl_abc123",
"records": [
{
"title": "VP Sales",
"industry": "SaaS",
"employees": 250
}
]
}'
200 OK
{
"model_id": "mdl_abc123",
"scores": [
{ "score": 82, "conversion_likelihood": 0.823, "enriched": false }
],
"records_scored": 1,
"cache_hits": 0,
"usage": { "current": 151, "limit": 10000, "remaining": 9849, "in_grace": false, "backstop": 20000 }
}

Errors

Every failure returns the /v1 envelope. Branch onerror.code, never on the HTTP status or the message text. The codes below are the ones the contract declares for this operation; the full table with prose for each is on theindex.

StatusCodes
400record_limit_exceeded · bad_request
401invalid_api_key
402expired_read_only
403api_disabled
404model_not_found
409deploy_blocked
422bad_request
429quota_exceeded · rate_limited
500internal_error

Notes

  • Records that match your existing scored data come back enriched with a delta; unmatched records are scored from the fields you send.
  • Batch up to 1000 records per call to stay well under the rate limit.
  • The score is a 0-100 ranking of conversion likelihood. It is not a percentage chance of conversion, and the per-record factors do not sum to it.
Need help?Contact supportLatest changes?See the changelog
Something wrong?Check system statusComing soon