Documentation

AL3 to JSON API

The AL3 to JSON API turns ACORD AL3 files, the fixed-width format carriers deliver through IVANS, into normalized JSON. Send a file, get back every policy transaction in one consistent schema.

  • Base URL: https://al3.nativebase.ai/v1
  • All requests over HTTPS. All responses are JSON.
  • Every response carries an X-Request-Id header.

Quickstart

  1. Get your keys. Request access and we set up your account, your agencies and a pair of keys: al3_test_ for development and al3_live_ for production.
  2. Send a file. Post the AL3 file to /v1/parse with your key and the agency it belongs to.
  3. Use the JSON. Each policy transaction in the file comes back as one object in transactions.
Request
curl https://al3.nativebase.ai/v1/parse \
  -H "Authorization: Bearer $AL3_API_KEY" \
  -H "X-Agency-Id: $AGENCY_ID" \
  -H "Content-Type: text/plain" \
  --data-binary @daily-download.al3
200 OK
{
  "transactions": [ { "transaction": { "type": "RWL", ... }, ... } ],
  "meta": {
    "parserVersion": "1.4.0",
    "warnings": [],
    "fieldCoverage": 0.97
  }
}

Authentication

Authenticate every request (except /v1/health, /v1/schema and /v1/openapi.json) with an API key in the Authorization header.

HTTP
Authorization: Bearer al3_live_3kq9…

Live and test keys

Live keys start with al3_live_. Test keys start with al3_test_, behave exactly like live keys, and are never billed. The full key is shown once, when it is created. We store only a salted hash and a short visible prefix, so keep the key in your secret store.

Scopes

Each key carries one or more scopes. A request outside the key's scopes returns 403.

  • parse: POST /v1/parse and POST /v1/validate
  • usage:read: GET /v1/usage

Rotation, expiry and revocation

Keys can carry an expiry date and can be revoked at any time. When you rotate a key, the old and new keys both work for 24 hours, so you can roll the new key out with zero downtime.

Agencies

Your account holds the agencies you serve. Every parse and validate request names one in the X-Agency-Id header. We check that the agency belongs to the key's account before the file is read, and record usage against it, so /v1/usage gives you per-agency numbers for your own billing.

A request without X-Agency-Id returns 400. An agency that is not in your account returns 403.

Reference

Endpoints

Every endpoint lives under https://al3.nativebase.ai/v1. The machine-readable contract is the OpenAPI spec.

POST
/v1/parseparse

Convert an AL3 file into normalized JSON.

POST
/v1/validateparse

Check a file’s structure and get warnings, without the JSON output.

GET
/v1/schema

The JSON Schema of the output.

GET
/v1/usageusage:read

Usage for a date range, broken down by agency.

GET
/v1/openapi.json

The OpenAPI 3.1 spec for every endpoint.

GET
/v1/health

Liveness and database connectivity.

POST/v1/parse

Converts an AL3 file into normalized JSON. Each policy transaction in the file becomes one object in transactions; meta reports versions, warnings and how much of the file was mapped. Files are parsed in memory and not stored.

NameInDescription
AuthorizationrequiredheaderBearer key with the parse scope.
X-Agency-IdrequiredheaderThe agency this file belongs to.
Content-Typerequiredheadertext/plain for the raw file, or multipart/form-data with the file in a file field.
Content-Encodingheadergzip to send a compressed body. Recommended for large initial loads.
includequeryraw adds raw.groups[]: every group's code, byte offset, length and raw text.
lobqueryLine-of-business hint, for files whose header leaves it ambiguous.
Response200 OK
{
  "transactions": [
    {
      "transaction": {
        "type": "PCH",
        "effectiveDate": "2026-11-01",
        "processingDate": "2026-10-28",
        "lineOfBusiness": "AUTOB",
        "carrier": { "name": "Example Mutual", "naic": "12345" },
        "agencyCodes": ["A0010001"]
      },
      "insured": {
        "names": ["Ridgeline Freight LLC"],
        "mailingAddress": { "line1": "400 Depot St", "city": "Dayton", "state": "OH", "zip": "45402" }
      },
      "policy": {
        "number": "CA2049117",
        "priorNumber": "CA1938841",
        "effectiveDate": "2026-11-01",
        "expirationDate": "2027-11-01",
        "termPremium": 18420.00,
        "billingType": "AGENCY"
      },
      "vehicles": [
        { "vin": "1FUJHHDR8KLKK1234", "year": 2019, "make": "FRHT", "model": "CASCADIA" }
      ],
      "drivers": [ { "name": "J. Alvarez", "licenseState": "OH" } ],
      "coverages": [
        { "code": "BI", "limit": 1000000, "premium": 9210.00, "level": "policy" }
      ],
      "additionalInterests": [],
      "forms": [ { "number": "CA0001", "edition": "1013" } ]
    }
  ],
  "meta": {
    "parserVersion": "1.4.0",
    "layoutVersions": { "5BPI": "3", "5BIS": "2" },
    "unmappedGroups": [],
    "warnings": [],
    "fieldCoverage": 0.97
  }
}

Warnings. Nothing in the file is dropped or guessed. Anything the parser cannot map, such as an unknown group or code or a date that does not parse, is returned raw and described in meta.warnings with its location:

Warning
{
  "code": "unknown_group",
  "groupCode": "9XAB",
  "offset": 1824,
  "message": "Group 9XAB has no layout. Returned raw."
}

POST/v1/validate

Takes the same input as /v1/parse and runs the structural checks only: messages, transactions, group lengths and codes. Use it to check files on arrival before parsing. Validation calls do not count toward your monthly transactions.

Response200 OK
{
  "messages": 1,
  "transactions": 3,
  "groups": 42,
  "warnings": [
    { "code": "length_mismatch", "groupCode": "6CVA", "offset": 2210,
      "message": "Declared length 064, found 061." }
  ]
}

GET/v1/schema

Returns the JSON Schema of the parse output. Generate types from it or validate responses in your own pipeline. The schema covers transaction, insured, policy, vehicles[], drivers[], coverages[], additionalInterests[], forms[], raw and meta.

GET/v1/usage

Usage for your account over a date range, broken down by agency. Requires the usage:read scope.

NameInDescription
fromrequiredqueryStart date, YYYY-MM-DD (inclusive).
torequiredqueryEnd date, YYYY-MM-DD (inclusive).
Response200 OK
{
  "from": "2026-10-01",
  "to": "2026-10-31",
  "totals": { "requests": 1284, "transactions": 3912, "bytesIn": 18734221 },
  "agencies": [
    { "agencyId": "7d1e…c42a", "name": "Harbor Insurance Group",
      "requests": 611, "transactions": 2040 },
    { "agencyId": "a93b…0f17", "name": "Summit Risk Partners",
      "requests": 673, "transactions": 1872 }
  ]
}

GET/v1/openapi.json

The OpenAPI 3.1 spec for every endpoint, generated from the same schemas that validate requests. Import it into Postman, Insomnia or your client generator.

GET/v1/health

Liveness and database connectivity. No authentication. Use it for uptime monitoring.

Conventions

Errors

Every error uses the same body, whatever the endpoint. code is stable and safe to branch on; message is for people. Error messages never contain file content.

403 Forbidden
{
  "error": {
    "code": "agency_not_allowed",
    "message": "This agency does not belong to your account.",
    "requestId": "b6f1c7e2-4c1d-4a8e-9a51-3f0c2d9e7a10"
  }
}
StatusMeaning
400The request is malformed: a missing header, a bad query parameter or an empty body.
401The key is missing, unknown, revoked or expired.
403The key lacks the scope, or the agency does not belong to your account.
413The body is over 4.5 MB. Send it gzip-compressed.
415The content type is not text/plain or multipart/form-data.
429A rate limit was reached. Retry after the number of seconds in Retry-After.
5xxSomething failed on our side. Safe to retry; quote the requestId if it persists.

Rate limits

Each key can make 60 requests a minute, and each account 300. Higher-volume accounts get higher limits. Every response reports where you stand:

HTTP
RateLimit-Limit: 60
RateLimit-Remaining: 57
RateLimit-Reset: 41

Over a limit, the API returns 429 with a Retry-After header in seconds. Wait that long, then retry.

Files and size

Send each AL3 file as you received it. Line endings (CRLF or LF) and wrapped lines are normalized for you. A request body can be up to 4.5 MB. Daily downloads are typically a few kilobytes; for large initial loads, gzip the body and set Content-Encoding: gzip.

Request IDs

Every response carries an X-Request-Id header, and every error body repeats it. Send your own ID in X-Request-Id (8 to 128 characters of letters, digits, ., _ or -) and we use it, so a request can be traced end to end across your systems and ours.

Data handling

Files and parsed output are processed in memory and not stored. Logs and usage records hold IDs, sizes, counts and timings, never file content or policyholder data. Encrypted file retention for debugging is available per account, with automatic deletion after 30 days.

Stop parsing AL3. Start using it.

Tell us about your agencies and carriers, and start building with free test keys.

Get API access →Explore the docs