Skip to main content

Documents API

Generate and download trade documents.

Generate Documents

Starts document generation for one or more document types. Returns job IDs for polling.

POST /api/v1/shipments/:id/generate

Request Body

{
"document_types": ["COMMERCIAL_INVOICE", "PACKING_LIST"]
}

Available Document Types

TypeDescription
COMMERCIAL_INVOICECommercial invoice
PACKING_LISTPacking list
BILL_OF_LADINGBill of lading
CERTIFICATE_OF_ORIGINCertificate of origin
PROFORMA_INVOICEProforma invoice
DANGEROUS_GOODSDangerous goods declaration
AIR_WAYBILLAir waybill

Response

{
"jobs": [
{
"job_id": "job_doc_a1b2c3d4",
"document_type": "COMMERCIAL_INVOICE",
"status": "processing"
},
{
"job_id": "job_doc_e5f6g7h8",
"document_type": "PACKING_LIST",
"status": "processing"
}
]
}

Get Document Job

GET /api/v1/documents/:jobId

Response (Completed)

{
"job_id": "job_doc_a1b2c3d4",
"document_type": "COMMERCIAL_INVOICE",
"status": "completed",
"download_url": "https://...",
"hash": "sha256:a1b2c3d4e5f6...",
"verification_url": "https://klervex.com/verify/a1b2c3d4e5f6",
"completed_at": "2026-03-31T10:00:05Z"
}

Download Document

GET /api/v1/documents/:jobId/download

Returns the PDF file with Content-Type: application/pdf.

Polling Strategy

Poll every 2 seconds per document job:

async function waitForDocument(jobId) {
for (let i = 0; i < 30; i++) {
const res = await fetch(`/api/v1/documents/${jobId}`, {
headers: { Authorization: `Bearer ${apiKey}` }
});
const job = await res.json();

if (job.status === 'completed') return job;
if (job.status === 'failed') throw new Error(job.error.message);

await new Promise(r => setTimeout(r, 2000));
}
throw new Error('Generation timed out');
}