Electronic Bill of Lading
Introduction
In this article we describe the CargoX Electronic Bill of Lading (eBL) API endpoints for integrators. In short, these endpoints (together with more general endpoints described here), integrators can view, transfer and execute various actions on eBL documents, as well as subscribe to eBL-related events via webhooks (eBL received, surrender for delivery accepted, etc).
Postman collection
Here is a JSON collection file. You can easily import it into Postman via File->Import command.
Postman will import the collection and you can try it after setting up OAuth for authentication.
Important
Third-party system requires the
client_idandclient_secretbefore using this postman examples. Please insertclient_idandclient_secretinto collection variables as shown here.
Example use case
In the following sections we will go through a single use case and through it illustrate the various eBL-related endpoints.
In the scenario we assume that your company has been registered as a third-party app and has access to the CargoX integration API.
The use case will illustrate the following operations:
- Subscribing to eBL-related events on the platform
- Sending a copy of an eBL
- Executing an eBL action: requesting surrender for delivery
- Fetching a single eBL or a list of eBLs
- Displaying or downloading an eBL
Subscribing to eBL-related events
You can subscribe to various platform events via our rules API. Each rule represents a specific event type (e.g., eBL updated) and is connected to one or more rule actions, which represent how to notify you about the event (e.g., via POST request to your webhook address).
Details about the notifications and rules endpoints can be found in our CargoX API v3 swagger.
Here we show you how to create a rule to be notified about every eBL-related update (including when an eBL is issued to you) by a POST request from us to the address https://my-custom-webhook-url/ together with a custom header key-value pair my-key=my-value:
{
"name": "My eBL rule",
"event": "ebl_update",
"for_company_id": "b32d525b-ee3c-4388-af4e-e60664119d8f",
"create_actions": [
{
"type": "post_webhook",
"data": ["https://my-custom-webhook-url/"],
"headers": [
{
"name": "my-key",
"value": "my-value"
}
]
}
],
"enabled": true
}
Note that for eBL, we currently support only the post_webhook action type.
Here is how the payload from us will look like when an eBL has been issued to your company:
{
"data": {
"event": "ebl_possession_transfered",
"ebl_id": "f871c644-1d17-4547-bdd4-e90d5584a8ac",
"ebl_reference": "REF-ykn-b",
"payload": null
},
"third_party_customer_id": null,
"event": "ebl_updated"
}
The ebl_id field in the data is the CargoX identifier for this resource. The ebl_reference is the external reference for this eBL and is defined by the issuer. You will use the ebl_id to refer to this particular eBL when using our eBL-related endpoints. Internally, several eBL document instances can refer to the same eBL (in terms of its reference), for example one original and one copy.
In the example above the payload field is empty, however, for certain events (ebl_amend_response, ebl_surrender_for_delivery_response and ebl_switch_to_paper_response) we will provide extra information. For example:
{
"data": {
"event": "ebl_surrender_for_delivery_response",
"ebl_id": "9792d47a-593c-4ba3-ab87-df98df1df78d",
"ebl_reference": "REF-ykn-b",
"payload": {
"decision": "reject",
"message": "Reject reason message"
}
},
"third_party_customer_id": null,
"event": "ebl_updated"
}
Send an eBL copy
You can send copies of eBLs to other companies. To do so, use the POST /api/integrators/ebl/v1/send-as-a-copy/ endpoint.
Example payload:
{
"eblId": "9792d47a-593c-4ba3-ab87-df98df1df78d",
"recipientInbox": "c3a34e2b-fc2e-4755-ab7c-8705be84524b"
}
You can address other companies via their inbox identifier, which you can find for companies that are among your contacts on the CargoX platform. See the contacts-related API at API v3.
The receiving company can then view the copy via the CargoX app or via the provided integrations API endpoints. They cannot do any action on their copy other than viewing it with the GET /api/integrators/ebl/v1/:ebl_id/preview/ or GET /api/integrators/ebl/v1/:ebl_id/download/ endpoints.
Execute an eBL action
Depending on the role you have in the lifecycle of the eBL (issuer, consignor, consignee), you can do certain actions on that eBL. For example, if you are stated as a consignee on the eBL, you can request surrender for delivery. This is an important action that needs to be recorded on the blockchain, which is why this action needs to be signed by the requestor using their private blockchain key.
1. Step: Call POST /api/integrators/ebl/v1/signing-data/ to start the desired action
For example, if we want to request surrender for delivery, the payload will look something like:
{
"operation": "REQUEST_SURRENDER_FOR_DELIVERY",
"eblId": "9792d47a-593c-4ba3-ab87-df98df1df78d",
"ethAddress": "0xf2Cc7cFF0588ae4cA23Ae91647485Fe9b0F691C9" // <-- The signing user's ethereum address
}
Our platform will return a payload that looks like this:
{
"eblId": "9792d47a-593c-4ba3-ab87-df98df1df78d",
"hash": "0x090980d9bf62fe7c3d156f8a690dbb3d62344e9558ee8571fceefd5421fc6e3f",
"relayNonce": 6,
"recipient": "0x746F5BB481c0bb3c423293A1D358a869e621dDB1",
"relayedFor": "0xf2Cc7cFF0588ae4cA23Ae91647485Fe9b0F691C9",
"transactionData": "0x179d95c00000000000000000000000000000000022df383e547f4f4c86575e209a17162d1f27829608d851ccd11ecbaa050e2d4a5d6873e0963de4de70fa71be4bd5a5e40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e185e0d234182135894ca5dff438886cf1ad71cd000000000000000000000000b8587062ab2d70c18dd4091fc29a792efb3b70e8000000000000000000000000e185e0d234182135894ca5dff438886cf1ad71cd",
"signature": null,
"operation": "REQUEST_SURRENDER_FOR_DELIVERY",
"signedForId": null
}
You will need this payload in the next step to continue with executing the desired eBL action.
2. Step: Sign the transaction hash
All eBL actions are essentially transactions on a public blockchain, which is why in the second step of this process you need sign the transaction with your private blockchain key. This can be done using your preferred programming language and library.
Here we provide an example using ethers and Typescript.
import { ethers } from 'ethers';
// ...
// Omitted: calling our `signing-data` endpoint and storing the response payload into `payload`
// ...
const privateKey = '<your-private-key>';
const wallet = new ethers.Wallet(privateKey);
// The hash field sent in the response of the previous step
const txHash = payload.hash;
const signedMessage = await wallet.signMessage(ethers.getBytes(txHash));
At this point you will need to submit the signedMessage back to us in the next step.
3. Step: Submit signed data and execute the eBL action by calling POST /api/integrators/ebl/v1/submit-signed-data/
The payload for this endpoint is the response of the endpoint from Step 1 in combination of the signedMessage from Step 2:
{
"eblId": "9792d47a-593c-4ba3-ab87-df98df1df78d",
"hash": "0x090980d9bf62fe7c3d156f8a690dbb3d62344e9558ee8571fceefd5421fc6e3f",
"relayNonce": 6,
"recipient": "0x746F5BB481c0bb3c423293A1D358a869e621dDB1",
"relayedFor": "0xf2Cc7cFF0588ae4cA23Ae91647485Fe9b0F691C9",
"transactionData": "0x179d95c00000000000000000000000000000000022df383e547f4f4c86575e209a17162d1f27829608d851ccd11ecbaa050e2d4a5d6873e0963de4de70fa71be4bd5a5e40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e185e0d234182135894ca5dff438886cf1ad71cd000000000000000000000000b8587062ab2d70c18dd4091fc29a792efb3b70e8000000000000000000000000e185e0d234182135894ca5dff438886cf1ad71cd",
"signature": "the-signed-message-from-step-2", // <-- the signed message from Step 2
"operation": "REQUEST_SURRENDER_FOR_DELIVERY",
"signedForId": null
}
After POST-ing this payload several things will happen:
- The action will be executed on the blockchain,
- The eBL will transition to a new state:
SURRENDER_FOR_DELIVERY_REQUESTED - The SURRENDEREE party will get the possession of the eBL
Transferring possession
When transferring possession of an eBL to another company, the first step of the process looks a bit differently, since you will also need to provide the recipient's inbox_id. See the example below:
{
"operation": "TRANSFER_POSSESSION",
"eblId": "9792d47a-593c-4ba3-ab87-df98df1df78d",
"ethAddress": "0xf2Cc7cFF0588ae4cA23Ae91647485Fe9b0F691C9",
"recipientInbox": "c3a34e2b-fc2e-4755-ab7c-8705be84524b" // <-- recipient company's inbox identifier
}
The rest of the process is exactly the same as in the REQUEST_SURRENDER_FOR_DELIVERY example above.
Fetch eBL data
We offer two endpoints for fetching eBL data. One for fetching a single eBL via its ebl_id and one for fetching a list of eBLs (and copies) to which the calling company has access.
As mentioned in the eBL events section, the subscribed company will receive the related ebl_id in the event payload. Using this id, they can fetch that particular eBL's data.
Fetch a single eBL
To fetch a single eBL's data, you can call GET /api/integrators/ebl/v1/:ebl_id and receive a payload like below:
{
"endorsementType": "TO",
"state": "ISSUED",
"titleId": "d41a68fb-4781-433b-810a-8d42d95171bb",
"possessionId": "c3a34e2b-fc2e-4755-ab7c-8705be84524b",
"parties": [
{
"type": "ISSUER",
"id": "7d7945f6-419a-4434-bf71-7451fd46804a",
"inboxId": "94fbe3b5-a612-4e26-bd67-354d409cda6c",
"contactEmail": null
},
{
"type": "SURRENDEREE",
"id": "db884cb6-716e-4a7c-bdb6-63ee92e0c642",
"inboxId": "94fbe3b5-a612-4e26-bd67-354d409cda6c",
"contactEmail": null
},
{
"type": "CONSIGNOR",
"id": "2f86ceb0-523e-4ba0-b99f-2cfb75e62425",
"inboxId": "d41a68fb-4781-433b-810a-8d42d95171bb",
"contactEmail": null
},
{
"type": "CONSIGNEE",
"id": "e3e77266-8717-408b-897b-176e548a8d7e",
"inboxId": null,
"contactEmail": null
}
],
"id": "1ff56cf3-900f-45c4-b349-ddf6899e2bd2",
"content": {
"issueTo": {
"legalName": "Local CargoX",
"partyCodes": [
{
"partyCode": "b32d525b-ee3c-4388-af4e-e60664119d8f",
"codeListName": "CargoX",
"codeListProvider": "EPUI"
}
],
"taxReference": "SI343444",
"sendToPlatform": "CARX",
"registrationNumber": "REG 1233",
"locationOfRegistration": "SI"
},
"document": {
"isToOrder": false,
"documentParties": [
{
"party": {
"partyName": "Consignee inc"
},
"partyFunction": "CN",
"isToBeNotified": false
}
],
"transportDocumentReference": "REF-3vn-s"
},
"eBLVisualisationByCarrier": {
"name": "ebl.pdf",
"content": "..."
}
},
"portOfDischarge": null,
"portOfLoading": null,
"vesselName": null,
"voyageNumber": null,
"reference": "REF-3vn-s",
"eblCopyId": null
}
Fetch a list of eBLs
The other option is to fetch a list of eBLs by calling GET /api/integrators/ebl/v1/list, where you will receive the eBLs to which your company has access to. You have access to eBLs that were issued or transferred to you.
If the eBL is just a copy of another eBL, the field eblCopyId will be non-null and will contain the original eBL id.
Fetch eBL PDF representation
We provide two endpoints for accessing an eBL's PDF representation.
- Use
GET /api/integrators/ebl/v1/:ebl_id/preview/for displaying in a UI. - Use
GET /api/integrators/ebl/v1/:ebl_id/download/for downloading the eBL PDF representation.
For details about the CargoX eBL API please refer to our Open API schema definition.