Authentication
D2 is Paltrack's message switch service — it receives structured data from authorised vendors and routes it to the relevant parties on the network. This API is the integration point for that exchange.
Every endpoint accepts either a bearer token or an API key — pick whichever suits your integration, no need to send both. The examples on this page show the Authorization: bearer header for brevity, but an x-api-key header works identically on every endpoint in this guide.
Bearer Token
Request a token using the OAuth 2 Resource Owner Password flow. Tokens are valid for 60 minutes; request a new one before expiry.
POST https://helpdesk.paltrack.co.za/token Content-Type: application/x-www-form-urlencoded grant_type=password&username={your_username}&password={your_password}
The response returns an access_token:
{
"access_token": "eyJ0eXAiOiJKV1QiLC...",
"token_type": "bearer",
"expires_in": 3599
}
Pass the token on every subsequent request:
Authorization: bearer {access_token}
API Key
A simpler alternative to Bearer tokens for server-to-server integrations that don't want to manage token refresh. API keys don't expire on a fixed cycle — they're valid until you revoke them, or until an optional expiry date you set yourself.
x-api-key: {your_api_key}
Getting a key:
- Self-service — log in to Paltrack's client portal (PalPortal) and go to API Keys. Click Generate to issue a new key for your company.
- Via Paltrack support — if you don't have PalPortal access, ask your Paltrack contact to issue one from your company record in Helpdesk.
Each key is tied to a single company (not an individual user), so any of your integrations can share one key. You can view your keys and revoke them any time from the same API Keys screen.
Credential scoping
Both bearer tokens and API keys are scoped to your Paltrack Location Code(s) and Location ID(s) — Depots, Packhouses, and Exporters can only access data linked to their own location codes, and only the data D2's Split rule engine has determined they should receive. This is the same scoping logic D2 Classic (flat files) uses — nothing changes here for vendors migrating from flat files to the API.
Testing
A QA environment is available so you can test your integration before going live:
https://papiqa.paltrack.co.za
Endpoint paths and request/response formats are identical to production — just point your integration at this host instead. For a QA API key, contact your Paltrack representative — QA keys are issued directly rather than through self-service PalPortal. Credential scoping applies in QA exactly as it does in production.
Rate Limiting & Content Type
All clients are limited to 60 requests per minute per IP address. Exceeding this returns HTTP 429. Implement exponential back-off and retry logic in your client.
All requests and responses use JSON only. Set Content-Type: application/json on every POST request.
Submit Dispatch
The tables below cover the fields most integrations need. Several request bodies have deeply nested objects (e.g. Consignments[].Pallets[], Consignments[].Container) with many more optional fields than are practical to list here — for the complete field list on any endpoint, see the Swagger UI.
Submit a truck dispatch (PO file) to D2 for routing to the destination depot. Returns a trackingId for the submission.
Request body — POFileDTO
| Field | Type | Description |
|---|---|---|
| POFileNameREQ | string | Unique file name for this dispatch |
| LocationIdREQ | string | D2 depot ID where pallets were loaded |
| LocationCodeREQ | string | D2 depot code where pallets were loaded |
| BatchNumberREQ | string | Sequence number for this batch file |
| TruckHeaderREQ | object | Truck and load details (see below) |
| ConsignmentsREQ | array | One or more consignment documents (see below) |
| CreatedDateTime | datetime | File creation timestamp — defaults to now |
| Provider | string | Name of your system — defaults to "Paltrack API" |
| Version | string | Version of your application |
| POPreviousFileName | string | Previous file name — only set on re-submissions |
TruckHeader key fields
| Field | Type | Description |
|---|---|---|
| PalletQuantityREQ | int? | Number of pallets on the truck |
| CartonQuantityREQ | int? | Number of cartons on the truck |
| NextTypeREQ | string | DP (depot) or CU (customer) |
| NextCodeREQ | string | Location code the truck is going to next |
| SeasonREQ | string | Season identifier |
| TransactionUserREQ | string | User creating/updating the record |
| TransactionDateTimeREQ | datetime | Date/time of the transaction |
| LoadReference | string | Truck registration or load reference |
| LoadName | string | Load name or trip number |
| Transport | string | Mode of transport — R (rail) or T (truck) |
| LoadType | string | Load type — F (flat-bed) or R (reefer) |
| Temperature | decimal? | Set temperature |
| LoadId | int? | Internal load ID (optional) |
Note: SealNumber is not a TruckHeader field — it belongs to Container, a separate nested object under Consignment.
Consignment key fields
| Field | Type | Description |
|---|---|---|
| DocumentNumber | string | Consignment note / document number |
| Organisation | string | Exporter / organisation code |
| DocumentType | string | Document type code |
| DocumentDate | string | Document date |
| Season | string | Season year (e.g. "2026") |
| Channel | string | Marketing channel |
| ToLocationCode | string | Destination depot code |
| CartonQuantity | int | Number of cartons |
| PalletQuantity | decimal | Number of pallets |
| Pallets | array | Individual pallet records |
TruckHeader, Consignment, and their nested Container/Location/Pallet objects: see Swagger.
Response
{
"trackingId": "550e8400-e29b-41d4-a716-446655440000",
"status": "Received"
}
{
"trackingId": "550e8400-e29b-41d4-a716-446655440000",
"payloadType": "Dispatch",
"errors": [
{ "field": "POFileName", "message": "Required field missing" }
]
}
Submit Intake
Submit a cold-store intake (PI file) to D2. Use this to report pallet arrivals at your depot.
Request body — PIFileDTO
| Field | Type | Description |
|---|---|---|
| PIFileNameREQ | string | Unique file name for this intake |
| LocationCodeREQ | string | Depot code receiving the intake |
| LocationId | string | Paltrack depot ID |
| BatchNumber | string | Batch sequence number |
| CreateDateTime | datetime | File creation timestamp |
| Provider | string | Name of your system |
| Version | string | Version of your application |
| Documents | array | Intake documents (IntakeDocumentDTO[]) |
IntakeDocument key fields
| Field | Type | Description |
|---|---|---|
| DocumentNumber | string | Intake document number |
| Organisation | string | Exporter / organisation code |
| DocumentType | string | Document type |
| DocumentDate | string | Document date |
| Season | string | Season year |
| Channel | string | Marketing channel |
| CartonQuantity | int | Number of cartons |
| PalletQuantity | decimal | Number of pallets |
| FromLocationCode | string | Origin depot code |
| Inspector | string | Inspector identifier |
| InspectionDate | datetime? | Inspection date |
| Temperature | decimal | Temperature reading |
IntakeDocumentDTO has many more optional fields than shown above, including nested Pallet and TransferIn objects — see Swagger for the full schema.
Response shape is identical to Submit Dispatch.
Submit Stock
Submit a full stock snapshot (PS file) to D2. Used to synchronise on-hand pallet records with authorised parties on the network.
Request body — PSFileDTO
| Field | Type | Description |
|---|---|---|
| PSFileNameREQ | string | Unique file name for this stock file |
| LocationCodeREQ | string | Depot code |
| LocationId | string | Paltrack depot ID |
| BatchNumber | string | Batch sequence number |
| CreateDateTime | datetime | File creation timestamp |
| Provider | string | Name of your system |
| Version | string | Version of your application |
| StockRecords | array | Pallet lines (StockRecordDTO[]) |
StockRecord key fields
| Field | Type | Description |
|---|---|---|
| PalletId | string | Paltrack pallet identifier |
| SSCC | string | GS1 SSCC barcode |
| DocumentNumber | string | Associated consignment document |
| LocationCode | string | Current depot code |
| OrganisationCode | string | Exporter code |
| Commodity | string | Commodity code |
| Variety | string | Variety code |
| Pack | string | Pack code |
| Grade | string | Grade code |
| SizeCount | string | Size/count code |
| Mark | string | Brand/mark code |
| CartonQuantity | string | Number of cartons on pallet |
| PalletQuantity | string | Pallet quantity (usually 1) |
| IntakeDate | string | Date pallet was received |
| Temperature | string | Storage temperature |
| PalletStatus | string | Current pallet status code |
StockRecordDTO has many more optional fields than shown above — see Swagger for the full schema.
Response shape is identical to Submit Dispatch.
Submit Mates
Submit a Mates Receipt (MT file) to D2 — the ship discharge record confirming which pallets came off at each port. Use this once a vessel's cargo has been reconciled against the ship's manifest.
Request body — MTFileDTO
| Field | Type | Description |
|---|---|---|
| MTFileNameREQ | string | Unique file name for this Mates submission |
| LocationId | string | Paltrack depot ID |
| LocationCodeREQ | string | Depot code submitting the Mates file |
| BatchNumber | string | Batch sequence number |
| CreatedDateTime | datetime | File creation timestamp |
| Provider | string | Name of your system |
| Version | string | Version of your application |
| ShipHeaderREQ | object | Ship header details (OL record, see below) |
ShipHeader key fields
| Field | Type | Description |
|---|---|---|
| ShipNumberREQ | string | Ship number |
| Organisation | string | Organisation code |
| Season | string | Season identifier |
| Transport | string | Transport type |
| LoadType | string | Ship type |
| LoadName | string | Ship name |
| StartDate | datetime | Start loading date |
| DepartureDate | datetime? | Departure date |
| NextType / NextCode | string | Next location type/code the ship is destined for |
| LoadingLocationREQ | object | Loading port details (ON record, TranType = L) |
| DispatchLocationREQ | array | One or more discharge/destination locations (ON records, TranType = D), each carrying its own pallet records |
Both LoadingLocation and each entry in DispatchLocation share the same shape — the file format lists loading and discharge legs as siblings, not a parent/child pair.
DispatchLocation[].PalletRecords[] key fields — MTPalletRecordDTO
| Field | Type | Description |
|---|---|---|
| PalletIdREQ | string | Pallet ID (typically placed in the SSCC field) |
| SSCCREQ | string | SSCC (18-character) identifier |
| CommodityREQ | string | Commodity code |
| VarietyREQ | string | Variety code |
| PackREQ | string | Pack code |
| GradeREQ | string | Grade code |
| FarmREQ | string | Farm code |
| CartonQuantity | int | Number of cartons — must be greater than zero |
| PalletQuantity | decimal | Pallet quantity — must be greater than zero (see part-pallet rule) |
| Organisation | string | Organisation code |
| ConsignmentNumber | string | Original intake consignment number |
| DestinationLocation | string | Destination location code |
MTShipHeaderDetailDTO, MTTransportLocationDTO and MTPalletRecordDTO have many more optional fields than shown above — see Swagger for the full schema.
Response shape is identical to Submit Dispatch.
Submit Day Instruction
Submit a Day Instruction (DI file) to D2 — a loading instruction for a single order (one ship or truck load). Unlike Dispatch/Intake/Stock, this is an instruction to be actioned, not a completion record.
Request body — DIFileDTO
| Field | Type | Description |
|---|---|---|
| DIFileNameREQ | string | Unique file name for this Day Instruction submission |
| LocationId | string | Paltrack depot ID of the sending depot |
| LocationCodeREQ | string | Depot code of the sending depot |
| BatchNumber | string | Batch sequence number |
| CreateDateTime | datetime | File creation timestamp |
| Provider | string | Name of your system |
| Version | string | Version of your application |
| OrderREQ | object | The loading instruction order (LO record, see below) |
Order key fields — DIOrderDTO
| Field | Type | Description |
|---|---|---|
| LocationCode | string | Sending depot code |
| OrderNumber | string | Unique order number for trucks; blank for ships |
| OrderType | string | V (conventional ship), T (container ship), D (normal truck), Z (container truck) |
| ShipNumber | string | Ship number |
| ShipName | string | Ship name |
| DestinationType | string | PO (ships), DP/CU (depot/customer for trucks) |
| DestinationCode | string | Discharge port (ships) or destination depot/customer code (trucks) |
| Instruction | string | Instruction text |
| OrderStatus | string | Blank for ships, O (open) or C (closed) for trucks |
| Port | string | Port code |
| OrderDetailsREQ | array | One or more loading instruction line items (LD records, see below) |
OrderDetails[] key fields — DIOrderDetailDTO
| Field | Type | Description |
|---|---|---|
| LocationCode | string | Sending depot code |
| DestinationType / DestinationCode | string | Destination port (ships) or depot/customer (trucks) |
| Commodity | string | Commodity code |
| Variety | string | Variety code |
| Pack | string | Pack code |
| Grade | string | Grade code |
| Farm | string | Farm code |
| TargetMarket | string | Target market code |
| UnitType | string | P (pallet-level) or C (carton-level) instruction |
| InstructionQuantity | int? | Quantity to be shipped |
| ShippedQuantity | int? | Quantity already shipped |
| PalletId | string | Pallet SSCC, where the instruction targets a specific pallet |
| Priority | string | Ascending priority order (0–9) in which the order is loaded |
DIOrderDTO and DIOrderDetailDTO have more optional fields than shown above — see Swagger for the full schema.
PalletQuantity = 1) that applies to Dispatch/Intake/Stock/Mates does not apply here.
Response shape is identical to Submit Dispatch.
Submit Load Instruction
Submit a Loading Instruction (LI file) to D2 — a ship or truck loading instruction. A single submission can cover multiple headers (e.g. multiple ships/trucks or line positions), each with its own destination.
Request body — LIFileDTO
| Field | Type | Description |
|---|---|---|
| LIFileNameREQ | string | Unique file name for this Loading Instruction submission |
| LocationId | string | Paltrack depot ID where the instructions originate |
| LocationCodeREQ | string | Depot code where the instructions originate |
| BatchNumber | string | Batch sequence number |
| CreateDateTime | datetime | File creation timestamp |
| Provider | string | Name of your system |
| Version | string | Version of your application |
| InstructionHeadersREQ | array | One or more instruction headers (LH records, see below) |
InstructionHeaders[] key fields — LIInstructionHeaderDTO
| Field | Type | Description |
|---|---|---|
| LocationCode | string | Sending depot code |
| OrderType | string | V (conventional ship), T (container ship), D (normal truck), Z (container truck) |
| OrderNumber | string | Blank for ships, unique identifier for trucks |
| ShipNumber / ShipName | string | Ship identifiers |
| DestinationType / DestinationCode | string | Discharge port (ships) or destination depot/customer (trucks) |
| OrderStatus | string | O (open) or C (closed); blank for ships |
| Channel | string | L (local) or E (export) |
| Commodity / Variety / Pack / Grade | string | Product classification codes |
| InstructionQuantity | int? | Quantity of units to be shipped |
| InstructionDetailsREQ | array | One or more instruction line items (LD records, see below) — at least one header must carry at least one detail line |
InstructionHeaders[].InstructionDetails[] key fields — LIInstructionDetailDTO
| Field | Type | Description |
|---|---|---|
| OrderNumber / ShipNumber | string | Matches the parent header |
| LocationCode | string | Sending depot code |
| DestinationType / DestinationCode | string | Destination port/depot/customer |
| Commodity / Variety / Pack / Grade | string | Product classification codes |
| InstructionQuantity | int? | Quantity of units to be shipped |
| InstructionShipped | int? | Quantity already shipped |
| Pool | string | Pool code |
| Warehouse | string | Warehouse code |
| Gtin | string | GTIN (Global Trade Item Number) |
| AgreementCode | string | eCert agreement code |
LIInstructionHeaderDTO and LIInstructionDetailDTO have more optional fields than shown above — see Swagger for the full schema.
Response shape is identical to Submit Dispatch.
Find Payloads
Returns all payloads queued for your depot(s) in D2. No request body or query parameters.
Response
[
{
"fileType": "PO",
"fileName": "PO_PACKHOUSE_20260630_001.txt",
"sourceDepot": "PACKHOUSE",
"destinationDepot": "COLDSTORE",
"exporterLocnId": "P01",
"documentNumber": "DOC001",
"season": "2026",
"statsDetailId": 12345
}
]
| Field | Description |
|---|---|
| fileType | Payload type: PO, PI, PS, MT, DI, LI, etc. |
| fileName | Original file name of the transmission |
| sourceDepot | Depot the payload originated from |
| destinationDepot | Intended recipient depot |
| exporterLocnId | Paltrack exporter location ID |
| documentNumber | Document number(s) covered by this payload |
| season | Season year |
| statsDetailId | Key used in GetPayload and PayloadReceived |
MT, one row is queued per discharge port on the ship; destinationDepot is that port and is informational only (Mates distribution is driven by Organisation Code, not destination), and documentNumber is left blank (a single Mates file can cover thousands of pallets sharing one original intake consignment number). For DI, one row is queued per file; documentNumber is the order number (the closest equivalent to a document ID). For LI, one row is queued per instruction header; destinationDepot/documentNumber reflect that header's own destination/order number.
Get Payload
Downloads the full data payload for a specific D2 transmission. Pass the PayLoadInfo object returned by FindPayloads as the request body.
Request body — PayLoadInfo
{
"fileType": "PO",
"fileName": "PO_PACKHOUSE_20260630_001.txt",
"sourceDepot": "PACKHOUSE",
"destinationDepot": "COLDSTORE",
"exporterLocnId": "P01",
"documentNumber": "DOC001",
"season": "2026",
"statsDetailId": 12345
}
Response is the full JSON payload for the requested file. After processing it successfully, call PayloadReceived to mark it as consumed.
Payload Received
Acknowledges successful receipt and processing of a D2 payload. Marks the transmission as complete in D2 and removes it from the FindPayloads queue.
Request body is the same PayLoadInfo object used in GetPayload. At minimum, statsDetailId must be set.
{ "result": true }
Validation
Submitted payloads (Submit Dispatch / Submit Intake / Submit Stock / Submit Mates / Submit Day Instruction / Submit Load Instruction) go through two validation layers, in order. Which layer rejects your payload determines the shape of the error response.
Layer 1 — required fields
Fields marked REQ in the endpoint tables above (e.g. POFileName, TruckHeader, Consignments) are checked before your payload is looked at further. If one is missing, you get back a field-level error shape rather than the errors[] shape used elsewhere in this guide:
{
"model.POFileName": [ "The POFileName field is required." ],
"model.TruckHeader": [ "The TruckHeader field is required." ]
}
This guide's tables cover the common fields only — nested objects (Consignment, TruckHeader, Pallet, etc.) have their own required fields too. The Swagger UI schema reflects all of these, since it's generated directly from the same model.
Layer 2 — business-rule validation
Once required fields pass, Paltrack runs payload-specific business rules and returns errors in the errors[] shape shown earlier in this guide.
| Code | Meaning |
|---|---|
INVALID_JSON | Payload body isn't valid JSON |
EMPTY_FIELD | Payload body was empty |
INVALID_VALUE | A value failed validation — e.g. Consignments/Documents/StockRecords array is missing or empty, or payloadType is unsupported |
MISSING_FIELD | A field required by business logic (not caught by Layer 1) is missing, e.g. PalletQuantity on a pallet row |
PART_PALLET | See below — sum of PalletQuantity for a pallet doesn't equal 1 |
DUPLICATE_PAYLOAD | Reserved for future use — not yet triggered by any current validation rule |
MISSING_DEPENDENCY | Reserved for future use — not yet triggered by any current validation rule |
SSCC/PalletId, the sum of PalletQuantity across all its rows must equal exactly 1 (0.001 tolerance). This applies to Consignments[].Pallets[] (Dispatch), Documents[].Pallets[] (Intake), StockRecords[] (Stock), and ShipHeader.DispatchLocation[].PalletRecords[] (Mates) alike. Submitting a pallet split across partial quantities will be rejected. Day Instruction and Load Instruction are instructions to be actioned rather than completion records, so this rule does not apply to either.
Integration Flow
GET /v1/FindPayloads
— list pending payloads for your depot(s)
POST /v1/GetPayload
— download the payload data
POST /v1/PayloadReceived
— acknowledge receipt; payload removed from queue
POST /v2/SubmitDispatch
— send a truck dispatch
POST /v2/SubmitIntake
— send a cold-store intake
POST /v2/SubmitStock
— send a stock snapshot
POST /v2/SubmitMates
— send a Mates Receipt (ship discharge)
POST /v2/SubmitDayInstruction
— send a Day Instruction (order-level loading instruction)
POST /v2/SubmitLoadInstruction
— send a Loading Instruction (ship/truck loading instruction)
trackingId returned by each Submit call. Include it when contacting Paltrack support about a specific submission.
Error Codes
| Status | Meaning | What to do |
|---|---|---|
| 200 | Success | — |
| 400 | Validation failed | Layer 1 or Layer 2 — see Validation |
| 401 | Unauthorised | Bearer token or API key is missing, expired, or invalid — re-authenticate |
| 409 | Reserved | Reserved for a future duplicate-submission check — not currently returned |
| 429 | Rate limit exceeded | Back off and retry — max 60 req/min per IP |
| 500 | Server error | Contact Paltrack support with your trackingId |