Multi-leg payments
The Multi-leg payments feature enables you to process complex payment transactions by grouping multiple legs into a single request. This approach simplifies payment processing and removes the need to send multiple separate single-leg payment requests. With this feature, you can define each individual transaction—either credit or debit—within each leg of the multi-leg payment.
The Pismo platform ensures data integrity by enforcing strict validation, idempotency, and error-handling mechanisms throughout the payment lifecycle. Each transaction is uniquely identified by a single-use tracking ID, which cannot be reused across different services. In the event of errors—such as a failed debit or credit leg—the platform employs a robust rollback process to reverse all successfully executed legs, maintaining transactional consistency and supporting accurate reconciliation.
Notes
- Each multi-leg payment request must contain a minimum of two legs (either credit or debit) and can include up to a maximum of 20 legs.
- You cannot use Post multi-leg payment to transfer credit and debit leg payments to different accounts for identical amounts. For such situations, send Post payment requests instead.
Tracking ID requirement
A tracking ID is used to identify and track an individual payment leg within a multi-leg transaction, whether it is a debit or a credit. When using the Post multi-leg payment endpoint, you must pass a tracking ID. It is used to generate a child tracking ID for each leg. These IDs are created by adding a control suffix to the original tracking ID. Each child tracking ID is then hashed to guarantee a unique identifier. For more information about tracking ID, refer to the description in the tracking_id
field of Post multi-leg payment.
About tracking ID
Each tracking ID is single-use and cannot be reused across different services. For example, if a tracking ID has already been used for a Post payment, it cannot be used again for a Post multi-leg payment. Every multi-leg payment transaction requires a unique tracking ID.
Force payment restrictions
In scenarios where force_post
is set to true
, any reason-based force payment restrictions on the account will result in a failed force payment operation. These restrictions apply to both credit and debit operations. Use the List account status reasons endpoint to view the corresponding reason IDs. Forced transfers from an earmark balance are not supported.
If an account has a status that prevents force operations, the payment will fail. For more information, refer to Manage account statuses.
Error handling mechanism
During the processing of a payment request, the Pismo platform enforces a robust error-handling mechanism known as rollback to safeguard data integrity. If any leg—including a credit leg—fails, the entire payment request is reversed, and all previously successful legs are rolled back. This rollback process is resource-intensive and generates compensating transactions to offset any legs that were already executed. To minimize the need for rollbacks, the platform conducts thorough validations when each payment request is received and proactively alerts you to potential failures upon detecting invalid inputs.
Error response structure
When validation errors occur within a request, the API returns a structured error response that has two components:
Standard error message: For example, the error code WMLP0005
warns users about invalid inputs without providing specific leg-related error details. This error typically happens when you reuse a tracking_id
.
Duplicate tracking ID: If you use the same tracking ID for a multi-leg payment request that was previously used in another transaction, the system generates error code WPMT0007
to notify you of the duplicate tracking ID and rejects your payment request.
List of leg-specific errors: In addition to generic error messages, a response payload may include detailed lists of leg-specific errors. In certain situations, an error can be related to an entire request, and not limited to leg-specific error (such as when a request exceeds the maximum allowable number of legs). In such cases, the standard error response containing only code and message attributes is provided. Refer to the examples in the Post multi-leg payment endpoint for various error types and their respective error codes.
Error identification
If a leg fails, you can use Get multi-leg payment status and refer to the event_datetime
field to determine when and where the error occurred. This timestamp enables you to accurately identify the source of the error for precise account reconciliation.
Note
If a credit leg fails in a multi-leg payment, the Pismo platform rolls back all successfully processed legs—both credit and debit.
How to use Post multi-leg payment
Consider a scenario in which your account has a balance of $1000, and you wish to initiate a payment request with three legs: two debit legs (one for $100, another for $200) and one credit leg for $600. Here are the account details.
Request details
{
"account_id": 150317653,
"division_code": "my-division-code-1705083775718",
"program_id": 10768,
"available_balance": 1000,
"earmark_balance": 0,
"overdraft_limit": 0,
"book_balance": 1000,
"value_dated_balance": 1000,
"children": [],
"status": "NORMAL",
"external_account_id": "df4c54fe-776e-4c49-bd2d-d03a89013218",
"currency_numeric_code": "840",
"currency_alphabetic_code": "USD",
"document_number": "27948365",
"account_creation_datetime": "2024-03-01T16:25:13.000Z"
}
To initiate the multi-leg payment, use the Post multi-leg payment endpoint. The following is a sample request for this operation. Note that tracking_id
must be unique; otherwise a validation error with WMLP0007
will occur.
Sample multi-leg payment request
curl --location 'https://sandbox.pismolabs.io/corporate/v1/payments/multileg' \
--header 'Content-Type: application/json' \
--header '<your_token>' \
--data '{
"tracking_id": "f85fd6e1-8b22-4850-b350-a2768dc443732233",
"debits": [
{
"amount": 100,
"currency": "USD",
"external_account_id": "df4c54fe-776e-4c49-bd2d-d03a89013218"
},
{
"amount": 200,
"currency": "USD",
"external_account_id": "df4c54fe-776e-4c49-bd2d-d03a89013218"
}
],
"credits": [
{
"amount": 600,
"currency": "USD",
"external_account_id": "df4c54fe-776e-4c49-bd2d-d03a89013218"
}
]
}'
Upon successful execution, the API returns the following response payload to confirm the successful processing of your request.
Sample response
{
"debits": [
{
"external_account_id": "df4c54fe-776e-4c49-bd2d-d03a89013218",
"amount": 100,
"currency": "USD",
"force_post": false,
"skip_account_date_validation": false
},
{
"external_account_id": "df4c54fe-776e-4c49-bd2d-d03a89013218",
"amount": 200,
"currency": "USD",
"force_post": false,
"skip_account_date_validation": false
}
],
"credits": [
{
"external_account_id": "df4c54fe-776e-4c49-bd2d-d03a89013218",
"amount": 600,
"currency": "USD",
"force_post": false,
"skip_account_date_validation": false
}
],
"tracking_id": "f85fd6e1-8b22-4850-b350-a2768dc443732233",
"metadata": null
}
You can optionally use Get transaction banking account info to retrieve and display the complete result of this transaction. As shown in the response below, the payment request comprising two debit legs totaling $300 and one credit leg of $600 results in an updated account balance of $1300.
Result
{
"account_id": 150317653,
"division_code": "my-division-code-1705083775718",
"program_id": 10768,
"available_balance": 1300,
"earmark_balance": 0,
"overdraft_limit": 0,
"book_balance": 1300,
"value_dated_balance": 1300,
"children": [],
"status": "NORMAL",
"external_account_id": "df4c54fe-776e-4c49-bd2d-d03a89013218",
"currency_numeric_code": "840",
"currency_alphabetic_code": "USD",
"document_number": "27948365",
"account_creation_datetime": "2024-03-01T16:25:13.000Z"
}
Updated 1 day ago