Freight Forwarder
Publish the full consignment lifecycle to the TWIN sandbox.
The publish-consignment.sh script sends 23 activities to TWIN one at a time, with a 2-minute delay between each: the consignment itself, its documents, and the journey events that mark its progress. As activities are published, TWIN automatically signals the Border Agencies and the Location Operator at the ports on the route.
This assumes you've already followed Get the scripts — you have a terminal open in the unzipped folder and config.env already has your credentials.
(Optional) Speed up the delay between activities
The full lifecycle takes ~46 minutes by default (120s between activities). To speed it up for testing, open config.env (in the same folder) and set SANDBOX_ACTIVITY_DELAY=5:
open -e config.envnano config.envSave and exit: Ctrl+O, Enter, Ctrl+X.
notepad config.envSANDBOX_ACTIVITY_DELAY=5(Optional) Change the route
The consignment travels Calais → Felixstowe by default. Set both the name and the UN/LOCODE of each port in config.env to publish it as a different route — Border Agencies match on the code:
SANDBOX_PORT_OF_EXIT_NAME=Rotterdam
SANDBOX_PORT_OF_EXIT_CODE=NLRTM
SANDBOX_PORT_OF_ENTRY_NAME=Dover
SANDBOX_PORT_OF_ENTRY_CODE=GBDVRCheck who your consignments are shared with
Publishing does not by itself make a consignment readable by anyone else. Who may read it is set up in the TWIN web app, under your organisation's data sharing settings — there is no script for it here.
A Border Agency is entitled to a consignment when one of its legs is in that agency's country, and a Location Operator when it calls at a port the operator manages. So the sharing you set up has to cover the route you are about to publish: with the default Calais → Felixstowe, that means the agencies of FR and GB, and the operators of FRCQF and GBFXT.
If you changed the route in the previous step, check this again before publishing.
Run the script
Still in the same terminal, same folder:
bash freight-forwarder/publish-consignment.shThe script logs each activity as it is published:
Publishing as: did:iota:0x...
Consignment: TESTFF-20260806-171432
Global ID: 6-GB-GB000000000001-20260806-171432
Route: Calais (FRCQF) → Felixstowe (GBFXT)
Activities: 23 — delay between activities: 120s
[1/23] ✓ Create Pre-Notification — TESTFF-20260806-171432
waiting 120s...
[2/23] ✓ Add Event — twin:preNotification
waiting 120s...
[3/23] ✓ Update Pre-Notification — TESTFF-20260806-171432
waiting 120s...
[4/23] ✓ Add Event — twin:carrierBooking
...
[23/23] ✓ Add Event — twin:arrivedAtFinalDestination
Done — 23 activities published
Consignment globalId:
6-GB-GB000000000001-20260806-171432The reference after the prefix is the UTC time the run started, so running the script again publishes a separate consignment rather than revising this one. Run it as many times as you need.
Activity sequence
| # | Type | Name / event code | Triggers |
|---|---|---|---|
| 1 | Create | Pre-Notification | ISN signal → Border Agency |
| 2 | Add | twin:preNotification | — |
| 3 | Update | Pre-Notification | ISN signal → Border Agency |
| 4 | Add | twin:carrierBooking | signal → Location Operator |
| 5–10 | Add | DocumentIssued | — |
| 11 | Add | twin:issuedDocument | — |
| 12 | Update | Despatch | ISN despatch signal → Border Agency |
| 13 | Add | twin:despatched | — |
| 14–15 | Add | DocumentIssued | — |
| 16 | Update | Despatch | ISN despatch signal → Border Agency |
| 17 | Add | DocumentIssued | — |
| 18 | Update | Export Declaration | — |
| 19 | Add | twin:atLocationOfExit | — |
| 20 | Add | twin:leftLocationOfExit | — |
| 21 | Add | twin:atLocationOfEntry | — |
| 22 | Add | twin:leftLocationOfEntry | — |
| 23 | Add | twin:arrivedAtFinalDestination | — |
Activity 4 is the one Location Operators are notified on. They are not notified of consignment updates or document uploads, so a lifecycle without it reaches nobody. The signal only goes out if the operator manages the port of exit or the port of entry you configured.
The globalId printed at the end identifies the consignment.