Attachments and documents
A declaration can carry supporting documents, such as an invoice, a packing list or a certificate of origin. ITS can also render any version of a declaration as the adopted AfCFTA Transit Document.
Attach supporting documents
POST /etd/{serial_no}/attachments
Send the files as multipart/form-data:
| Part | Required | Notes |
|---|---|---|
file | Yes | One document. Repeat the part to send several. |
document_type | No | What kind of document these are, in your own words, such as INVOICE, PACKING_LIST or CERTIFICATE_OF_ORIGIN. It applies to every file in the request. |
curl --fail-with-body --silent --show-error \
--cert "$ITS_CLIENT_CERT" --key "$ITS_CLIENT_KEY" \
--header "Authorization: Bearer $ITS_TOKEN" \
--form "file=@invoice.pdf" \
--form "file=@packing-list.pdf" \
--form "document_type=INVOICE" \
"$ITS_GATEWAY_URL/etd/KEMBATD26081138/attachments"
A successful call answers 201 with the declaration's attachments after the act.
Send the whole set in one request. Each request is one act: it appends one version of the declaration and announces it once to every country the declaration concerns. Twelve pages sent one at a time would make twelve versions and twelve announcements for every other country to receive and acknowledge.
- Who may attach: any country the declaration concerns, not only the departure country, with the
etd:attachpermission. A REC may attach for the members it acts for. - All or nothing: nothing is stored unless every file in the request is accepted.
- Type is checked from the content: ITS detects each file's type from its bytes, not from the header you send. A file whose content contradicts its declared type is refused, and so is a type this deployment does not accept.
- Retries are harmless: a file ITS already holds is identified by its digest and returned rather than stored twice.
- There is no delete: an attachment is evidence. Supersede it by attaching another.
| Status | Meaning |
|---|---|
201 | Stored |
400 | No file sent, or a file was empty (VAL-ETD-037) |
403 | You may see the declaration but not add to it (AUTHZ-ETD-036) |
404 | No such declaration in your scope |
413 | A file is larger than this deployment accepts |
415 | A file is not an accepted type, or is not what it claims to be |
503 | The deployment cannot scan files right now. Not your fault; try again later. |
List the attachments
GET /etd/{serial_no}/attachments
Each entry carries:
| Field | Meaning |
|---|---|
sha256 | The lowercase hex SHA-256 of the file's bytes |
filename | The name the file was uploaded under, for display only |
document_type | The document_type it was attached with |
The same list is inside the signed document, as envelope.attachments, on every read. There is no include=attachments: you already have it.
Download an attachment
GET /etd/{serial_no}/attachments/{attachment_id}/download
The file is streamed through ITS under the same authorisation as every other read, with Cache-Control: private, no-store.
Verify what you receive. Hash the bytes and compare them with the sha256 in envelope.attachments. If they differ, the file is not the one the declaration was signed with.
Print the Transit Document
GET /etd/{serial_no}/pdf
GET /etd/{serial_no}/versions/{version_no}/pdf
Both need etd:read, the same permission as reading the JSON. The response is application/pdf: the adopted AfCFTA Transit Document, two A4 leaflets with 44 numbered boxes, rendered from the version's stored, signed content.
| Query | Values | Default |
|---|---|---|
leaflet | I, II or BOTH | BOTH |
lang | A language tag for the box captions | English |
disposition | attachment or inline | attachment |
as_of | An instant, on the current-version route only | The current version |
leaflet I is the declarant's segment and leaflet II the customs office segment, so each prints alone. An unknown leaflet or lang value is 400 VAL-ETD-058.
disposition changes only the Content-Disposition header. Use inline when you hand the URL to a viewer that renders in place.
curl --fail-with-body --silent --show-error \
--cert "$ITS_CLIENT_CERT" --key "$ITS_CLIENT_KEY" \
--header "Authorization: Bearer $ITS_TOKEN" \
--output KEMBATD26081138.pdf \
"$ITS_GATEWAY_URL/etd/KEMBATD26081138/pdf?leaflet=BOTH"
What the printed document shows
- Boxes 43 and 44 show one country's leg. They carry the office of entry and the office of exit of the last country to have stamped at or before the version you print. To print an earlier leg, print an earlier version.
- Every date is when ITS received a stamp. The captions say
RECORDED BY AfCFTA ITS. They are not the time somebody signed. - No handwritten signature is drawn or imitated. The signature boxes carry the officer and station your administration supplied, with an attestation that ITS sealed the version. It is not the officer's own signature.
- A transit ITS closed itself says so. The closing row on leaflet II is marked, with the words
NOT EVIDENCE OF ARRIVAL. - Captions follow
lang; values never change. A name filed in Arabic prints in Arabic inside an English-captioned form. A right-to-left language right-aligns the fields without reversing the box order.
Caching the PDF
ITS renders the PDF on request and keeps no copy. The same request reproduces the same document later, so keep the copy you were served if you need one.
The PDF's ETag is weak, W/"<content-hash>.<render-revision>.<leaflet>.<language>", and is not the version's content hash. Send it back as If-None-Match to get a 304.
Never send the PDF's ETag as If-Match on an amendment. Take If-Match from GET /etd/{serial_no}, or the amendment is refused with 412.
Someone without an ITS account, such as a declarant, can download the current leaflet through the public route. See Verify and track.