Two objects:
  • file: bytes you uploaded or the implementer generated. It is carrier-agnostic, like Stripe Files.
  • document_upload: a submission of one or more files to a carrier as trade documents (commercial invoice, certificate of origin, licence), also known as paperless trade, ETD, or PLT.
Splitting them means a client uploads an invoice once and can submit it to several carriers, retry a failed submission without re-uploading, and audit exactly which bytes each carrier received. The diagram below shows how the two objects relate: one file can be cited by many submissions, and each submission belongs to one connection and, after the label, one shipment.

1. The file object

purpose is one of customs_document, dangerous_goods_declaration, label (generated), manifest (generated), signature_image, proof_of_delivery, logo (printed on labels or invoices where carriers allow it), or other.

Upload

The form fields are file (binary, required), purpose (required), and user_metadata[key]. The maximum size is 10 MB. Allowed types per purpose: customs_document takes PDF, PNG, JPG and TIFF, and logo takes PNG and SVG. There is also a JSON alternative for agents and serverless clients that cannot do multipart easily:
Other file endpoints: GET /v1/files/{id}, GET /v1/files/{id}/contents (streams bytes), GET /v1/files?purpose=..., and DELETE /v1/files/{id}. Deletion is refused (409) while a pending document_upload references the file. accepted, partially_accepted and rejected are terminal.

2. The document_upload object

3. Submit documents

stage is derived: if shipment or tracking_number is present, it is post_shipment, and otherwise pre_shipment. This is how the implementer derives stage and resolves the connection from the request parameters. A post-shipment submission against a shipment the implementer created looks like this. Errors: option_unsupported (the carrier or corridor does not accept paperless documents, so print and attach instead), document_type_unsupported, file_too_large_for_carrier (carrier limits are often lower than 10 MB), shipment_not_eligible (already delivered, or outside the upload window).

Pre-shipment flow

When customs_declaration.documents[] references a document_upload, the implementer resolves its carrier references. A reference made under a different connection returns 400 parameter_invalid. The same flow as a sequence: the document reaches the carrier first, and the purchase cites it by reference.

Generated documents

If customs_declaration.paperless_trade is true and neither order.invoice.file nor a commercial_invoice document reference is provided, implementers SHOULD generate a commercial invoice from order (number, date, charges), handling_units[].items[] (lines) and customs_declaration (parties, incoterm, certification), submit it, and expose it as shipment.documents[type=commercial_invoice] and a document_upload with system_metadata.generated = true. The diagram shows when an invoice is generated and which shipment data feeds it.

4. Retrieve, list, update

Expandable: shipment, documents.file.

5. Events

file.created, document_upload.created, document_upload.accepted, document_upload.partially_accepted, document_upload.rejected.