Reference

Response contract

The complete catalog of JSON shapes the API returns today. Every response is JSON (UTF-8). Success bodies are flat objects; error bodies follow a single envelope. We do not document fields or error codes that are not actually emitted.

A note on confidence_score

confidence_score is a tiered match-quality indicator in [0, 1], not a calibrated probability. It reflects how strong the name / registration match was, not the statistical likelihood that the business exists. Use the tiers (0.99 registration-number match, ≈0.96 exact name match, 0.5–0.94 fuzzy match) as a gating signal, not a probabilistic input to a downstream model.

1. Successful match — 200 OK

Returned by POST /v1/verify when an entity is found in the live registry ingestion.

200 OK · verified
{
  "verified": true,
  "status": "active",
  "business_name": "<canonical name from registry>",
  "entity_type": "<from registry, may be null>",
  "state": "TX",
  "registration_number": "<from registry, may be null>",
  "formation_date": "<ISO date, may be null>",
  "confidence_score": 0.97,
  "source": "Texas Comptroller — Active Franchise Tax Permit Holders",
  "source": "Texas Comptroller — Active Franchise Tax Permit Holders",
  "trustregistry_id": "be_...",
  "data_source": "live_registry_ingestion"
}

2. Not found — 200 OK

A /verify call with no matching entity returns 200 OK (not 404) with verified: false. This lets clients branch on status instead of HTTP errors.

200 OK · not_found
{
  "verified": false,
  "status": "not_found",
  "business_name": "Nonexistent Corp",
  "state": "TX",
  "registration_number": null,
  "entity_type": null,
  "formation_date": null,
  "confidence_score": 0,
  "source": "Texas Comptroller — Active Franchise Tax Permit Holders",
  "data_source": "live_registry_ingestion",
  "message": "No matching entity found in the live Texas Comptroller registry ingestion."
}

3. Unsupported state — 200 OK

Requests for states that are not yet live return a structured response with status: "unsupported_state" and are not billed.

200 OK · unsupported_state
{
  "verified": false,
  "status": "unsupported_state",
  "state": "DE",
  "message": "Coverage for DE is not live yet. Texas (TX) is currently supported. Delaware, Florida, and California are coming next."
}

Error envelope

Every 4xx and 5xx response uses this single shape. Branch on HTTP status first, then on error.code.

error envelope
{
  "error": {
    "code": "<machine-readable code>",
    "message": "<human-readable explanation>"
  }
}

4. Unauthorized — 401

Missing Authorization header, malformed token, key not found, or key revoked.

401 · unauthorized
{
  "error": {
    "code": "unauthorized",
    "message": "Missing Authorization header. Use: Authorization: Bearer tr_live_..."
  }
}

5. Invalid request — 400

Malformed JSON, missing required field, or a value that fails validation (e.g. state is not 2 letters, business_name is empty or over 255 chars). The message identifies the offending field.

400 · invalid_request
{
  "error": {
    "code": "invalid_request",
    "message": "business_name: String must contain at least 1 character(s)"
  }
}

6. Quota exceeded — 429

Returned once your account has consumed its monthly included verifications. The quota is a hard stop — overage billing is not enabled. Upgrade your plan or wait until the next billing period to resume calls.

429 · quota_exceeded
{
  "error": {
    "code": "quota_exceeded",
    "message": "Monthly verification quota exceeded (250/250). Upgrade your plan or wait until 2026-06-01T00:00:00.000Z."
  }
}

7. Internal error — 500

An unhandled server-side failure. Safe to retry idempotent calls with exponential backoff (e.g. 1s, 2s, 4s, 8s).

500 · internal_error
{
  "error": {
    "code": "internal_error",
    "message": "Auth lookup failed: <underlying message>"
  }
}
Honesty note. The seven shapes above are the entire surface area today. If you see a response that does not match one of these, that's a bug — please tell us.