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-Idheader.
Quickstart
- Get your keys. Request access and we set up your account, your agencies and a pair of keys:
al3_test_for development andal3_live_for production. - Send a file. Post the AL3 file to
/v1/parsewith your key and the agency it belongs to. - Use the JSON. Each policy transaction in the file comes back as one object in
transactions.
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{
"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.
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/parseandPOST /v1/validateusage: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.
Endpoints
Every endpoint lives under https://al3.nativebase.ai/v1. The machine-readable contract is the OpenAPI spec.
Convert an AL3 file into normalized JSON.
Check a file’s structure and get warnings, without the JSON output.
The JSON Schema of the output.
Usage for a date range, broken down by agency.
The OpenAPI 3.1 spec for every endpoint.
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.
| Name | In | Description |
|---|---|---|
Authorizationrequired | header | Bearer key with the parse scope. |
X-Agency-Idrequired | header | The agency this file belongs to. |
Content-Typerequired | header | text/plain for the raw file, or multipart/form-data with the file in a file field. |
Content-Encoding | header | gzip to send a compressed body. Recommended for large initial loads. |
include | query | raw adds raw.groups[]: every group's code, byte offset, length and raw text. |
lob | query | Line-of-business hint, for files whose header leaves it ambiguous. |
{
"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:
{
"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.
{
"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.
| Name | In | Description |
|---|---|---|
fromrequired | query | Start date, YYYY-MM-DD (inclusive). |
torequired | query | End date, YYYY-MM-DD (inclusive). |
{
"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.
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.
{
"error": {
"code": "agency_not_allowed",
"message": "This agency does not belong to your account.",
"requestId": "b6f1c7e2-4c1d-4a8e-9a51-3f0c2d9e7a10"
}
}| Status | Meaning |
|---|---|
400 | The request is malformed: a missing header, a bad query parameter or an empty body. |
401 | The key is missing, unknown, revoked or expired. |
403 | The key lacks the scope, or the agency does not belong to your account. |
413 | The body is over 4.5 MB. Send it gzip-compressed. |
415 | The content type is not text/plain or multipart/form-data. |
429 | A rate limit was reached. Retry after the number of seconds in Retry-After. |
5xx | Something 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:
RateLimit-Limit: 60
RateLimit-Remaining: 57
RateLimit-Reset: 41Over 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.