TradeLink Integration Guide for Liquidity Providers
This guide provides a comprehensive walkthrough for Liquidity Providers (LPs) to integrate with the Tradelink Network. By integrating with Tradelink, LPs can provide liquidity to clients leveraging Ledger's robust collateral management system.
1. Overview
Ledger Tradelink is a collateral management and off-exchange trading solution. It enables financial institutions, including Liquidity Providers, Asset Managers, and Custodians, to manage and monitor collateral, handle pledges, and settle transactions securely via APIs. The core advantage is that physical transfer of assets isn't always necessary; instead, HSM cryptographic proofs verify ownership of pledged assets.
In this setup, the Custodian is the one controlling the Ledger Enterprise workspace and matching, via dedicated Tradelink accounts, Asset Managers with Liquidity Providers. Asset Managers and Liquidity providers will then connect to the account either via Personal Security Device (PSD) for the Asset Manager or via API for the Liquidity Provider.
As a Liquidity Provider on Tradelink, your primary roles will involve:
Accepting or Rejecting Pledge Requests: Asset Managers will pledge collateral to you.
Initiating Settlement Requests: To settle trades and manage payables/receivables.
2. Getting Started
Follow these initial steps to kick off your integration:
Step 1: Engagement with Ledger's Technical Account Team
Schedule a meeting with Ledger's Technical Account team. They will provide a detailed overview of the Tradelink integration process, answer your specific questions, and discuss your requirements.
This team then support you in your integration by acting as the third party who will be able to help you approve, create and reject requests, guiding you to be fully operational on Tradelink.
Step 2: Familiarize Yourself with Documentation
Tradelink Exchange/LP Integration Overview: https://help.vault.ledger.com/developer-portal/content/tradelink/exchange/ (While titled for "Exchange", the concepts for LPs are the same).
Ledger Enterprise API Documentation: https://ledger-enterprise-api-portal.redoc.ly/openapi/le_api/overview/ This is your primary technical reference for building the API integration.
3. Core Workflows
Understanding the pledge and settlement flows is key to a successful integration.
A. Approving Pledges
Pledge requests are initiated by Asset Managers who wish to use their collateral (held by a Custodian on Tradelink) to secure a line of credit from you.
Pledge Initiation: An Asset Manager creates and approves a pledge request via the Tradelink UI or API, specifying the assets and amount they intend to pledge to you.
Notification to LP: Your system will receive the pledge request, typically via a registered Webhook OR by polling our requests endpoint.
Webhook Implementation: You'll need to expose an endpoint that Tradelink can call.
Polling: You would call out GET/requests API endpoint and filter for any requests.
headers = {
'Authorization': f'Bearer {access_token}',
'X-Ledger-Workspace': workspace,
'Content-Type': 'application/json',}
data = {"all": {"webhook": {"secret": "secret", "url": "test_url"}}}
# Using Requests endpoint to check status of anything that is pending approval
response = requests.delete(f'{vault_url}/notifications/configuration', headers=headers, json=data)
# Check the status code of the response
if response.status_code == 200:
response_json = response.json()
print(json.dumps(response_json, indent=4)) # Pretty-print the JSON response
headers = response.headers
print(headers)
else:
print(f"Request failed with status code {response.status_code}")
print(f"Request failed with status code {response.text}")
Authentication: If you haven’t already setup authentication methods, please follow the steps at this page to do so.
Get the Pledge Request: After you have authenticated, you will need to confirm that you agree with the pledge details by hitting the GET/pledges/{id} endpoint. You will have retrieved this id from the webhook that was sent. This will return the following.
{
"edges": [
{
"cursor": 0,
"node": {
"account_id": 1,
"amount": 0,
"asset_manager": {
"approver_group_id": 33,
"code": "OOF",
"id": "b81fd631-dbee-4aff-93ce-e6acf1ed994e",
"name": "OneOf",
"role": "ASSET_MANAGER",
"whitelist_id": 13
},
"custodian": {
"code": "SCH",
"id": "b2015189-0657-4e6d-89ba-fae58300f54b",
"name": "Standard Chartered",
"role": "CUSTODIAN"
},
"exchange": {
"approver_group_id": 32,
"code": "BIN",
"id": "2e3f8b71-7f25-4c3d-bee2-5a1df58fd8b1",
"name": "Binance",
"role": "EXCHANGE",
"whitelist_id": 12
},
"id": "270f6d5f-9b43-497c-badf-c8d0c01df5b6",
"pending": 0,
"pledge_subaccount_id": 2,
"state": "PLEDGE_READY"
}
},
{
"cursor": 1,
"node": {
"account_id": 4,
"amount": 0,
"asset_manager": {
"approver_group_id": 33,
"code": "OOF",
"id": "b81fd631-dbee-4aff-93ce-e6acf1ed994e",
"name": "OneOf",
"role": "ASSET_MANAGER",
"whitelist_id": 13
},
"custodian": {
"code": "SCH",
"id": "b2015189-0657-4e6d-89ba-fae58300f54b",
"name": "Standard Chartered",
"role": "CUSTODIAN"
},
"exchange": {
"approver_group_id": 32,
"code": "BIN",
"id": "2e3f8b71-7f25-4c3d-bee2-5a1df58fd8b1",
"name": "Binance",
"role": "EXCHANGE",
"whitelist_id": 12
},
"id": "5671e1be-c455-405d-9d4f-bd2caa68df0f",
"pending": 51600390280912259497,
"pledge_subaccount_id": 5,
"state": "PLEDGE_INCREMENT_PENDING_APPROVAL"
}
}
],
"page_info": {
"count": 2,
"has_next_page": false
}
}
LP Review: You review the pledge request based on your own internal review process. This may involve internal automated checks based on risk appetite, available credit lines etc.
Get the request details: Now you need to approve the request, to do so, hit the GET/requests to retrieve the request id. There are several filters that can be used on your requests, but we recommend using the pending approval filter so your request would look something like {{GATEWAY_ADDRESS}}/requests?status=PENDING_APPROVAL
The response will look like this:
{
"edges": [
{
"cursor": 0,
"node": {
"created_by": null,
"created_on": "2025-05-29T13:26:42.685145+00:00",
"expires_at": "2025-06-05T13:26:42.685100+00:00",
"id": 88,
"status": "PENDING_APPROVAL",
"target_id": 10,
"target_type": "PLEDGE_INCREMENT",
"type": "CREATE_PLEDGE_INCREMENT",
"used_admin_group": null
}
}
],
"page_info": {
"count": 1,
"has_next_page": false
}
}
Get the challenge: Now hit the GET/requests/{{REQ_ID}}/challenge endpoint. In our example, the REQ_ID would be “88” as seen in the response from the previous step. You will get a simple response similar to the below:
{
"challenge": "eyJhbnRpcmVwbGF5IjoiRUZBOERBN0UzRUJFN0ZBODQ5RUMxOTQ0NzQ1NDI3MThGODBFNUIzNjU2MkRCRDVBQzg2MDAzMUI2Q0NFMEE1QiIsImRhdGEiOnsiYWNjb3VudF9uYW1lIjoiVEwtMDAwMS1VU0QtT09GLVNDSCIsImFtb3VudCI6IjUxNjAwMzkwMjgwOTEyMjU5NDk3IiwiY29udHJhY3RfYWRkcmVzcyI6IjB4YmRDN2MwODU5MkVlNGFhNTFEMDZDMjdFZTIzRDUwODdENjVhRGJjRCIsImN1cnJlbmN5IjoiZXRoZXJldW0iLCJleGNoYW5nZSI6IkJpbmFuY2UiLCJ0aW1lc3RhbXAiOiIyMDI1LTA1LTI5VDEzOjI2OjQyLjU2NzA2NSIsInRvdGFsX3BsZWRnZSI6IjUxNjAwMzkwMjgwOTEyMjU5NDk3In0sInR5cGUiOiJQTEVER0VfUkVRVUVTVF9BUFBST1ZBTCJ9",
"id": 88
File setup: In order to sign the challenge, you will need a .ts file that contains something similar to the following code snippet.
import * as crypto from 'crypto';
import * as jwt from 'jsonwebtoken';
// // Data to be signed
const dataToSign = "eyJhbnRpcmVwbGF5IjoiRUZBOERBN0UzRUJFN0ZBODQ5RUMxOTQ0NzQ1NDI3MThGODBFNUIzNjU2MkRCRDVBQzg2MDAzMUI2Q0NFMEE1QiIsImRhdGEiOnsiYWNjb3VudF9uYW1lIjoiVEwtMDAwMS1VU0QtT09GLVNDSCIsImFtb3VudCI6IjUxNjAwMzkwMjgwOTEyMjU5NDk3IiwiY29udHJhY3RfYWRkcmVzcyI6IjB4YmRDN2MwODU5MkVlNGFhNTFEMDZDMjdFZTIzRDUwODdENjVhRGJjRCIsImN1cnJlbmN5IjoiZXRoZXJldW0iLCJleGNoYW5nZSI6IkJpbmFuY2UiLCJ0aW1lc3RhbXAiOiIyMDI1LTA1LTI5VDEzOjI2OjQyLjU2NzA2NSIsInRvdGFsX3BsZWRnZSI6IjUxNjAwMzkwMjgwOTEyMjU5NDk3In0sInR5cGUiOiJQTEVER0VfUkVRVUVTVF9BUFBST1ZBTCJ9"
// Json to be sign
const decodedString = atob(dataToSign);
const jsonObject = JSON.parse(decodedString);
console.log("----- Json to be signed ----")
console.log(jsonObject);
console.log("----------------------------")
// Load the private key Minivault/Vault-qa
const pkey = `-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIKDf41jzAH2DK22AQLUiQQpYWp7x5CQ6vFToReV+YnHQoAoGCCqGSM49AwEHoUQDQgAEEDlOyOtJz/ytrtUbwxC8Yavw5IiOv65u+DXYhPSkLDpImvfZGqubknFCB9SJ+KxcY4tH38e9eQxaXeZe3InQ1g==\n-----END EC PRIVATE KEY-----`
// PPR1 private Key
//const pkey = `-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIHTnKHwz9sxzOJPUMqwZlZTdJXjcxIuVk0OjDKx2c2XpoAoGCCqGSM49\nAwEHoUQDQgAEFsX8z0mwv923fC30Sg3CUXnEQaCOgM1zwRNc0pm0jUYxpo4JFkiE\nMfPDZPYRdjn9M2PdIpZGyFcw5lJP2Cuabw==\n-----END EC PRIVATE KEY-----`
const privateKey = crypto.createPrivateKey({
key: pkey,
format: 'pem'
});
const privateKeyPem = privateKey.export({ format: 'pem', type: 'sec1' });
console.log('\nLoaded Private Key (PEM/SEC1):\n', privateKeyPem);
// Sign the data using the private key
const decodedData = Buffer.from(dataToSign, 'base64').toString('hex');
const jws = jwt.sign(Buffer.from(decodedData, 'hex'), privateKeyPem, {
algorithm: 'ES256',
header: {
alg: 'ES256',
typ: 'JWT'
}
});
console.log("----- JWS Token ----")
console.log(jws);
console.log("--------------------")
The data to sign is the challenge that you retrieved from the previous step.
The private key is the private key of the relevant API operator that you have set up.
Sign Challenge: You will then need to run a command that signs the challenge and returns the JWS token you require to approve the pledge request. The command would look something like this - npx ts-node {{file_name}}.ts. This will return the JSON that needs to be signed. It will look like this:
----- Json to be signed ----
{
antireplay: 'EFA8DA7E3EBE7FA849EC194474542718F80E5B36562DBD5AC860031B6CCE0A5B',
data: {
account_name: 'TL-0001-USD-OOF-SCH',
amount: '51600390280912259497',
contract_address: '0xbdC7c08592Ee4aa51D06C27Ee23D5087D65aDbcD',
currency: 'ethereum',
exchange: 'Binance',
timestamp: '2025-05-29T13:26:42.567065',
total_pledge: '51600390280912259497'
},
type: 'PLEDGE_REQUEST_APPROVAL'
}
----------------------------
Loaded Private Key (PEM/SEC1):
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIKDf41jzAH2DK22AQLUiQQpYWp7x5CQ6vFToReV+YnHQoAoGCCqGSM49
AwEHoUQDQgAEEDlOyOtJz/ytrtUbwxC8Yavw5IiOv65u+DXYhPSkLDpImvfZGqub
knFCB9SJ+KxcY4tH38e9eQxaXeZe3InQ1g==
-----END EC PRIVATE KEY-----
----- JWS Token ----
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhbnRpcmVwbGF5IjoiRUZBOERBN0UzRUJFN0ZBODQ5RUMxOTQ0NzQ1NDI3MThGODBFNUIzNjU2MkRCRDVBQzg2MDAzMUI2Q0NFMEE1QiIsImRhdGEiOnsiYWNjb3VudF9uYW1lIjoiVEwtMDAwMS1VU0QtT09GLVNDSCIsImFtb3VudCI6IjUxNjAwMzkwMjgwOTEyMjU5NDk3IiwiY29udHJhY3RfYWRkcmVzcyI6IjB4YmRDN2MwODU5MkVlNGFhNTFEMDZDMjdFZTIzRDUwODdENjVhRGJjRCIsImN1cnJlbmN5IjoiZXRoZXJldW0iLCJleGNoYW5nZSI6IkJpbmFuY2UiLCJ0aW1lc3RhbXAiOiIyMDI1LTA1LTI5VDEzOjI2OjQyLjU2NzA2NSIsInRvdGFsX3BsZWRnZSI6IjUxNjAwMzkwMjgwOTEyMjU5NDk3In0sInR5cGUiOiJQTEVER0VfUkVRVUVTVF9BUFBST1ZBTCJ9.Tsr-lMFROLKDG2yaHVobzEhsRRqKLFyhfUiMIfnzWCiNvWNijKMuifd4pXAQeRln8rrfSFyHo9-5warn9N1uLw
--------------------
The important part of this response is the JWS token.
API Approval: You approve (or reject) the pledge request via an API call to the
POST/requests/{{REQ_ID}}/approve endpoint for approval.
Or to reject, one must call the "reject" challenge via GET /requests/{{REQ_ID}}/challenge/reject and then reject via POST /requests/{{REQ_ID}}/reject.
The body of your request should look something like you see below. The JWS Token that you have received after signing the challenge (seen above) is used to approve the request.
POST /requests/{{REQ_ID}}/approve
Content-Type: application/json
Authorization: Bearer {{your_api_key}}
Body: {
"jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJUcmFuc2FjdGlvbiBwcm9wZXJ0aWVzIjp7Ik1heCBnYXMgcHJpY2UiOiJzd2VpIDY3MzY5NTY2OTAiLCJBbW91bnQiOiJzd2VpIDEyMzAwMDAwMDAwMDAwMCIsIk1heCB0b3RhbCBmZWVzIjoic3dlaSAxNDE0NzYwOTA0OTAwMDAiLCJSZWNpcGllbnQgYWRkcmVzcyI6IjB4YjU1MDM4ODU0NzY5MWE1MjYxOTBkNjBDMzBDMmY5RTJhZjAzZkYzRCIsIkdhcyBsaW1pdCI6IjIxMDAwIn0sImNoYWxsZW5nZSI6IkZGQTMzNzk1MzZDNTVBOEMxRkQwNEREMEEzNjg3MjAwRjQyMkVGRjA1NDZCNTc5QTc3OTA4MTczQTczMEQwQTYifQ.wc7ilV47pari5lL7qJIm7a7PD59kdVm-59ilyN5BGglEXQtZeoLPOn3iz0GoX1X1fcRG__7fJMqxwPgJDzMTTA"
}
Collateral Locked & Credit Extended: Once approved by you, Tradelink secures the assets as collateral. You can then update the Asset Manager's account on your platform with the corresponding line of credit.
B. Creating Settlements
Settlements are typically initiated by you (the LP/Exchange) at the end of a trading period or when specific conditions are met (e.g., margin call, LTV trigger).
Create Settlement Request: You initiate a settlement request via the Tradelink API. This request will detail the transactions, specifying whether it's an "inbound" settlement (assets due to the Asset Manager from you) or an "outbound" settlement (assets due to you from the Asset Manager's pledged collateral).
API Call Example:
POST /settlements
Content-Type: application/json
X-Ledger-Workspace: {{workspace}}
Authorization: Bearer {{your_api_key}}
{
"id": "36a45ef2-0e08-4ff5-bef5-9569c1863389",
"from_pledge_id": "{{pledge_id}}",
"outbound_transaction_intent": {{outbound_transaction_intent}},
// OR "inbound_transaction_intent": {{inbound_transaction_intent}},
"meta": {}
}
Pre-Approval (Optional): Tradelink may support a pre-approval step where the Asset Manager can review and agree to the settlement terms. This can help streamline the process and reduce disputes. They will review and approve the settlement request using their API Operator or via the Ledger Enterprise UI.
Custodian Approval: The Custodian, who holds the Asset Manager's collateral, has the final approval authority for any movement of funds. They will review and approve the settlement request using their API Operator or via the Ledger Enterprise UI.
Transaction Execution & Confirmation:
Inbound Transaction (Payable to Asset Manager): You (the LP) are responsible for creating the transaction and broadcasting it to the Asset Manager's whitelisted address. You then update the tradelink account by creating a new inbound settlement, including the details of the transaction you have already broadcasted. No approvals will be required for this inbound transaction and settlement. You can retrieve the Whitelisted address from the GET/asset_manager endpoint.
Outbound Transaction (Receivable by LP): Upon Custodian approval, the transaction is typically created directly from the Ledger Vault (where the collateral is held) to your whitelisted address.
Your system should monitor for transaction confirmations on the respective blockchains and update Tradelink and your internal records accordingly.
4. Building Your Integration
Step 1: API Integration Development
Using the Ledger Enterprise API documentation, develop the necessary API clients in your preferred programming language to interact with Tradelink.
Key API Endpoints to focus on:
Receiving and processing webhook notifications for pledge requests.
Creating settlement requests (inbound and outbound).
Querying status of pledges and settlements.
Implement robust error handling, retry mechanisms, and logging for all API interactions.
Step 2: API Key Management
Once your integration is built, you will need API Operator keys. These keys are typically associated with a Custodian's workspace on Ledger Enterprise and grant your system the necessary permissions to perform actions (like approving pledges or initiating settlements) within the Tradelink network.
Securely store and manage these API keys. Follow best practices for API key security, such as using environment variables or a dedicated secrets management system. Do not hardcode keys in your application.
5. Testing Your Integration
Phase 0: Documentation Review
Objective: Ensure all team members understand the Tradelink workflows, API specifications, and this integration guide.
Tests/Checks:
Verify access to all relevant documentation (API docs, Help Centre, this guide).
Confirm understanding of the pledge flow from an LP perspective.
Confirm understanding of the settlement flow (inbound and outbound) from an LP perspective.
Review security requirements for API key handling and webhook validation.
Phase 1: Setup & Configuration
Objective: Ensure you have been registered as a new API User in a test workspace managed by your TAM. For this, you should generate a public key pair and give the TAM the public key for the TAM to initiate registration.
Tests/Checks:
Successfully connect to the Tradelink account API (e.g., a simple health check or version endpoint).
Configure and register your webhook endpoint with Tradelink.
Verify that your system can receive and correctly parse test webhook events from Tradelink. You can do this by sending funds to the account to trigger a notification.
Validate API key permissions – ensure your API key has the necessary rights for subsequent tests.
Phase 2: Pledging Workflow
Objective: Test the end-to-end pledge workflow.
Tests/Checks:
Receive Pledge Request: Simulate an Asset Manager creating a pledge. Verify your webhook receives the request.
Process Pledge Request: Ensure your system correctly processes the details of the pledge.
Approve Pledge:
Get the challenge, sign it and call the approve API endpoint to approve the pledge request. Verify a successful response from Tradelink.
Confirm the pledge status is updated to "Approved" in Tradelink (via API query).
Reject Pledge:
Send an API call to reject a pledge. Verify a successful response.
Confirm the pledge status is updated to "Rejected".
Handle Edge Cases:
Test with invalid pledge data.
Test scenarios where your system might internally decline a pledge before sending an API rejection.
Test behavior during API downtime (e.g., exponential back-off retry logic).
Phase 3: Settlement Workflow
Objective: Test the end-to-end settlement workflow for both inbound and outbound settlements.
Tests/Checks:
Create Outbound Settlement (LP Claiming Assets):
Initiate an outbound settlement request via API. Verify successful creation.
Ask your TAM to approve this request.
Verify your system correctly identifies that assets should be received.
Confirm asset movement or balance updates.
Create Inbound Settlement (LP Paying Assets):
Initiate an inbound settlement request via API. Verify successful creation.
Verify your system correctly identifies that assets need to be sent.
If your system is responsible for broadcasting:
Simulate transaction creation and broadcast.
Create ab inbound settlement request with the details of the already broadcasted inbound transaction.
Query Settlement Status: Test API calls to fetch the status of ongoing or completed settlements.
Handle Edge Cases & Errors:
Test with insufficient pledged collateral for an outbound settlement.
Test settlement requests for non-existent or invalid pledges.
Test scenarios with partial settlements (if supported).
Test error handling if a Custodian rejects a settlement.
General Testing Considerations:
Idempotency: Ensure your API calls are idempotent where appropriate (e.g., approving a pledge multiple times should have the same effect as approving it once).
Concurrency: If applicable, test how your system handles multiple simultaneous pledge or settlement requests.
Monitoring & Logging: Verify that your integration produces clear and comprehensive logs for all actions, errors, and important events. This is crucial for troubleshooting in production.
6. Going Live
Once testing is complete and all parties are confident:
Transition from test credentials to production credentials.
Perform a final round of "smoke tests" in the production environment, possibly with small, controlled amounts.
Coordinate with Ledger and relevant Custodians for the official launch.
This guide should provide a solid foundation for your Tradelink integration. Remember to work closely with the Ledger technical team throughout the process.
Last updated