ax1om is in private beta · real-data testers lock in the founding-member rate for life. Join the beta Already have a code?

API reference / v1

Score a record with one POST.

The ax1om Scoring API takes your CRM field values and returns a fit score (0-100) and a conversion likelihood. Two endpoints, Bearer key auth, and a stable versioned contract. Mint a key in the app and make your first call in minutes.

01 / Quickstart

From key to first score.

  1. Mint a key. In the app, open Settings, API keys, then Create key. The secret (ax1m_sk_...) is shown once. Save it. API scoring is available on Pro and above.
  2. Grab a model_id. Any trained model in your workspace. It looks like mdl_abc123.
  3. POST a record. Send the fields you have. You do not need every field the model trained on.
curl 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 }
    ]
  }'

You get back a fit score, a conversion likelihood, and your month-to-date usage:

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": 50000, "remaining": 49849, "in_grace": false, "backstop": 100000 }
}
02 / Authentication

Bearer key on every request.

Every call sends your key as a Bearer token. The webhook endpoint also accepts an X-API-Key header for CRM tools that map headers more easily. Keys start with ax1m_sk_. Treat the secret like a password: it is shown once at creation and stored only as a hash.

header
Authorization: Bearer ax1m_sk_your_key

Test keys

A key that starts with ax1m_sk_test_ scores against the real model but meters into a separate free bucket (1000 records/mo). It never touches your live quota and never bills. Use it to wire up and verify an integration before you flip to a live key. Test-key responses carry "test": true.

curl test key
curl -X POST https://api.ax1om.ai/v1/score \
  -H "Authorization: Bearer ax1m_sk_test_your_test_key" \
  -H "Content-Type: application/json" \
  -d '{ "model_id": "mdl_abc123", "records": [ { "title": "VP Sales" } ] }'
03 / Batch scoring
POST/v1/score

Score up to 1000 records in one call. Returns one row per input record, in order. Records that match your existing scored data come back enriched with a delta; unmatched records are scored from the fields you send (see Cold records).

Request body

FieldTypeRequiredDescription
explain boolean No Opt in to per-record drivers and top_reason_1..3 strings. Adds a few ms; off by default.
model_id string Yes The trained model to score against (mdl_...).
records array<object> Yes Up 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

FieldTypeDescription
cache_hits integer How many records matched your existing scored data.
model_id string
records_scored integer Count of records scored in this call.
scores array<V1ScoreRow>
test boolean Present and true only for test keys (ax1m_sk_test_...). Never billed.
usage V1Usage

Score row (each item in scores)

FieldTypeDescription
conversion_likelihood number (float) Model conversion likelihood, 0-1 (4 dp).
crm_id string Echoed back when supplied on the input record.
delta integer score minus previous_score, when a previous score exists.
drivers array<object> Per-record feature contributions. Present only when explain=true.
enriched boolean true only when the record matched your existing scored data. false = thin score from the fields you sent (cold record).
previous_score integer Prior score for this crm_id, when one exists.
score integer Fit score, 0-100.
top_reason_1 string | null Top driver string. Present only when explain=true.
top_reason_2 string | null Second driver. Present only when explain=true.
top_reason_3 string | null Third driver. Present only when explain=true.
warnings array<string> Present only when the record trips the recency age guard. Metadata only; the score is not changed.
04 / Webhook scoring
POST/v1/webhooks/score

A single-record variant with a flat response, shaped for Marketo, Zapier, and other tools that map fields one to one. The record is the raw JSON body; model_id is a query parameter.

Parameters

NameInTypeRequired
model_id query string Yes
authorization header string No
X-API-Key header object No

Send the field values as a flat JSON body:

curl POST /v1/webhooks/score
curl -X POST "https://api.ax1om.ai/v1/webhooks/score?model_id=mdl_abc123" \
  -H "X-API-Key: ax1m_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "Title": "VP Sales", "Industry": "SaaS", "LeadSource": "Webinar" }'

Response

FieldTypeDescription
age_sentinel string | null Recency age-guard note. Always present (null when in-range) for sentinel-trained models only.
conversion_likelihood number (float)
delta integer score minus previous_score, when a previous score exists.
percentile integer Approximate percentile for the single record.
previous_score integer Present when a prior score exists for record_id.
record_id string Echoed crm_id when supplied.
score integer
test boolean Present and true only for test keys.
tier "hot" | "warm" | "cold"
top_reason_1 string | null
top_reason_2 string | null
top_reason_3 string | null
200 OK
{
  "score": 87,
  "tier": "hot",
  "percentile": 87,
  "conversion_likelihood": 0.8732,
  "top_reason_1": "VP title (2.3x lift)",
  "top_reason_2": "SaaS industry",
  "top_reason_3": "Webinar source"
}
05 / Cold records

A new lead still gets a real score.

When you score a record that is not yet in your existing scored data, ax1om scores it from exactly the fields you send. Nothing is invented and no account matching happens on the request path. The response tells you plainly with the enriched flag:

enrichedMeaning
trueThe record matched your existing scored data. It carries a previous_score and delta where available.
falseA cold record. Scored from the fields in your request only. Send richer input to get a richer score.

The score is always real, never a placeholder. enriched: false is a signal about input completeness, not score quality.

06 / Errors

One envelope, stable codes.

Every /v1 error returns the same shape. Branch on error.code, never on the HTTP status or the message text. The codes are frozen: new ones may be added, existing ones never change.

error envelope
{
  "error": {
    "code": "invalid_api_key",
    "message": "API key required. Send Authorization: Bearer ax1m_sk_...",
    "docs_url": "https://ax1om.ai/docs/api"
  }
}
CodeHTTPWhen it fires
invalid_api_key 401 Missing key, malformed key, or a revoked/unknown key.
bad_request 400 / 422 Malformed body, no records, or a record the model could not featurize.
record_limit_exceeded 400 More than 1000 records in one batch call.
model_not_found 404 The model_id does not exist for your org.
quota_exceeded 429 Scoring is paused for the month: usage passed the included limit and the grace band, and hit the hard backstop. Upgrade or contact support to resume.
rate_limited 429 Too many requests per second for the key. Slow down and retry.
internal_error 500 An unexpected server error. Safe to retry with backoff.
07 / Rate limits & usage

Two limits, both visible.

A per-key rate limit (default 10 requests/second) guards against bursts and returns rate_limited when tripped. A separate monthly metered quota counts the records you score. The monthly limit is a soft cap: live keys on a paid plan keep scoring past it in a grace band (in_grace: true, remaining goes negative) and only hard-stop with quota_exceeded at the backstop. Test keys meter into their own free bucket with a hard cap.

Every batch response includes a usage object so you always know where you stand this month:

FieldTypeDescription
backstop integer | null Hard stop for this billing month. Scoring pauses (429, code quota_exceeded) once usage reaches it. null for test keys.
current integer Records scored so far this billing month, including this call.
in_grace boolean true once the org is scoring past its included monthly limit, in the grace band.
limit integer Monthly included scored-record limit for the plan (test keys meter into a separate free bucket).
remaining integer Records left this month. Goes negative in the grace band once usage passes the included limit.

Batch up to 1000 records per call to stay well under the rate limit.

08 / Versioning

Stable by prefix.

The API is versioned by URL prefix (/v1). Additive changes, new response fields, new optional request fields, and new endpoints ship within /v1 without a version bump. Breaking changes, renaming or removing a field, changing a type, or changing an error code, get a new prefix, never a silent change to /v1.

Deprecated root aliases

The unversioned POST /score and POST /webhooks/score still work but are deprecated. They return the pre-v1 contract (the 0-1 float is named probability) and carry Deprecation: true plus a Sunset response header (RFC 8594). Deprecated surfaces run for a minimum of 90 days. Sunset date: 2026-10-19. New integrations should use /v1, where the same value ships as conversion_likelihood and errors use the stable envelope.

Use thisNot this (deprecated)Sunset
POST /v1/scorePOST /score2026-10-19
POST /v1/webhooks/scorePOST /webhooks/score2026-10-19
09 / Ship it

Mint a key and score your first record.

Wire it up with a test key, verify the shape, then flip to live. No SDK required, just HTTP.