RECOMMENDATION
We highly recommend using webhooks instead of long-polling to get the status.
Request
To identify the order’s status, you can make the following API call:
{ # A unique id on the merchant side "merchantOrderId": "1697637323" }
Response
{ "data": { # An identifier of the order on our side "id": "e300df2c-5692-4efd-8c3b-b1f498709a01", # A unique id on the merchant side "merchantOrderId": "1697637323", # Type of order "type": "payout", # Time of order creation "createdAt": "2023-10-18T12:56:39+00:00", # Status of order "status": "processing", # Sub status of order, "subStatus": null, # Depends on order type # Those fields represent change of balance of merchant wallets # Look at order type-specific "Status" sections for more details "merchantSourceWallet": null, "merchantTargetWallet": null, # Transactions that were created during order processing # Look at order type-specific "Status" sections for more details "transactions": [ # ... ] }, "error": null }
The response for both Payment and Withdrawal will be similar, but there are some differences in how to interpret it. You can find more details in the order type-specific “Status” sections.
Unexpected errors during order creation
During the order creation phase, you may encounter errors and might be uncertain if the order was created. In this case you need to check that order was actually created or not.
If you receive ORDER_NOT_FOUND error code you should be sure that order was not created.
It is especially vital for withdrawals.
Substatus: awaiting_confirmation
This substatus is used in conjunction with the primary status processing. It indicates that the funds have been debited from the sender’s account, and we are awaiting final confirmation via API before further progressing the transaction.
- Once we receive a debit confirmation from the senderโs bank or payment source, the transaction is marked as processing with the substatus awaiting_confirmation.
- This state reflects a transition phase, where funds are already deducted, but final backend confirmation is pending.
If the payment remains in processing + awaiting_confirmation for more than 20 days, it will be automatically closed by the system.
Webhook
You can also rely on the webhook, which will be sent to the webhookUrl you specified during order creation, once the order receives its final status.
Structure of webhook request will be the same as data object from response of status call.
WARNING
There is no guarantee that the webhook will only be delivered once.
Relies on the so-called at-least-once delivery.
We’ll try to deliver webhook until you respond with 200 OK status code. Expected response time must not exceed 3 seconds.
In case of any not expected response or network malfunction, will retry delivery attempt no more than 20 times. Every subsequent webhook retry will be sent with double delay.
Sample
Webhook will have the following structure:
{ "id": "e300df2c-5692-4efd-8c3b-b1f498709a01", "merchantOrderId": "1697637323", "type": "payin", "createdAt": "2023-10-18T12:56:39+00:00", "status": "completed", "subStatus": null, "merchantSourceWallet": null, "merchantTargetWallet": { "amount": "100.02", "currency": "brl" }, "transactions": [ # ... ] }
Verification
Webhook verification is essential to confirm that the data received from our server was indeed generated by us and has not been tampered with during transmission.
We rely on the following steps for webhook verification:
- Shared Public Key: We provide a shared public key that all merchants use to verify webhook requests.
- Request Signature: With each webhook payload sent from our server, we include a base64-encoded Signature header that is created by private key using sha512. This signature is unique to each request and ensures that the data has not been altered in transit.
- Signature Verification: Upon receiving a webhook request, you should retrieve the included signature and use the shared public key to verify the signature. If the verification is successful, you can be confident that the webhook data is authentic and unaltered.
- IP Whitelisting: To further enhance security, it is highly recommended that you maintain a whitelist of IP addresses from which you will accept webhook requests. This ensures that only requests originating from trusted sources are accepted by your application.
Appendix A
Download “webhook-shared-public-key.pem”
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA11FN+8yJrq6X+PD18h8A x+RrTFxOIiYiuJ0fCFeEOR5mkFhUGuDl6iV8lNsrbOvgePoIz0RrBzx6mVireJJZ TIp+wa1N3263IqAmAkUpRK+hGi0oxdSUgo0tbUEq64F/pX+5berF0/ZwHp9XpkC1 sNBARPetC74WqSJpiqfqNbH9Ghx/H6qVBW33XE/m49FJbvrbLBWC6ZuWf5RZdQEC y2NAamQZ9iyoDPuwCCcsMuC5jR0eGSq3mg0p7yKd4UjqEQjniJFkLeE7/UUhk7yr NDKicqrf7D5I5PprurUJI1LtFvs95vqAxlpekoZ5X9Hf34rxz6+fUIIOYTZSYhmN QwIDAQAB -----END PUBLIC KEY-----
Appendix B
18.198.253.217
Appendix C
There are several snippet samples for webhook verification:
openssl dgst -sha512 \ -verify ./webhook-shared-public-key.pem \ -signature ./signature \ ./request-body
Let’s try on example request
POST /webhook-url/1697633610 HTTP/1.1 Host: example.com Signature: J3xnvxLYUHWVMeIOlUrXl/ljxLLQQmqHB+77SdlO8dh57IFlHM+ne9ir5se/W557Scfp5N8D8BK+SI+8G7TJ4VF3hT4UZeyuD59DUCvP0JhPk3ml5SZ0S/tgW/U82uVqAzlJr1r30/RmJvynRQ9L/SSjYhI0i3UBbKkn5ansslktBPYy5RwBH7LRaoqWwBsIh7TKHpMQ6Jy8OexYW00chtH2NTjeeZzpnzMk0LDrvFgGRRYKpCFUXOGWB51PG5h6dr7qGZ8W9Kl/PAmSQke8VRIj6fwrvIl+B8kCrbm/J6kYgRyRXytgJzJ1hymY908QTYF/PrsLetIHZWvgzO0E3A== {"data": {}, "error": null}
- Create file “./webhook-shared-public-key.pem” and put Download “webhook-shared-public-key.pem”
echo "-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA11FN+8yJrq6X+PD18h8A x+RrTFxOIiYiuJ0fCFeEOR5mkFhUGuDl6iV8lNsrbOvgePoIz0RrBzx6mVireJJZ TIp+wa1N3263IqAmAkUpRK+hGi0oxdSUgo0tbUEq64F/pX+5berF0/ZwHp9XpkC1 sNBARPetC74WqSJpiqfqNbH9Ghx/H6qVBW33XE/m49FJbvrbLBWC6ZuWf5RZdQEC y2NAamQZ9iyoDPuwCCcsMuC5jR0eGSq3mg0p7yKd4UjqEQjniJFkLeE7/UUhk7yr NDKicqrf7D5I5PprurUJI1LtFvs95vqAxlpekoZ5X9Hf34rxz6+fUIIOYTZSYhmN QwIDAQAB -----END PUBLIC KEY-----" > ./webhook-shared-public-key.pem
- Create file “./request-body” and put “{“data”: {}, “error”: null}”
echo -n '{"data": {}, "error": null}' > ./request-body
- Create file “./signature”. Take content of Signature header, decode it from base64 and put into file “signature”
echo "J3xnvxLYUHWVMeIOlUrXl/ljxLLQQmqHB+77SdlO8dh57IFlHM+ne9ir5se/W557Scfp5N8D8BK+SI+8G7TJ4VF3hT4UZeyuD59DUCvP0JhPk3ml5SZ0S/tgW/U82uVqAzlJr1r30/RmJvynRQ9L/SSjYhI0i3UBbKkn5ansslktBPYy5RwBH7LRaoqWwBsIh7TKHpMQ6Jy8OexYW00chtH2NTjeeZzpnzMk0LDrvFgGRRYKpCFUXOGWB51PG5h6dr7qGZ8W9Kl/PAmSQke8VRIj6fwrvIl+B8kCrbm/J6kYgRyRXytgJzJ1hymY908QTYF/PrsLetIHZWvgzO0E3A=="|base64 -d > ./signature
- Run
openssl dgst -sha512 \ -verify ./webhook-shared-public-key.pem \ -signature ./signature \ ./request-body
'; $signature = base64_decode(''); if (openssl_verify($body, $signature, $publicKey, \OPENSSL_ALGO_SHA512) !== 1) { throw new Exception('Signature verification failed'); } echo 'Webhook is verified ๐';
JavaScript / Node.js const fs = require('fs'); const crypto = require('crypto'); const publicKey = fs.readFileSync('./webhook-shared-public-key.pem', 'utf8'); const body = ''; const signature = Buffer.from(' ', 'base64'); if (!crypto.verify('SHA512', body, publicKey, signature)) { throw new Error("Signature verification failed"); } console.log('Webhook is verified ๐');
import rsa import base64 with open('./webhook-shared-public-key.pem', 'r') as public_key_file: public_key = rsa.PublicKey.load_pkcs1_openssl_pem(public_key_file.read().encode('utf-8')) body = '' signature = base64.b64decode(' ') try: rsa.verify(body, signature, public_key) print('Webhook is verified ๐') except rsa.VerificationError: raise Exception('Signature verification failed')
Depends on your platform your own implementation may differ from our samples.
When you use the provided request sample and our shared public key, your implementation should:
- Successfully validate the signature using the shared public key.
- Confirm that the signature in the Signature header matches the computed signature.
- Accept the request and process the payload as valid, as the provided request is a valid test case.
If your implementation passes these checks and behaves as expected, it indicates that your webhook verification process is correctly configured. This ensures that your application can trust incoming webhook requests from our service and accurately verify their authenticity.
Please keep in mind that the provided request sample is for testing and validation purposes only. In a production environment, you should implement webhook verification with actual incoming requests from our service using the shared key.
By following these steps, you can ensure that your webhook implementation is correctly configured and able to verify signatures as required for secure webhook processing.
POST /webhook-url/1697633610 HTTP/1.1 Host: example.com Signature: J3xnvxLYUHWVMeIOlUrXl/ljxLLQQmqHB+77SdlO8dh57IFlHM+ne9ir5se/W557Scfp5N8D8BK+SI+8G7TJ4VF3hT4UZeyuD59DUCvP0JhPk3ml5SZ0S/tgW/U82uVqAzlJr1r30/RmJvynRQ9L/SSjYhI0i3UBbKkn5ansslktBPYy5RwBH7LRaoqWwBsIh7TKHpMQ6Jy8OexYW00chtH2NTjeeZzpnzMk0LDrvFgGRRYKpCFUXOGWB51PG5h6dr7qGZ8W9Kl/PAmSQke8VRIj6fwrvIl+B8kCrbm/J6kYgRyRXytgJzJ1hymY908QTYF/PrsLetIHZWvgzO0E3A== {"data": {}, "error": null}
Order status list
Name | Status | is final status ? |
---|---|---|
new |
Status | FALSE |
processing |
Status | FALSE |
awaiting_confirmation |
subStatus | FALSE |
completed |
Status | TRUE |
rejected |
Status | TRUE |
canceled |
Status | TRUE |
partially_completed |
Status | TRUE |
refunded |
Status | TRUE |
overpaid |
Status | TRUE |
underpaid |
Status | TRUE |
true – This status is final and will not be changed.
false – This status is not final and can be changed.
Are there any inquiries still outstanding?
Our team of experts is available 24/7 to answer all your questions. Feel free to reach out to us at any time, and we will be happy to help you address any inquiries or issues. Your comfort and satisfaction are our priority.