Guide to Tracking Task and Payment Status
This guide details the correct methods for checking the status of tasks and payments via the Paysend Enterprise API, outlining the specific use cases and limitations of each approach.
Asynchronous Tracking with Webhooks (Recommended)
Webhooks are the preferred method for status tracking. They provide scalable, real-time, event-driven updates without the need for constant polling. We offer two types of webhooks to suit different needs.
Basic Webhooks (For All Task Types)
For general-purpose tasks, you can set a webhook endpoint on a per-request basis. This is configured directly within the API payload of your call.
- How it works: You provide a
callBackURIin your API request. Our system sends a notification to this URL when the task's status changes. - Use Case: Ideal for tracking the lifecycle of non-payment tasks, like generating a statement, requesting FX for a currency pair, or validating card details.
Expanded Webhooks (For Payment Transactions)
For robust payment tracking, we provide expanded webhook capabilities. These offer more detailed status updates specific to the payment lifecycle.
- How it works: Expanded webhooks are configured once in your back-end settings, not in individual API calls. This creates a persistent, reliable channel for all your payment status notifications. Contact your Customer Experience or Implementation manager to set this up.
- Use Case: This is the highly recommended method for all payment reconciliation and tracking.
Our system processes payouts asynchronously across multiple services. When your payout request receives an initial "accepted" status, there is a brief propagation delay while the transaction details are synchronized internally.
During this period, a direct status check may be unable to locate the transaction details immediately, which can result in a 3006: "Unable to find requested data" error. This indicates the data is still in transit within our system, not that the transaction has failed or your request is invalid.
To ensure data consistency for exception handling, you must wait at least 3 minutes after receiving the "accepted" status before using the task.statusGet method to query a payout's status.
Security: Signature Verification
This is a critical security step for all webhooks. Every notification from Paysend includes an X-OPP-Signature in the HTTP header. Your listener endpoint must verify this signature using your shared secret key to confirm the request is authentic. Reject any request that fails verification.
Verification Process
The signature is passed in the X-OPP-Signature HTTP header. The verification process involves recreating this signature on your end and comparing it to the one received.
Here is the step-by-step algorithm:
- Receive the Webhook: Isolate the raw, unmodified JSON body of the incoming POST request and the value of the
X-OPP-Signatureheader. - Prepare the Input String: Create a new string by concatenating the raw request body with your secret key. The secret key should be appended directly to the end of the body string.
- Compute the Hash: Calculate the hash of the resulting concatenated string.
- Compare Hashes: Compare your computed hash with the value received in the
X-OPP-Signatureheader. If they match exactly, the webhook is authentic.
Step-by-Step Example
Let's walk through an example.
- A webhook is sent to your endpoint.
HTTP Header: X-OPP-Signature: 1f373068bd1a17e4ad2ab4462e054d37 Raw Request Body:
{"webhookType":"TransactionStatusUpdate","invoiceId":"MTCN123456789","transactionId":"5d8149f7-9dd5-4784-9f25-3da3215b8a7g","status":"OnHold","statusDateTime":"2025-06-19T00:27:01.810858+03:00","errorCode":"5","errorDescription":"Offline Antifraud check: RFI","rrn":null,"arn":null,"traceId":null}
- You prepare the input string for hashing.
Your Secret Key:
14130906-70e2-44ae-9ac1-e5f0688ebd77
Resulting Concatenated String (Raw Body + Secret Key):
{"webhookType":"TransactionStatusUpdate","invoiceId":"MTCN123456789","transactionId":"5d8149f7-9dd5-4784-9f25-3da3215b8a7g","status":"OnHold","statusDateTime":"2025-06-19T00:27:01.810858+03:00","errorCode":"5","errorDescription":"Offline Antifraud check: RFI","rrn":null,"arn":null,"traceId":null}14130906-70e2-44ae-9ac1-e5f0688ebd77
The resulting hash (using the MD5 algorithm) will be: 1f373068bd1a17e4ad2ab4462e054d37
Synchronous Tracking with Direct API Calls
While webhooks are best for ongoing tracking, direct API calls are available for specific, on-demand checks. It's crucial to understand the limitations of these methods.
Checking Recent Task Status (Global ID Method)
You can perform a direct status check on a task using its globalId. However, this method has a significant limitation.
- How it works: This endpoint queries the function block that processed the task. This block, and therefore your ability to query it, has a limited lifecycle of only 2-3 hours.
- Use Case: This method is only suitable for immediate, short-term checks. For example, you can use it to provide instant feedback in a user interface right after a transaction is submitted. It cannot be used for historical lookups or for reconciliation after the 2-3 hour window has passed.
Handling Payment Exceptions (task.statusGet)
For handling specific payment exceptions, the task.statusGet method is your tool.
Important: This is a reserved method and should not be used for regular polling, but it is essential for resolving complex situations.
Use task.statusGet only in these two scenarios:
- Request for Information (RFI): If a payment status changes to
OnHold, your system will be notified via your expanded webhook. After you submit the required information, you can usetask.statusGetwith thepaymentIdto confirm the RFI has been cleared. - Failover for Timeouts: If your system fails to receive a final status webhook for a transaction (e.g., due to a network timeout),
task.statusGetshould be used as a failover mechanism to retrieve the definitive status and ensure your records are accurate. This is especially important for transactions older than the 2-3 hourglobalIdlookup window.
Sample request:
"tasks": [
{
"type": "task.statusGet",
"payload": {
"identifier": "827eec16-009e-49b7-92ed-dcac6c6b3082"
}
}
]
"tasks": [
{
"type": "task.statusGet",
"payload": {
"invoiceId": "MTCN123456789"
}
}
]