Reference for third-party developers integrating with the ASCI API, a customs-broker document integration service. This page documents the client-facing surface only: how to submit customs documents, query their status, and receive results via webhooks.
Getting started
Core concepts every integration needs: base URL, authentication, request conventions, the error contract, and the status lifecycle.
Overview
The ASCI API lets an external system exchange customs-broker documents with the ASCI back-office system. It is organized into per-document-type modules: ISF (Importer Security Filing), QP (In-Bond), BL (Import Billing), ACEQE (ACE Quick Entry), and LG (Log Book, read-only).
There are two directions of traffic, and you can use either or both:
-
Inbound
You push documents in. Your system POSTs a JSON
document to
/api/{Module}/Submit. The API validates it, accepts it, and hands it to the customs-broker back-office system for processing. You poll status (or subscribe to a webhook) to learn the outcome and the assigned reference number. -
Outbound
The API delivers processed results back to you. When
the back-office system produces or finalizes a document, the API makes
it available to you in two ways: a webhook notification pushed
to a URL you register, and/or a
GETyou can poll. There is no separate "outbound submit" endpoint you call - results flow to you.
POST /Submit = you send a
document in. GET + webhooks = you receive
documents and status updates back out.
Base URL & versioning
All requests are made to the ASCI production API base URL:
https://asci-api.asciofmiami.com
All client endpoints live under the /api path prefix
(for example https://asci-api.asciofmiami.com/api/Isf/Submit).
Endpoint paths in this document are written from /api/...
onward; prepend the base URL above.
The API is versioned by deployment rather than by a URL version segment. Existing routes, verbs, request shapes, and the error contract are kept backward-compatible; new fields and endpoints may be added over time. Treat unknown JSON fields in responses as additive and ignore the ones you do not consume.
Authentication
Every request must include an ApiKey request header carrying
the API key issued to your integration:
ApiKey: YOUR_API_KEYKeys are issued per integration. The server derives your account (tenant) from the key itself - you never send a tenant identifier in the URL, query string, or body. Every list and lookup is automatically scoped to your own data; you cannot see or address another integration's records.
Authentication outcomes:
- A request with no key, or an unknown / revoked / expired key, returns
401 unauthenticated. - A valid key that is not authorized for the operation returns
403 forbidden. Your key must be authorized for the operation you are calling (submitting documents, reading status, and managing webhooks are separate permissions). If you get a403on an operation you expect to use, ask your provider to authorize the key for it.
Request conventions
JSON
Requests and responses are JSON. Send
Content-Type: application/json on every request that has a
body.
The Submit envelope
Every POST /api/{Module}/Submit body wraps the document in a
single document object:
{
"document": {
"reference_no": "NEW",
"...": "module-specific fields"
}
}Reference numbers and "NEW"
Each document carries a reference_no. Set it to the string
"NEW" (case-insensitive; an empty value is treated the same)
to have the back-office system allocate the next consecutive reference
number for you. The allocated number is reported back through the status
and detail endpoints (field bbx_reference_no). You may also
pass an explicit reference number; it is used verbatim.
metadata (optional key/value bag)
Every inbound document (ISF / QP / BL / ACEQE) accepts an optional
metadata object at the top level of the document
object, next to reference_no. It is a client-supplied
JSON object of string→string key/value pairs: up to
50 entries, keys up to 40 characters,
values up to 500 characters each; it is never required.
The API stores it verbatim and echoes it back
to you on the GET .../{submissionId}/Status response and on the
document.status_changed webhook. It is never used to look up
or deduplicate an entry — use submission_id for that.
{
"document": {
"reference_no": "NEW",
"metadata": { "order_id": "A123", "warehouse": "MIA" },
"...": "module-specific fields"
}
}Idempotency-Key (required on every Submit)
Every POST /Submit must include an
Idempotency-Key header, 8 to 128 characters, unique per
logical submission:
Idempotency-Key: 7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22Replay semantics:
- Same key + same payload returns the
original result (HTTP
200) with"duplicate": trueand the originalsubmission_id- no second document is created. - Same key + a different payload is a conflict and
returns
409 duplicate_idempotency_key; theextra.original_submission_idfield points at the prior submission.
This makes it safe to retry a Submit after a network timeout: reuse the same key and you will never double-insert.
Trace id
Every response (success or error) carries an X-Trace-Id
response header, and error bodies repeat it as trace_id.
Quote that value when reporting an issue so support can correlate it with
server logs.
Error responses
Every 4xx / 5xx response uses one uniform JSON
shape:
{
"status": 409,
"code": "duplicate_idempotency_key",
"message": "Idempotency-Key has already been used with a different payload.",
"hint": "Submit with a fresh Idempotency-Key, or replay with the original payload.",
"endpoint": "POST /api/Isf/Submit",
"trace_id": "0HMXXXXXXXXX...",
"timestamp": "2026-05-08T16:24:27.3078184Z",
"field_errors": null,
"extra": { "original_submission_id": "a9051bfa23dc4df8b38f3bc11c3a1411" }
}| Field | Meaning |
|---|---|
status | HTTP status code, repeated in the body. |
code | Stable machine-readable error code (see table below). Branch on this, not on message. |
message | Human-readable summary. |
hint | Optional suggested fix. May be null. |
endpoint | The method + route that produced the error. |
trace_id | Correlation id; matches the X-Trace-Id header. |
timestamp | UTC time of the error. |
field_errors | Per-field validation messages on 400/422; otherwise null. |
extra | Optional context object (varies by error code). May be null. |
Common error codes
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_payload | Request body is null or not a JSON object. |
| 400 | missing_idempotency_key | Idempotency-Key header missing on a Submit. |
| 400 | invalid_argument / bad_request / invalid_json | Generic malformed-request variants. |
| 400 | invalid_direction | The direction filter was not inbound or outbound (LG accepts only outbound). |
| 401 | unauthenticated | Missing or unknown API key. |
| 403 | forbidden | Your key is not authorized for this operation, or the source is not permitted. |
| 404 | not_found | The submission / document does not exist for your account. |
| 409 | duplicate_idempotency_key | Same Idempotency-Key reused with a different payload. extra.original_submission_id carries the prior id. (Same key + same payload returns 200 with duplicate=true instead.) |
| 409 | invalid_state | The operation is not allowed in the current state. |
| 413 | - | Payload exceeds the size cap (256 KB on Submit). |
| 422 | invalid_payload | Body is well-formed JSON but semantically invalid; field_errors lists the issues. |
| 429 | tenant_quota_exceeded | Submission volume limit reached. Also returned when the per-key rate limit (60 req/min on Submit) is exceeded. |
| 500 | internal_error | Unexpected server error; quote trace_id when reporting. |
field_errors
On validation failures (400 / 422),
field_errors is an object mapping each offending field name
to a reason string:
{
"status": 422,
"code": "invalid_payload",
"message": "One or more fields are invalid.",
"field_errors": {
"document.header.scac_code": "scac_code must be exactly 4 uppercase letters.",
"document.header.ior_qualifier": "ior_qualifier must be one of EI, SS, CN."
}
}Status lifecycle
After a successful Submit, a document moves through these states as the back-office system picks it up and processes it:
| Status | Meaning |
|---|---|
queued | Accepted by the API and queued for the back-office system. (Reported as submitted on older records.) |
processing | The back-office system has taken the document and is creating the record. |
processed | Done. The reference number is populated (bbx_reference_no). |
rejected | The back-office system could not create the record; an error message is attached. |
Processing model
Accepted documents are queued in the API and inserted into
ASCI one at a time, in submission order (FIFO),
serialized - never in parallel. Each entry runs through the
lifecycle independently:
queued → processing →
processed | rejected. Its result is recorded in
the API and a document.status_changed webhook is emitted
per entry.
Webhook delivery is asynchronous with retries and does not hold up the queue: a slow or unavailable webhook endpoint never stalls legacy insertion of the next entry. Use polling (below) and/or the webhook to learn each entry's outcome.
Poll the thin status endpoint to track progress. It returns
{ submission_id, status, direction, metadata, entry_no,
approval_status, updated_at } (metadata echoes back
the object you supplied on Submit, if any). entry_no and
approval_status carry the back-office-reported entry number and
disposition once the entry is processed, and are returned on the Status
response for every module (ISF, QP, BL, ACEQE); they are
null until the back-office system reports them:
GET /api/{Module}/{submissionId}/Status/{submissionId}/Status. ACEQE uses the
order /Status/{submissionId} (/api/AceQe/Status/{id}).
The exact form for each
module is shown in its section below.
Rather than polling, you can register a webhook (see Webhooks) to be notified as documents are received and as their status changes.
Document modules
Per-document-type submission endpoints - ISF, QP, BL, ACEQE (read/write) and LG (read-only).
Per-module endpoint reference
Each of ISF, QP, BL, and ACEQE exposes the same four client
endpoints. Replace {Module} with the module route segment:
Isf, Qp, Bl, or
AceQe.
| Endpoint | Purpose | Authorization |
|---|---|---|
POST/api/{Module}/Submit | Submit a new document (inbound). | submit documents |
GET/api/{Module} | List your submissions (filterable). | read status |
GET/api/{Module}/{submissionId} | Envelope-shaped detail for one submission. | read status |
GET/api/{Module}/.../Status | Thin status for one submission. | read status |
List query filters (GET /api/{Module})
| Param | Notes |
|---|---|
direction | inbound or outbound. Omit for both. (LG accepts only outbound.) |
reference_no | Zero-pad tolerant: 11160 matches a stored 011160. |
status | Filter by status string. |
from / to | ISO-8601 timestamps bounding the creation time. |
limit | 1-500, default 100. |
offset | ≥ 0, for paging. Newest first. |
GET /api/Isf?direction=inbound&reference_no=11160&status=processed&limit=50&offset=0Detail envelope shape (GET /api/{Module}/{submissionId})
The detail endpoint returns an envelope describing one submission:
{
"channel": "isf.create",
"tenant_cid": "your-tenant",
"idempotency_key": "7f3c1e9a-...",
"submission_id": "3da64f8278c346ef922033414fe62be7",
"payload": {
"type": "ISF",
"status": "ADDITION",
"data": { "reference_no": "011160", "...": "all typed columns" },
"formatted_message": [
{ "line_no": 0, "message": "..." },
{ "line_no": 1, "message": "..." }
]
}
}
A 404 not_found is returned for an unknown id or one that
belongs to another account.
ISF - Importer Security Filing
header.importer_code is now validated against your imported
customers - an unknown code is rejected
(load it first via POST /api/Customers).
Several fields are
computed by the server and need not be sent:
reference_no is allocated when set to "NEW", and
header.isf_date, header.sailing_date, and
header.sf_trans_no are populated server-side. Any values you
send for those are overridden.
Required headers: ApiKey,
Idempotency-Key, Content-Type: application/json.
Returns 202 with a submission_id and a
status_url.
Pre-send validation. Every ISF Submit runs the same
pre-send checks the ASCI transmission queue applies (entity sets, address
rules, B/L + master-B/L, bond cross-rules, code tables). Blocking findings
reject the submission with 422 isf_validation_failed; the
structured list is under extra.errors /
extra.warnings (each entry
{ code, field, line_ref, message }). Non-blocking findings come
back on the 202 body as validation_warnings. Use
POST /api/Isf/Validate to pre-check a payload
without submitting.
Draft staging. Set document.submit_mode to
"draft" to stage the filing instead of sending it - the response
returns status "draft" and a transmit_url; nothing
is processed until POST /api/Isf/{submissionId}/Transmit.
Example request
POST /api/Isf/Submit
ApiKey: YOUR_API_KEY
Idempotency-Key: 7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22
Content-Type: application/json
{
"document": {
"reference_no": "NEW",
"header": {
"submission_type": "1",
"action_code": "A",
"action_reason": "CT",
"shipment_type": "01",
"operator_code": "001",
"ior_qualifier": "EI",
"ior_number": "12-3456789",
"importer_code": "ACME",
"mode_of_transport": "11",
"scac_code": "MAEU",
"customer_ref": "CUST-REF-001"
},
"bills_of_lading": [
{ "seq_no": "001", "code_qualifier": "OB", "bol_ref_no": "MAEU123456789" }
],
"containers": [ { "seq_no": "001", "container_no": "MAEU1234567" } ],
"parties": [
{ "party_type": "IM", "name": "ACME IMPORTS INC",
"identifier_qualifier": "EI", "identifier": "12-3456789" },
{ "party_type": "CN", "name": "ACME IMPORTS INC",
"identifier_qualifier": "EI", "identifier": "12-3456789" },
{ "party_type": "BY", "name": "ACME IMPORTS INC", "address_1": "123 MAIN ST",
"city": "MIAMI", "state": "FL", "postal_code": "33101", "country": "US" },
{ "party_type": "ST", "name": "ACME WAREHOUSE", "address_1": "123 MAIN ST",
"city": "MIAMI", "state": "FL", "postal_code": "33101", "country": "US" },
{ "party_type": "SE", "name": "GLOBAL TRADING CO", "address_1": "12 HARBOUR RD",
"city": "SHANGHAI", "country": "CN" },
{ "party_type": "LG", "name": "GLOBAL TRADING CO", "address_1": "12 HARBOUR RD",
"city": "SHANGHAI", "country": "CN" },
{ "party_type": "CS", "name": "GLOBAL TRADING CO", "address_1": "12 HARBOUR RD",
"city": "SHANGHAI", "country": "CN" },
{ "party_type": "MF", "name": "GLOBAL TRADING CO", "address_1": "12 HARBOUR RD",
"city": "SHANGHAI", "country": "CN", "manufacturer_id": "CNGLOTRA12SHA" }
],
"tariff": [
{ "seq_no": "001", "hts_number": "8471300100",
"description": "PORTABLE COMPUTERS", "country_of_origin": "CN" }
],
"bond": { "bond_type": "8", "activity_code": "01" },
"additional_references": []
}
}Example response (202)
{
"submission_id": "3da64f8278c346ef922033414fe62be7",
"document_type": "ISF",
"status": "queued",
"status_url": "https://asci-api.asciofmiami.com/api/ISF/Status/3da64f8278c346ef922033414fe62be7",
"message": "Queued for processing. Poll the status_url for progress."
}List submissions. See list filters.
GET /api/Isf?direction=inbound&limit=100&offset=0
ApiKey: YOUR_API_KEY{
"count": 1,
"rows": [
{
"submission_id": "3da64f8278c346ef922033414fe62be7",
"reference_no": "011160",
"status": "processed",
"direction": "inbound",
"created_at": "2026-05-08T22:37:06.443Z"
}
]
}Envelope-shaped detail; see the detail envelope shape.
GET /api/Isf/3da64f8278c346ef922033414fe62be7
ApiKey: YOUR_API_KEYGET /api/Isf/3da64f8278c346ef922033414fe62be7/Status
ApiKey: YOUR_API_KEY{
"submission_id": "3da64f8278c346ef922033414fe62be7",
"status": "processed",
"direction": "inbound",
"metadata": { "order_id": "A123", "warehouse": "MIA" },
"entry_no": "26000009901",
"approval_status": "APPROVED",
"updated_at": "2026-05-08T22:37:11.002Z"
}
entry_no and approval_status are part of the
Status payload for every module (ISF, QP, BL, ACEQE) and are
null until the back-office system reports them.
Dry-run pre-send validation - the same rule engine the Submit gate uses,
without storing or sending anything. Accepts the same body shape as
POST /api/Isf/Submit (partial drafts are fine - required-field
annotations are not enforced here). No Idempotency-Key needed.
Always returns 200 with the outcome - never 422.
errors would block a Submit; warnings never block
(typically “could not be verified” findings when reference data
has not been imported). field is a JSON-path-ish name
(header.scac_code, parties.address_1, ...);
line_ref identifies the row (a seq_no/index, or the
entity code for party findings).
POST /api/Isf/Validate
ApiKey: YOUR_API_KEY
Content-Type: application/json
{ "document": { "header": { ... }, "bills_of_lading": [ ... ], "parties": [ ... ] } }Example response (200)
{
"valid": false,
"errors": [
{ "code": "isf_entity_country_required", "field": "parties.country",
"line_ref": "SE", "message": "Entity SE ISF-10+2: Missing Entity Country Code" },
{ "code": "isf_bol_required", "field": "bills_of_lading", "line_ref": null,
"message": "At Least one B/L MUST be entered to complete the ISF Submission." }
],
"warnings": [
{ "code": "isf_carrier_unverified", "field": "header.scac_code", "line_ref": null,
"message": "ISF-10+2: SCAC Code 'MAEU' could not be verified against the Carrier File (no carrier data imported)" }
]
}
Files the stored ISF submission directly with CBP: the API
validates it (pre-send rules), builds the ABI SF transaction and
transmits it over the certified CBP connection. Replies are ingested
automatically and reflected back onto the submission
(cbp_accepted / cbp_rejected / cbp_warning
plus the CBP-assigned ISF transaction number) with a
document.status_changed webhook.
Required headers: ApiKey with the cbp.submit scope and
Idempotency-Key (replaying a key returns the prior CBP submission
with duplicate: true). The account must be enabled for CBP
transmission - otherwise 403 cbp_not_enabled. A payload that needs
a transmission feature not yet certified (delete action, containers, FROB,
personal-ID entities, submission types 5/6) returns
422 isf_catair_unsupported and nothing is transmitted.
POST /api/Isf/3da64f8278c346ef922033414fe62be7/TransmitCbp
ApiKey: YOUR_API_KEY
Idempotency-Key: cbp-7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22Example response (202)
{
"submission_id": "3da64f8278c346ef922033414fe62be7",
"cbp_submission_id": "c9c1b2a3d4e5f60718293a4b5c6d7e8f",
"status": "SENT",
"reference_no": "011692",
"environment": "CERT"
}
The CBP outcome for an ISF filed via TransmitCbp: the linked CBP
submission status (PENDING / SENT /
ACCEPTED / REJECTED / WARNING /
ERROR / TIMED_OUT), the CBP-assigned ISF transaction
number and the reply conditions. Requires the cbp.read scope.
404 not_transmitted when the ISF has not been filed with CBP by
the API yet.
GET /api/Isf/3da64f8278c346ef922033414fe62be7/CbpStatus
ApiKey: YOUR_API_KEYExample response (200)
{
"submission_id": "3da64f8278c346ef922033414fe62be7",
"cbp_submission_id": "c9c1b2a3d4e5f60718293a4b5c6d7e8f",
"status": "ACCEPTED",
"validation_status": null,
"isf_number": "S26-01234567890",
"bill_no": "APLU123456789",
"reference_no": "011692",
"environment": "CERT",
"transmitted_at": "2026-07-14T15:43:18.000Z",
"last_reply_at": "2026-07-14T15:44:02.000Z",
"error_message": null,
"conditions": [
{ "code": "02", "severity": "I", "text": "DATA ACCEPTED",
"received_at": "2026-07-14T15:44:02.000Z" }
]
}ISF document field reference
document top level:
| JSON key | Type | Req | Description |
|---|---|---|---|
reference_no | string(15) | yes | Reference number, or "NEW" to auto-allocate. |
metadata | object | no | Client-supplied key/value bag (string→string, ≤50 entries), echoed back on Status + webhook. |
header | object | yes | Header fields (below). |
bills_of_lading | array | no | Bill-of-lading lines. |
containers | array | no | Container lines. |
parties | array | no | Commercial parties (buyer, seller, etc.). |
tariff | array | no | HTS tariff lines. |
frob | array | no | Freight-remaining-on-board lines. |
additional_references | array | no | Additional reference rows. |
document.header:
| JSON key | Type | Req | Description |
|---|---|---|---|
submission_type | string(1) | no | Submission type. |
action_code | string(1) | no | Action code. |
abi_status | string(1) | no | ABI status. |
ior_qualifier | string | yes | Importer-of-record qualifier: EI = IRS/EIN, ANI = CBP-assigned #, 34 = SSN, AEF = Passport, 2 = SCAC (submission type 2 only). SS/CN also accepted. |
ior_number | string(15) | yes | Importer-of-record number. |
importer_code | string(6) | yes | Importer code. |
mode_of_transport | string | yes | Mode of transport (ABI MOT code list). |
scac_code | string(4) | yes | Exactly 4 uppercase letters. |
sf_trans_no | string(15) | no | Security filing transaction number. |
isf_date | string(7) | no | ISF date. |
sailing_date | string(7) | no | Sailing date. |
cbp_bill_on_file_date | string(7) | no | CBP bill-on-file date. |
cbp_bill_on_file_time | string(4) | no | CBP bill-on-file time. |
customer_ref | string(16) | no | Your customer reference. |
action_reason | string(2) | no | ISF action reason: CT = Compliant Transaction (the default when omitted), FR, FT, FX. |
shipment_type | string(2) | no* | Shipment type 01-11 (01 Standard, 02 To Order, 03 Household Goods, 04 Military/Government, 05 Diplomatic, 06 Carnet, 07 US Return Goods, 08 FTZ, 09 International Mail, 10 OCS, 11 Informal). *Required by pre-send validation. |
operator_code | string(3) | no* | Data-entry operator code, validated against the ASCI operator file. *Required by pre-send validation. |
country | string(2) | no | ISO country code; required when ior_qualifier is AEF (Passport). |
date_of_birth | string(10) | no | Date of birth, YYYYMMDD (-// separators tolerated); required when ior_qualifier is AEF (Passport). |
bills_of_lading[]: seq_no (string 3),
code_qualifier (string 2: OB = regular/ocean bill,
BN = house bill; with house bills the master B/L goes in
additional_references),
bol_ref_no (string 50, required per line). At least one line is required.
containers[]: seq_no (3),
container_no (15). Only allowed for mode_of_transport 11.
parties[]: party_type (3),
name (35), address_1/address_2 (35),
city (20), state (2),
postal_code (10), country (2),
identifier_qualifier (3), identifier (20),
manufacturer_id (16, MF parties). ISF-10 requires the entity set
MF, SE, BY, ST, IM, LG, CS (CN optional); ISF-5 requires BKP + ST. Address
information is mandatory for MF, SE, BY, ST, CS, LG.
tariff[]: seq_no (3),
hts_number (10), description (70),
country_of_origin (2, required per line on ISF-5).
frob[]: seq_no (3),
port_of_unlading (5), bol_ref_no (50).
ISF-5 only; maximum ONE row per filing.
additional_references[]: seq_no (3),
ref_qualifier (2), ref_value (35).
QP - In-Bond
Required headers: ApiKey,
Idempotency-Key, Content-Type: application/json.
The QP document is the most deeply nested: a header, a
conveyances array, a bills_of_lading array
(each bill nesting containers, which nest
harmonized_lines, pieces_descriptions,
marks_numbers, and hazardous_materials),
plus parties, all_additional_references, and
abi_status arrays.
Example request (abridged)
POST /api/Qp/Submit
ApiKey: YOUR_API_KEY
Idempotency-Key: qp-7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22
Content-Type: application/json
{
"document": {
"reference_no": "NEW",
"header": {
"in_bond_no": "QP260000099",
"in_bond_type": "61",
"customer_code": "ACME01",
"initiation_port_code": "5201",
"mode_of_transport": "10",
"carrier_code": "MAEU",
"us_port_of_destination": "1601",
"log_number": "LOG12345678",
"comments": ["line 1", "line 2"]
},
"conveyances": [
{ "seq_no": "01", "importing_carrier": "MAEU", "transportation_mode": "10",
"conveyance_name": "EVER GIVEN", "port_of_unlading": "5201", "num_bls": 1 }
],
"bills_of_lading": [
{ "conveyance_no": "01", "bl_line": "0001", "awb_bl_no": "MAEU2220000001",
"consignee_code": "CNSG01", "quantity": 100, "weight": 2500,
"containers": [
{ "container_line": "001", "container_number": "MAEU2222222",
"harmonized_lines": [
{ "item_line": "001", "seq": "001", "harmonized_tariff": "8471300100", "value": 50000 }
] }
] }
],
"parties": [
{ "conveyance_no": "01", "bl_line": "0001", "record_type": "C",
"name": "ACME IMPORTS LLC", "party_code": "CNSG01" }
],
"all_additional_references": [],
"abi_status": []
}
}Example response (202)
{
"submission_id": "b1d4...e7",
"document_type": "QP",
"status": "queued",
"status_url": "https://asci-api.asciofmiami.com/api/QP/Status/b1d4...e7"
}List submissions. See list filters.
Envelope detail; see detail shape.
Thin status, as shown in Status lifecycle - includes entry_no and approval_status.
QP document field reference
document top level:
| JSON key | Type | Req | Description |
|---|---|---|---|
reference_no | string(15) | yes | Reference number or "NEW". |
metadata | object | no | Client-supplied key/value bag (string→string, ≤50 entries), echoed back on Status + webhook. |
header | object | yes | In-bond header (below). |
conveyances | array | no | Conveyance rows. |
bills_of_lading | array | no | Bill-of-lading rows, each nesting containers + detail. |
parties | array | no | Party rows. |
all_additional_references | array | no | Additional reference rows. |
abi_status | array | no | ABI status rows. |
document.header (selected; the only required field is customer_code):
| JSON key | Type | Req | Description |
|---|---|---|---|
customer_code | string(6) | yes | Customer code. |
in_bond_no | string(12) | no | In-bond number. |
in_bond_type | string(2) | no | In-bond type. |
internal_date | string(7) | no | Internal date. |
initiation_port_code | string(4) | no | Initiation port code. |
mode_of_transport | string(3) | no | Mode of transport. |
carrier_code | string(4) | no | Carrier code. |
carrier_irs | string(12) | no | Carrier IRS number. |
us_port_of_destination | string(4) | no | US port of destination. |
foreign_port_of_destination | string(5) | no | Foreign port of destination. |
in_bond_value | number | no | In-bond value. |
num_conveyances | number | no | Conveyance count. |
log_number | string(11) | no | Log book number. |
comments | string[] | no | Free-text comment lines. |
Other header fields (all optional): previous_in_bond_no,
ftz_indicator, air_in_bond_pedimento,
scac_firms_indicator, inward_indicator,
first_delivering_trucking, ibec_code,
vessel_supplies_indicator, previous_in_bond_date,
canada_mexico_non_seaport, operator_code,
printed_indicator, bta_indicator,
go_number, previous_in_bond_type,
previous_in_bond_port.
conveyances[]: seq_no(2),
importing_carrier(4), country_of_carrier(2),
transportation_mode(2), vessel_code(7),
conveyance_name(23), voyage_flight_trip_no(5),
location_of_goods(4), port_of_unlading(4),
export_country(2), via(12),
num_bls, est_date_of_arrival,
export_date (numbers).
bills_of_lading[]: conveyance_no(2),
bl_line(4), awb_bl_no(16),
house_awb_bl_no(12), foreign_port_of_lading(5),
qty_unit(5), weight_unit(2),
measurement_unit(2), place_of_receipt(17),
sub_house_awb_bl_no(12), foreign_shipper_code(6),
consignee_code(6), notify_party_code(6),
secondary_notify_1..4(9), quantity,
weight, measurement, num_containers,
sailing_date (numbers), exporting_conveyance(23),
log_book_reference(6), warehouse_entry_balance(8),
in_bond_via(70), plus nested containers[] and
additional_references[].
bills_of_lading[].containers[]: container_line(3),
container_number(14), seal_number_1(15),
equipment_code(2), seal_number_2(15),
and nested harmonized_lines[],
pieces_descriptions[], marks_numbers[],
hazardous_materials[].
harmonized_lines[]: item_line(3),
seq(3), harmonized_tariff(10),
weight_unit(2), more_indicator(1),
item_from_hts(5), value, weight,
rate, duty (numbers), item_code(20).
pieces_descriptions[]: item_line(3),
seq(3), pieces(number), description(45),
more_indicator(1), manifest_unit_code(3).
marks_numbers[]: item_line(3), seq(3),
marks_and_numbers(45), more_indicator(1).
hazardous_materials[]: item_line(3), seq(2),
hazmat_code(10), class(4), qualifier(1),
description(30), contact_name_phone(24),
flashpoint_temperature(3), flashpoint_unit(2),
negative_indicator(1), description_instructions(29),
classification(30), description_instructions_2(29),
classification_2(30), more_indicator(1).
parties[]: conveyance_no(2), bl_line(4),
record_type(1), name(32),
address_line_1..3(30), phone(10),
party_code(6).
all_additional_references[] /
bills_of_lading[].additional_references[]:
conveyance_no(2), bl_line(4), seq(2),
qualifier(3), description(30).
abi_status[]: in-bond / arrival / export / transfer /
diversion status codes, dates, and times plus port and entry fields
(see Swagger for the full set).
BL - Import Billing
Required headers: ApiKey,
Idempotency-Key, Content-Type: application/json.
A header plus a charge_lines array; one record is created
per charge line.
Example request
POST /api/Bl/Submit
ApiKey: YOUR_API_KEY
Idempotency-Key: bl-7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22
Content-Type: application/json
{
"document": {
"reference_no": "NEW",
"additional_invoice_code": "",
"header": {
"invoice_no": "",
"customer_code": "ACME",
"customer_ref": "CUST-REF-100",
"transaction_code": "I",
"invoice_date": "20260424",
"invoice_description": "Import billing - ocean freight",
"shipper_consignee": "ACME / SHANGHAI EXPORTS",
"origin_destination": "CN/US",
"entry_number": "ENT-2026-001",
"entry_date": "20260420",
"airline_steamship": "MAEU",
"arrival_departure_date": "20260501",
"awb_bl_number": "MAEU123456789",
"house_awb": "",
"gl_division": "01",
"num_pieces": "100",
"invoice_value": 25000.00,
"weight": 1500.5,
"remarks": []
},
"charge_lines": [
{ "seq_no": "001", "company_code": "01", "vendor_code": "MAEU",
"transaction_code": "I", "log_type_code": "OF", "charge_code": "FRT",
"gl_number": "4100", "ap_gl_number": "2100", "prepaid_indicator": "P",
"charge_description": "Ocean Freight", "awb_bl_number": "MAEU1234567",
"pending_charge_ind": "N", "charge_amount": 3500.00, "ap_amount": 3200.00 },
{ "seq_no": "002", "company_code": "01", "vendor_code": "MAEU",
"transaction_code": "I", "log_type_code": "OF", "charge_code": "DOC",
"gl_number": "4110", "ap_gl_number": "2100", "prepaid_indicator": "C",
"charge_description": "Documentation Fee", "awb_bl_number": "MAEU1234567",
"pending_charge_ind": "N", "charge_amount": 75.00, "ap_amount": 0.00 }
]
}
}Example response (202)
{
"submission_id": "c8a2...f1",
"document_type": "BL",
"status": "queued",
"status_url": "https://asci-api.asciofmiami.com/api/BL/Status/c8a2...f1"
}List submissions. See list filters.
Envelope detail; see detail shape.
Thin status - includes entry_no and approval_status.
BL document field reference
document top level:
| JSON key | Type | Req | Description |
|---|---|---|---|
reference_no | string(15) | yes | Reference number or "NEW". |
metadata | object | no | Client-supplied key/value bag (string→string, ≤50 entries), echoed back on Status + webhook. |
additional_invoice_code | string(1) | no | Additional invoice code. |
header | object | yes | Billing header (below). |
charge_lines | array | no | One record is created per charge line. |
document.header:
| JSON key | Type | Req | Description |
|---|---|---|---|
invoice_no | string(6) | yes | Invoice number. |
customer_code | string(6) | yes | Customer code. |
customer_ref | string(11) | no | Your customer reference. |
transaction_code | string(1) | no | Transaction code. |
invoice_date | string(8) | no | Julian (7) or YYYYMMDD (8). |
invoice_description | string(20) | no | Invoice description. |
shipper_consignee | string(30) | no | Shipper / consignee. |
origin_destination | string(15) | no | Origin / destination. |
entry_number | string(12) | no | Entry number. |
entry_date | string(8) | no | Entry date. |
airline_steamship | string(17) | no | Airline / steamship line. |
arrival_departure_date | string(8) | no | Arrival / departure date. |
awb_bl_number | string(16) | no | AWB / BL number. |
house_awb | string(16) | no | House AWB. |
gl_division | string(2) | no | G/L division. |
num_pieces | string(8) | no | Piece count. |
invoice_value | number | no | Invoice value. |
weight | number | no | Weight. |
remarks | string[] | no | Free-text remark lines. |
charge_lines[]:
| JSON key | Type | Description |
|---|---|---|
seq_no | string(3) | Line sequence. |
company_code | string(1) | Company code. |
vendor_code | string(6) | Vendor code. |
transaction_code | string(1) | Transaction code. |
log_type_code | string(1) | Log type code. |
charge_code | string(3) | Charge code. |
gl_number | string(12) | G/L number. |
ap_gl_number | string(12) | A/P G/L number. |
prepaid_indicator | string(1) | Prepaid / collect indicator. |
charge_description | string(28) | Charge description. |
awb_bl_number | string(11) | AWB / BL number. |
pending_charge_ind | string(1) | Pending charge indicator. |
charge_amount | number | Charge amount. |
ap_amount | number | A/P amount. |
ACEQE - ACE Quick Entry
ACE Quick Entry is a flat-header document with ACE-specific fields, structured
commercial_entities, and a flat
pga_indicators array. It anchors on a
6-byte reference number allocated when
reference_no is "NEW".
/api/AceQe/Status/{submissionId} (id after
Status).
Required headers: ApiKey, Idempotency-Key, Content-Type: application/json.
Example request (abridged)
POST /api/AceQe/Submit
ApiKey: YOUR_API_KEY
Idempotency-Key: aceqe-7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22
Content-Type: application/json
{
"document": {
"reference_no": "NEW",
"filed_7501": "",
"consignee_type_code": "EI ",
"consignee_irs_number": "591234567 ",
"rlf_indicator": " ",
"default_country_code": "CN ",
"district_port_code": "52 ",
"gsp_cbi_nafta": "N",
"statement_status": "1",
"broker_or_sales_rep": "AF1 ",
"ach_indicator": "N",
"port_of_entry": "5201",
"firms_code": "ASCI",
"firms_city": "MIAMI",
"vessel_name": "EVER GOLDEN ",
"wh_indicator": "N",
"goods_description": "MEN'S KNIT SHIRTS - COTTON/POLYESTER BLEND ",
"invoice_count": " 1",
"team_code": "AF1",
"purchased_indicator": "Y",
"bond_notation": "BN",
"importer_of_record": "ABCIM1",
"ace_entry_type": "23",
"tariff_lines": [
{ "bond_no": "00123456789", "ruling_no": "H317.00000000 ",
"country_of_origin": "CN", "manufacturer_id": "CNSHGFACT001 ",
"tariff_no": "6110202010 " }
],
"bond_type_code": "9",
"box29_lines": ["MSCU1234567 ", ""],
"remarks_line_1": "ACE QUICK ENTRY TEST - VESSEL CONSUMP",
"i7": [0, 0, 0, 0],
"i9": [0],
"i10": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
"commercial_entities": [
{ "role": "CN", "name": "ABC IMPORTS INC ",
"type_qualifier": "EI ", "identifier": "591234567 ",
"address_block": "1000 NW 42ND AVE ",
"customer_division": "ABCIM1" },
{ "role": "MF", "name": "SHANGHAI GARMENT FACTORY ",
"type_qualifier": "MF ", "identifier": "CNSHGFACT001 ",
"address_block": "123 PUJIANG RD SHANGHAI CHINA ",
"customer_division": "ABCIM1" }
],
"pga_indicators": ["N", "N", "N", "N", "N"],
"country_subdivision": "FL"
}
}Example response (202)
{
"submission_id": "5b77...c0",
"document_type": "ACEQE",
"status": "queued",
"status_url": "https://asci-api.asciofmiami.com/api/ACEQE/Status/5b77...c0"
}List submissions. See list filters.
Envelope detail; ACEQE nests commercial_entities and pga_indicators under payload.data.
Thin status (note the Status/{id} order) - includes entry_no and approval_status.
ACEQE document field reference
Fields sit directly under document. Only
reference_no is required. ace_entry_type,
when supplied, must be one of 23, 24,
25, 28, 31, 51.
Several string fields are space-padded to a fixed width
in the legacy layout.
| JSON key | Type | Req | Description |
|---|---|---|---|
reference_no | string(6) | yes | 6-byte reference number, or "NEW". |
metadata | object | no | Client-supplied key/value bag (string→string, ≤50 entries), echoed back on Status + webhook. |
filed_7501 | string(1) | no | "1" = 7501 filed. |
consignee_type_code | string(3) | no | IRS type code. |
transcargo_indicator | string(10) | no | Customer-specific indicator. |
consignee_irs_number | string(12) | no | Consignee IRS#; blank if multiple. |
rlf_indicator | string(1) | no | Remote location filing. |
rlf_qualifier | string(4) | no | RLF reference qualifier. |
default_country_code | string(5) | no | Default country / port. |
district_port_code | string(5) | no | Examiner district / port. |
bond_type_indicator | string(1) | no | Bond / periodic indicator. |
gsp_cbi_nafta | string(1) | no | Trade preference indicator. |
statement_status | string(1) | no | Statement status. |
broker_or_sales_rep | string(5) | no | Sales rep / broker code. |
nafta_claim_type | string(1) | no | NAFTA claim type (entry type 08). |
ach_indicator | string(1) | no | ACH payment indicator. |
flight_number | string(5) | no | Flight / voyage number. |
port_of_entry | string(4) | no | Port of entry. |
firms_code | string(4) | no | Location code for exam. |
unbalanced_indicator | string(1) | no | "1" = unbalanced. |
firms_city | string(5) | no | City portion. |
vessel_name | string(22) | no | Vessel / carrier name. |
weekly_estimated_ind | string(1) | no | Weekly / periodic indicator. |
wh_indicator | string(1) | no | Warehouse indicator. |
goods_description | string(60) | no | Free-text goods description. |
invoice_count | string(4) | no | Number of invoices. |
no_release_requested | string(1) | no | Suppress automated release request. |
transfer_indicator | string(1) | no | In-bond / transfer type. |
team_code | string(3) | no | Team code. |
purchased_indicator | string(1) | no | Goods purchased flag. |
bond_notation | string(2) | no | Bond notation ("BN"). |
immediate_delivery_ind | string(1) | no | Immediate delivery indicator. |
importer_of_record | string(6) | no | Importer of record code. |
awb_date_or_multi | string(7) | no | AWB/BL date or "MULTI ". |
paperless_flag | string(1) | no | Paperless 7501 flag. |
ruling_info_indicator | string(1) | no | Ruling numbers entered. |
secondary_port_code / secondary_port_name | string(4)/(25) | no | Secondary port of lading. |
aii_filed | string(1) | no | Filed AII indicator. |
split_release | string(1) | no | Split release. |
multi_consignee / multi_manufacturer / multi_other_entities | string(1) | no | Multiple-entity flags. |
ace_entry_type | string(2) | no | One of 23, 24, 25, 28, 31, 51. |
entry_class_init | string(11) | no | Entry type setup field. |
aii_supplier_id | string(15) | no | AII supplier ID. |
ces_transfer_site | string(4) | no | CES exam transfer site. |
district_port_short | string(2) | no | District port (2-char). |
exam_site_data | string(15) | no | Exam site additional data. |
tariff_lines | array | no | Up to 5 tariff lines. |
bond_type_code | string(1) | no | Bond type code. |
multi_seller ... multi_booking | string(1) | no | ACE multiple-entity flags (seller/buyer/ship-to/location/consolidator/booking). |
box29_lines | string[] | no | Up to 10 Box-29 lines (36 chars each). |
containers | array | no | Structured containers; preferred over box29_lines when present. |
remarks_line_1..3 | string(35) | no | Free-text remarks. |
i7 / i9 / i10 | int[] | no | Numeric blocks (4 / 1 / 25 elements). |
commercial_entities | array | no | One per consignee / manufacturer / seller / buyer / etc. (below). |
pga_indicators | string[] | no | Per-tariff-line "Y"/"N" PGA flags. |
country_subdivision | string | no | State / province subdivision (e.g. "FL"). |
commercial_entities[]: role(3, e.g. "CN"/"MF"),
name(35), type_qualifier(3, e.g. "EI"/"MF"),
identifier(20), address_block(70),
customer_division(6).
containers[]: seq (int, 0-based row index),
awb_seq(6, ties container to its AWB/BL),
container_number(20).
LG - Log Book (outbound / read-only)
LG is read-only. There is no LG Submit endpoint; LG records are produced
by the back-office system and made available to you for reading. All LG
list/lookup endpoints enforce direction=outbound.
List LG submissions. direction defaults to
outbound and only that value is accepted (any other
returns 400 invalid_direction). Other filters match the
standard list filters.
GET /api/Lg?direction=outbound&limit=100&offset=0
ApiKey: YOUR_API_KEYEnvelope-shaped detail for one LG submission; see the detail envelope shape. Tenant-scoped (404 on miss/cross-tenant).
GET /api/Lg/3da64f8278c346ef922033414fe62be7
ApiKey: YOUR_API_KEYThin status for one LG submission.
GET /api/Lg/3da64f8278c346ef922033414fe62be7/Status
ApiKey: YOUR_API_KEYCBP Communication (CBPCOM)
The CBP module transmits a built CATAIR message to U.S. Customs (CBP) over the
ABI / ISF / Quick-Entry / AES / DIS channels and captures every reply. The legacy
system builds the CATAIR (after inserting the entry and generating the reference);
these endpoints perform the transmit and reply tracking. Certification is
the active environment by default - switching to Production is a
controlled, loopback-only operation. Scopes: cbp.submit (transmit),
cbp.read (view).
{channel} is one of isf, qe,
abi, aes, dis. Every response (success and
failure) is recorded in two stages: a pre-transmit validation_status
(blocks the send on failure) and the CBP outcome status
(PENDING → SENT →
ACCEPTED / REJECTED / WARNING /
ERROR). Captured identifiers include entry_no (Quick
Entry), isf_number (ISF Transaction Number), bill_no (bill
of lading), and confirmation_no, plus the full list of CBP condition
codes per reply.
Transmit a built CATAIR message to CBP for {channel}. Requires an
Idempotency-Key header (replay returns the prior submission). Send
the message inline as catair, or reference a file the legacy step
dropped in the tenant CBP outbox as catair_file. Returns
202 with a submission_id. A failed pre-transmit
validation returns 422 cbp_validation_failed (never reaches CBP).
POST /api/Cbp/isf/Transmit
ApiKey: YOUR_API_KEY
Idempotency-Key: 7b1f...e9
Content-Type: application/json
{
"reference_no": "009125",
"filer_code": "S38",
"catair": "A5206S38ROBERT...SF\n..."
}List your CBP submissions. Filters: channel, status, reference_no, limit, offset.
GET /api/Cbp/Submissions?channel=isf&status=ACCEPTED&limit=100
ApiKey: YOUR_API_KEY
Full detail for one submission, including every captured CBP reply (condition
codes + text + severity), the assigned entry_no /
isf_number / bill_no, the raw CATAIR sent, and the raw
reply blocks. Tenant-scoped (404 on miss/cross-tenant).
GET /api/Cbp/isf/3da64f8278c346ef922033414fe62be7
ApiKey: YOUR_API_KEYThin status: status, validation_status, entry_no, isf_number, confirmation_no, bill_no, last_reply_at.
GET /api/Cbp/isf/3da64f8278c346ef922033414fe62be7/Status
ApiKey: YOUR_API_KEY
Returns the active CBP environment - CERT (Certification) or
PROD (Production) - plus the gateway host/port and queue names.
Switching environments is an operator action in the ASCI API Manager (loopback-only).
GET /api/Cbp/Environment
ApiKey: YOUR_API_KEYWorkflows & features
Optional flows layered on top of Submit: stage as a draft, transmit it, or clone an existing entry.
Draft vs direct submit
Every POST /api/{Module}/Submit can either send the document
straight through to the back-office system (the historical behaviour) or
stage it as a draft that you edit, validate, and
explicitly release later. The choice is made per request with an
optional field on the envelope; the default is
direct, so existing integrations are unaffected.
Selecting the mode
Set submit_mode to either "direct" or
"draft" (case-insensitive). It is accepted in any of three
places - under document, at the top level of the body,
or under data - so it is easy to add wherever your
builder assembles the request. As an alternative you may send a boolean
draft (true = draft, false =
direct).
{
"document": {
"reference_no": "NEW",
"submit_mode": "draft",
"...": "module-specific fields"
}
}| Mode | What happens |
|---|---|
direct (default) |
Unchanged behaviour. The submission is queued and
inserted into ASCI by the serialized FIFO
consumer. Lifecycle: queued → processing →
processed | rejected. |
draft |
The submission is held in the API with status
draft. No inbox files are written and nothing
is inserted into ASCI. You edit/validate it on
the platform, then release it with the
Transmit endpoint. Lifecycle:
draft → (Transmit) → queued →
processing → processed | rejected. |
Draft Submit response (202)
A draft Submit returns 202 with status: "draft"
and, in addition to the usual status_url, a
transmit_url plus an extra.actions array listing
the next action you can take:
{
"submission_id": "9b1c4f0a7e2d4c1f8a3b6e5d2c9f0a11",
"document_type": "ISF",
"status": "draft",
"status_url": "https://asci-api.asciofmiami.com/api/Isf/Status/9b1c4f0a...",
"transmit_url": "https://asci-api.asciofmiami.com/api/Isf/9b1c4f0a.../Transmit",
"message": "Staged as a draft. Edit and validate, then POST the transmit_url to send it.",
"extra": { "actions": ["send_to_cbp"] }
}bbx_reference_no. The reference number is assigned at
Transmit/insert time. Poll the
status_url after transmitting to pick it up.
Transmit a draft
Send a previously-staged draft to the
back-office system. After a draft Submit, the draft sits in the API with status
draft until you call its Transmit endpoint. ISF, QP,
BL, and ACEQE all expose Transmit; the same key authorization as
Submit is required.
The route is the same shape for every module:
POST /api/{Module}/{submissionId}/Transmit
Replace {Module} with Isf, Qp,
Bl, or AceQe. On success returns 202
with status: "queued", transmitted: true, and a
status_url. The new reference_no is allocated by
the back-office system at Transmit/insert time, not at draft/copy time.
Releases the ISF draft into the serialized FIFO queue.
POST /api/Isf/9b1c4f0a7e2d4c1f8a3b6e5d2c9f0a11/Transmit
ApiKey: YOUR_API_KEY{
"submission_id": "9b1c4f0a7e2d4c1f8a3b6e5d2c9f0a11",
"document_type": "ISF",
"status": "queued",
"transmitted": true,
"status_url": "https://asci-api.asciofmiami.com/api/Isf/Status/9b1c4f0a..."
}The QP (In-Bond) equivalent. Same semantics and response shape as ISF Transmit.
POST /api/Qp/9b1c4f0a7e2d4c1f8a3b6e5d2c9f0a11/Transmit
ApiKey: YOUR_API_KEYThe BL (Import Billing) equivalent. Same semantics and response shape as ISF Transmit.
POST /api/Bl/9b1c4f0a7e2d4c1f8a3b6e5d2c9f0a11/Transmit
ApiKey: YOUR_API_KEYThe ACEQE equivalent. Same semantics and response shape as ISF Transmit.
POST /api/AceQe/9b1c4f0a7e2d4c1f8a3b6e5d2c9f0a11/Transmit
ApiKey: YOUR_API_KEYdraft status is transmitted. A second call against an
already-transmitted draft returns 200 with
transmitted: false and does not double-insert,
so it is safe to retry after a timeout.
Transmit is tenant-scoped: an unknown id, or one belonging to another
account, returns 404 not_found as the uniform
error body.
Reference data (master data)
Tenant-scoped master data - customers, manufacturers, and products - with per-category lookup (GET) and create/upsert (POST), and the provisional 7501 linkage.
Overview
The API holds your master data - customers,
manufacturers, and products - in a persistent, tenant-scoped store.
Every lookup and write is automatically scoped to your own account; you
never address another integration's records. The data backs the platform
forms and is what inbound documents validate against (for example, an ISF
importer_code is checked against your imported customers).
This category is organized by entity. Each entity exposes the same two operations:
- Lookup
GET- list / partial-match search (and, for customers, fetch one by exact code). Requires your key be authorized to read status (scopequeue.read). - Create / upsert
POST- create or idempotently update one record. Requires submit authorization (scopeipjson.submit) and the sameIdempotency-Keyheader as any document Submit.
All write endpoints synchronously upsert into the API store (so lookups resolve immediately) and enqueue a forward-compatible legacy write on the same FIFO pipeline the document modules use.
code (customers), mid (manufacturers), and
optional product_code (products). Re-sending the same key is
an idempotent update, not a duplicate - the store keys on
(your account + that identifier).
Customers
Your importer / customer master. Keyed by a client-supplied
code. This is the list an inbound ISF
importer_code is validated against.
List / search your customer master. Scope: queue.read.
GET /api/Customers?code=ACME&name=IMPORTS&limit=200
ApiKey: YOUR_API_KEY| Query param | Notes |
|---|---|
code | Partial match on customer code. |
name | Partial match on customer name. |
limit | Max rows, default 200. |
Returns { count, rows[] }; each row carries the full customer field set (below) plus created_at / updated_at.
Fetch a single customer by exact code. 404 not_found if absent for your account. Scope: queue.read.
GET /api/Customers/ACME
ApiKey: YOUR_API_KEY
Create or upsert one customer. The record is upserted into the API
store immediately (idempotent, keyed by your account + code)
and a legacy write is enqueued. Returns 202 with a
submission_id. Required headers: ApiKey
(scope ipjson.submit), Idempotency-Key (8-128
chars), Content-Type: application/json.
Example request
POST /api/Customers
ApiKey: YOUR_API_KEY
Idempotency-Key: cust-7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22
Content-Type: application/json
{
"code": "ACME",
"id_qualifier": "EI",
"id_number": "12-3456789",
"name": "ACME IMPORTS INC",
"address_1": "123 MAIN ST",
"address_2": "",
"city": "MIAMI",
"state": "FL",
"zip": "33101",
"country": "US",
"irs_no": "123456789",
"surety": "BOND SURETY CO",
"bond_type": "8",
"continuous_bond_no": "9876543210",
"manufacturer_no": "CNACM1234SHA"
}
code is the only required field. A missing or blank
code returns 400 missing_code as the uniform
error body.
Customer field reference
| JSON key | Type | Req | Description |
|---|---|---|---|
code | string(10) | yes | Client-supplied customer code; the upsert key. |
id_qualifier | string(2) | no | Identifier qualifier (e.g. EI). |
id_number | string(15) | no | Identifier number. |
name | string(35) | no | Customer name. |
address_1 | string(35) | no | Address line 1. |
address_2 | string(35) | no | Address line 2. |
city | string(20) | no | City. |
state | string(2) | no | State / province. |
zip | string(10) | no | Postal code. |
country | string(2) | no | ISO country code. |
irs_no | string(15) | no | IRS number. |
surety | string(35) | no | Surety. |
bond_type | string(2) | no | Bond type. |
continuous_bond_no | string(15) | no | Continuous bond number. |
manufacturer_no | string(15) | no | Linked manufacturer number. |
defaults | object | no | Free-form per-customer ISF default overrides, stored verbatim. |
Manufacturers
Your MID (manufacturer-id) master. Keyed by a client-supplied mid.
Partial-match search over your manufacturer master. Scope: queue.read.
GET /api/Manufacturers?name=ACME&address=SHANGHAI&mid=CNACM&limit=200
ApiKey: YOUR_API_KEY| Query param | Notes |
|---|---|
name | Partial match on manufacturer name. |
address | Partial match on the address lines or city. |
mid | Partial match on the manufacturer id (MID). |
limit | Max rows, default 200. |
Returns { count, rows[] }; each row carries the manufacturer field set (below) plus created_at / updated_at.
Create or upsert one manufacturer (idempotent, keyed by your account +
mid). Returns 202 with a
submission_id. Required headers: ApiKey
(scope ipjson.submit), Idempotency-Key (8-128
chars), Content-Type: application/json.
Example request
POST /api/Manufacturers
ApiKey: YOUR_API_KEY
Idempotency-Key: mfr-7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22
Content-Type: application/json
{
"mid": "CNACM1234SHA",
"name": "ACME MANUFACTURING CO",
"address_1": "123 PUJIANG RD",
"address_2": "",
"city": "SHANGHAI",
"state": "",
"postal_code": "200120",
"country": "CN"
}
mid is the only required field. A missing or blank
mid returns 400 missing_mid as the uniform
error body.
Manufacturer field reference
| JSON key | Type | Req | Description |
|---|---|---|---|
mid | string(15) | yes | Manufacturer id; the upsert key. |
name | string(35) | no | Manufacturer name. |
address_1 | string(35) | no | Address line 1. |
address_2 | string(35) | no | Address line 2. |
city | string(35) | no | City. |
state | string(2) | no | State / province. |
postal_code | string(10) | no | Postal code. |
country | string(2) | no | ISO country code. |
Products
Your product (catalog item) master. A product may be linked to a manufacturer, but the link is optional - see the unlinked case below.
Search your product master. Scope: queue.read.
GET /api/Products?code=ABC&description=COTTON&manufacturer_id=CNACM1234SHA&limit=200
ApiKey: YOUR_API_KEY| Query param | Notes |
|---|---|
code | Partial match on product code. |
description | Partial match on product description. |
manufacturer_id | Exact-match filter to one manufacturer id. |
limit | Max rows, default 200. |
Returns { count, rows[] }; each row is { product_code, description, tariff_no, manufacturer_id, created_at, updated_at } (manufacturer_id is null for an unlinked product).
Create or upsert one product (idempotent, keyed by your account +
product_code). Returns 202 with a
submission_id. Required headers: ApiKey
(scope ipjson.submit), Idempotency-Key (8-128
chars), Content-Type: application/json.
description is the only required field. A missing or blank
description returns 400 missing_description as
the uniform error body.
manufacturer_id is optional - unlinked
products are supported. Supply manufacturer_id to
link the product to a manufacturer (the legacy key is the
MID + description pair). Omit it for an unlinked
product - a description plus optional tariff with no manufacturer.
This is the supported "verbatim product line" case, where the platform
carries a product line on the entry as typed without resolving it to a
MID. product_code is also optional: when you omit it the
store synthesizes a stable code from manufacturer_id +
description (linked) or from description alone
(unlinked).
Example request (linked)
POST /api/Products
ApiKey: YOUR_API_KEY
Idempotency-Key: prod-7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22
Content-Type: application/json
{
"manufacturer_id": "CNACM1234SHA",
"description": "MEN'S KNIT SHIRTS - COTTON/POLYESTER BLEND",
"tariff_no": "6110202010",
"product_code": "SHIRT-001"
}Example request (unlinked - "verbatim product line")
POST /api/Products
ApiKey: YOUR_API_KEY
Idempotency-Key: prod-9a01-8c2f5b6d1e22-2b44-4d6e
Content-Type: application/json
{
"description": "ASSORTED PROMOTIONAL GIFT ITEMS",
"tariff_no": "9505900000"
}Product field reference
| JSON key | Type | Req | Description |
|---|---|---|---|
description | string(70) | yes | Product description. |
manufacturer_id | string(16) | no | Optional. Omit for an unlinked product; when present, links the product to this MID. |
tariff_no | string(10) | no | HTS tariff number. |
product_code | string(70) | no | Optional. The store key; synthesized from MID + description (linked) or description (unlinked) when omitted. |
Vendors (A/P)
Your accounts-payable vendor master - a first-class reference
entity like customers / manufacturers / products. Keyed by a client-supplied
code (the legacy AP_VEND_CODE). Source: legacy A/P
vendor master APVE{CID}. The vendor master backs the
Pending Charges billing module, which resolves
its provider payee against these records.
POST /api/Vendors is a synchronous store upsert only. Vendors can
also be loaded in bulk via POST /api/Import/Entities (the
vendors array) and exported for push-to-legacy via
GET /api/Import/EntitiesExport?types=vendors.
List / search your A/P vendor master. Scope: queue.read.
GET /api/Vendors?code=CARGO&name=SPRINT&limit=200
ApiKey: YOUR_API_KEY| Query param | Notes |
|---|---|
code | Partial match on vendor code. |
name | Partial match on vendor name. |
q | Single term matching code OR name. |
limit | Max rows, default 200. |
Returns { count, rows[] }; each row carries the full vendor field set (below) plus created_at / updated_at.
Fetch a single vendor by exact code. 404 not_found if absent for your account. Scope: queue.read.
GET /api/Vendors/ACMEFRT
ApiKey: YOUR_API_KEY
Create or upsert one vendor. The record is upserted into the API store
immediately (idempotent, keyed by your account + code).
Returns { code, inserted, updated }. Required headers:
ApiKey (scope ipjson.submit),
Content-Type: application/json.
Example request
POST /api/Vendors
ApiKey: YOUR_API_KEY
Content-Type: application/json
{
"code": "ACMEFRT",
"name": "ACME FREIGHT LLC",
"vendor_type": "AP",
"address_1": "1 PROVIDER WAY",
"city": "ATLANTA",
"state": "GA",
"zip": "30301",
"country": "US",
"terms_code": "NET30",
"gl_acct_ap": "2000",
"payto_name": "ACME FREIGHT LLC"
}
code is the only required field. A missing or blank
code returns 400 missing_code as the uniform
error body.
Vendor field reference
| JSON key | Type | Req | Description |
|---|---|---|---|
code | string(15) | yes | Vendor code / AP_VEND_CODE; the upsert key. |
name | string | no | Vendor name. |
vendor_type | string | no | Vendor type (AP_VENDOR_TYPE). |
contact | string | no | Contact name (AP_CONTACT). |
address_1 / address_2 / address_3 | string | no | Address lines. |
city / state / zip / country / overseas | string | no | Location. |
phone_area / phone / fax_area / fax | string | no | Phone + fax. |
terms_code / form_code | string | no | Payment terms + form code. |
gl_acct_ap | string | no | A/P GL control account (GL_ACCT_AP). |
gl_acct_no | string | no | Default expense GL account (GL_ACCT_NO). |
our_acct_no | string | no | Our account number with this vendor. |
recipient_id | string | no | 1099 recipient id (RECIPIENT_ID). |
payto_name / payto_addr_1 / payto_addr_2 / payto_city / payto_state / payto_zip / payto_country / payto_attn / payto_phone | string | no | Remit-to (pay-to) block. |
Delete one vendor by code (returns { deleted: 1 }), or
DELETE /api/Vendors?confirm=true to wipe ALL vendors for your
account so they can be re-imported. Scope: ipjson.submit.
7501 entry (provisional)
POST /api/Entry7501/CreateFromQuickEntry
ApiKey: YOUR_API_KEY
Content-Type: application/json
{ "aceqe_reference_no": "011160" }Example response (202)
{
"entry_7501_reference": "75-011160",
"source_aceqe_reference_no": "011160",
"status": "linked",
"note": "provisional linkage; full 7501 entity pending design"
}Billing
Pending-charges store + settlement writeback feed (ASCI only).
Pending Charges
The Pending Charges module is the API-side read-model of the
legacy IPCHR pending charges (doc type PCHG),
tenant-scoped and keyed by (ref_no, seq_no). Its
payee resolves against the A/P Vendors master. Traffic
flows in three directions: ASCI pushes charges in, the billing pipeline sends
them to the payment provider for settlement, and the ASCI side polls a settlement feed to
apply results back.
charges.pending channel dispatches to the outbound payment handler,
currently a STUB pending the provider's API spec).
This module is ASCI only.
Direction: ASCI → API store. Push a batch of
pending charges. Idempotent UPSERT keyed by tenant +
(ref_no, seq_no); mode is
add (skip existing) or replace (upsert; default).
Provider settlement fields are preserved across a re-push. Scope:
ipjson.submit. Returns
{ mode, inserted, updated, skipped, errors }.
Example request
POST /api/Charges/Import
ApiKey: YOUR_API_KEY
Content-Type: application/json
{
"mode": "replace",
"charges": [
{
"ref_no": "011160",
"seq_no": "001",
"vendor_code": "ACMEFRT",
"charge_code": "FRT",
"record_type": "C",
"amount": 1250.00,
"billed": "N",
"customer_id": "ACME",
"date": "2026-06-26",
"vendor_name": "ACME FREIGHT LLC",
"payment_type": "ACH",
"awb_bl_no": "MAEU123456789"
}
]
}Charge field reference (charges[])
| JSON key | Type | Req | Description |
|---|---|---|---|
ref_no | string | yes | CH_REF_NO (key). |
seq_no | string | yes | CH_SEQ_NO (key). |
vendor_code | string | no | A/P vendor code (payee). |
charge_code | string | no | Charge code. |
record_type | string | no | Record type. |
amount | number | no | Charge amount. |
billed | string | no | Billed flag. |
customer_id | string | no | Customer id. |
check_no | string | no | Check number. |
date | string | no | Charge date. |
vendor_name | string | no | Vendor name (denormalized). |
payment_type | string | no | Payment type. |
awb_bl_no | string | no | AWB / B-L number. |
status | string | no | Optional initial status (defaults to pending). |
List pending charges. Filters: ?status=&vendor_code=&customer_id=&limit=. Scope: queue.read. Returns { count, rows[] }.
GET /api/Charges?status=pending&vendor_code=ACMEFRT&limit=500
ApiKey: YOUR_API_KEYFetch a single charge by ref_no + seq_no. 404 not_found if absent. Scope: queue.read.
GET /api/Charges/011160/001
ApiKey: YOUR_API_KEY
Direction: API → ASCI (poll). The settlement
writeback feed the ASCI side polls to apply results back to ASCI.
Returns charges that carry a provider settlement (default: those with a
non-empty settlement_status). The ASCI poller applies these
onto its IPCHR records, then re-imports with an advanced
status to close the loop. Filters:
?status=&settlement_status=&limit=. Scope:
queue.read.
GET /api/Charges/Settlements?limit=500
ApiKey: YOUR_API_KEY{
"count": 1,
"rows": [
{
"ref_no": "011160",
"seq_no": "001",
"status": "paid",
"provider_payment_id": "SP-9988",
"paid_amount": 1250.00,
"paid_date": "2026-06-26",
"settlement_status": "settled",
"settlement_raw": "{...}",
"updated_at": "2026-06-26T14:30:00Z"
}
]
}Integration
Receive results without polling, and a copy-paste path from zero to your first submission.
Webhooks
Register one or more URLs to be notified whenever a document is accepted for your account. This is how processed/outbound results reach you in near-real time without polling. Managing webhooks requires that your key be authorized for webhook management.
Register
POST /api/Webhook/register
ApiKey: YOUR_API_KEY
Content-Type: application/json
{
"url": "https://your-server.example.com/hooks/asci",
"event_type": "document.received",
"secret": "your-shared-hmac-secret"
}
url is required and must be a public HTTPS URL.
event_type is optional and defaults to
document.received (currently the event fired).
secret is optional; when set, deliveries are signed (see
below). Returns 201 with the registration object
(including its numeric id).
List
GET /api/Webhook/list
ApiKey: YOUR_API_KEYReturns 200 with an array of your registrations.
Unregister
DELETE /api/Webhook/unregister/42
ApiKey: YOUR_API_KEY
Returns 204 on success, 404 if the id does
not exist, 403 if the registration belongs to another
account.
Notification body
On each event, the API POSTs a JSON notification to every active
registration. The body carries the event metadata plus the full typed
document under data, so you can consume it directly:
{
"event_type": "document.received",
"document_type": "ISF",
"reference_no": "011160",
"submission_id": "3da64f8278c346ef922033414fe62be7",
"tenant_domain": "your-tenant",
"received_at": "2026-05-08T22:37:06.443Z",
"data": {
"channel": "isf.create",
"tenant_cid": "your-tenant",
"idempotency_key": "7f3c1e9a-...",
"submission_id": "3da64f8278c346ef922033414fe62be7",
"payload": {
"type": "ISF",
"status": "ADDITION",
"data": { "reference_no": "011160", "...": "all typed columns" },
"formatted_message": [ { "line_no": 0, "message": "..." } ]
}
}
}
data may be null if the typed document is not
available for an event. For ACEQE events, data.payload.data
nests the child arrays (tariff_lines,
box29_lines, containers,
commercial_entities, pga_indicators).
Status-change notifications (document.status_changed)
As each queued entry is processed by the back-office system (see
Processing model), the API emits a
document.status_changed webhook for that entry. In addition to
the existing reference_no, status, and
error_message fields, the payload carries the
back-office-reported results - both as top-level envelope fields and
under data:
| Field | Meaning |
|---|---|
metadata | The client-supplied metadata object you sent on Submit (or null). |
entry_no | Back-office-reported entry number, when one was assigned (else null). |
approval_status | Back-office-reported approval / disposition (else null). |
{
"event_type": "document.status_changed",
"document_type": "ISF",
"reference_no": "011160",
"submission_id": "3da64f8278c346ef922033414fe62be7",
"status": "processed",
"error_message": null,
"metadata": { "order_id": "A123", "warehouse": "MIA" },
"entry_no": "26000009901",
"approval_status": "APPROVED",
"tenant_domain": "your-tenant",
"received_at": "2026-05-08T22:37:11.002Z",
"data": {
"status": "processed",
"reference_no": "011160",
"metadata": { "order_id": "A123", "warehouse": "MIA" },
"entry_no": "26000009901",
"approval_status": "APPROVED",
"error_message": null
}
}Push vs pull consumer patterns
- Push consumer: read
datadirectly from the notification body. No follow-up call needed. - Pull consumer: ignore
data, treat the webhook purely as a signal, and callGET /api/{Module}/{submissionId}to fetch the document when you are ready.
Both patterns work from the same notification.
Signature verification (HMAC-SHA256)
If you registered the webhook with a secret, every delivery
includes a signature header computed over the exact raw request body:
X-Webhook-Signature: sha256=<HMAC-SHA256 hex of the raw body, keyed with your secret>
On receipt, recompute the HMAC-SHA256 of the raw body bytes using your
secret, hex-encode it, prefix sha256=, and compare against
the header using a constant-time comparison before trusting the payload.
// Node.js example
const crypto = require('crypto');
function verify(rawBody, header, secret) {
const expected = 'sha256=' +
crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(header || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Delivery & retry policy
Deliveries are fire-and-forget with a 10-second timeout.
There is no automatic retry in this version: if your
endpoint returns a non-2xx status or times out, that delivery is recorded
as failed and not re-sent. Make your receiver fast and idempotent, return
2xx quickly, and use the submission_id to
de-duplicate. If you miss a notification, you can always reconcile by
listing or polling the relevant module endpoint.
Quick start
- Get your API key from your ASCI integration contact, and the base URL for your environment. Confirm the key is authorized for the operations you need (submitting, reading status, managing webhooks).
-
Submit a document with an
Idempotency-Key:The response iscurl -X POST "https://asci-api.asciofmiami.com/api/Isf/Submit" \ -H "ApiKey: YOUR_API_KEY" \ -H "Idempotency-Key: 7f3c1e9a-2b44-4d6e-9a01-8c2f5b6d1e22" \ -H "Content-Type: application/json" \ -d '{ "document": { "reference_no": "NEW", "header": { "ior_qualifier": "EI", "ior_number": "12-3456789", "importer_code": "ACME", "mode_of_transport": "10", "scac_code": "MAEU" } } }'202with asubmission_idand astatus_url. -
Poll status until it reaches
processed(with a reference number) orrejected:(For ACEQE the status path iscurl "https://asci-api.asciofmiami.com/api/Isf/3da64f8278c346ef922033414fe62be7/Status" \ -H "ApiKey: YOUR_API_KEY"/api/AceQe/Status/{id}.) -
Optionally, register a webhook so you are notified
automatically instead of polling:
Verify the
curl -X POST "https://asci-api.asciofmiami.com/api/Webhook/register" \ -H "ApiKey: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-server.example.com/hooks/asci", "event_type": "document.received", "secret": "your-shared-hmac-secret" }'X-Webhook-Signatureon every delivery and read the document straight from the notification'sdatafield, or useGET /api/{Module}/{submissionId}to fetch it.