Disbursement Error Handling
Overview
When making payments to workers, robust handling of error cases is a necessity to ensure money is moved correctly. After using Create Disbursement, check the HTTP response status code and the disbursement's status to determine followup actions.
- If a
200or a201is returned, the request was successful and no action is required. - If a
500, a504, or a202withstatus=PENDINGis returned, the request result is temporarily uncertain and should be polled. - If a
400or a429is returned, the request failed due to misconfiguration or rate limiting. - If a
202withstatus=FAILEDis returned, the request failed and should be resolved before retrying the disbursement. Check thereason_codeto determine resolution actions.- After confirming the disbursement
status=FAILED, a disbursement can be safely retried if desired.
- After confirming the disbursement
Check the HTTP Response Status Code
| Code | Condition | Actions |
|---|---|---|
200 | A matching disbursement already exists, status is CANCELED or SKIPPED | Can be retried if CANCELED.Can be updated and reattempted if SKIPPED. |
201 | A new disbursement was created, status is SCHEDULED or COMPLETED | Can be canceled if SCHEDULED.Can be updated and reattempted or reversed if COMPLETED. |
202 | A new disbursement was attempted, status is PENDING or FAILED | Can be polled if PENDING.Can be resolved then retried if FAILED. |
400 | A static request validation is incorrect or no invoice configuration is found for the request | If static request validation failed, inspect the response and fix the request accordingly. If no invoice configuration was found, then contact Support or your Account Manager. |
429 | Too many actual requests are being sent to the API, or the org has exceeded their daily disbursement limit. | If rate-limited, handle by waiting with exponential backoff. Otherwise, contact Support or your Account Manager about potentially increasing the daily disbursement limit. |
500 | Unexpected Error | Poll to check if the error automatically resolves. If the problem persists, contact Support or your Account Manager with any additional information that can be provided. |
504 | Disbursement request timed out on initial attempt and fallback retry | Poll to reattempt the payout. If the problem persists, contact Support or your Account Manager. |
Poll Temporary States for Completion
Upon using Create Disbursement, the response might indicate an intermittent failure or intermediate state. These cases should be polled until a terminal state is returned.
Perform polling by repeating Create Disbursement with external_id and type set to match the original request. Poll for completion every 10 seconds 2-3 times, then exponentially back off to 15 min -> 30 min -> 60 min.
An HTTP 500 response is an intermittent failure caused by an unhandled exception from a dependency of Branch's systems. Polling can detect when the dependency resumes normal functionality. Contact Branch with any additional information about these errors to resolve them more quickly.
An HTTP 504 response is an intermittent failure caused by a timeout from a dependency of Branch's systems. Polling will retry the request until the dependency responds within the allotted timeframe.
An HTTP 202 response where the disbursement's status = PENDING is an intermediate state where it's not yet known if the payment will be COMPLETED or FAILED. Polling will query the existing disbursement for the updated status.
Check the Reason Code
Pending Disbursements
If the status of a disbursement is PENDING, poll to query the finalized status.
| Reason Code | Description | Suggested Action |
|---|---|---|
PAYOUT_PENDING | The disbursement is still in progress. | Poll for completion every 10 seconds 2-3 times, then exponentially back off to 15 min -> 30 min -> 60 min |
Skipped Disbursements
If the status of a disbursement is COMPLETED or SKIPPED, the request must be updated with unique external_id or metadata before reattempting.
| Reason Code | Description | Suggested Action |
|---|---|---|
RETRY_PERIOD_ELAPSED | The disbursement already existed and is too old to be attempted again. | A new payout with unique external_id will need to be created to replace the expired one |
RETRY_LIMIT_EXCEEDED | The disbursement has been retried the max number of allowed attempts (100). | A new payout with unique external_id will need to be created to replace the expired one |
LIKELY_MATCH_FOUND | The disbursement was not attempted because another disbursement was identified as a duplicate. | Review payout to ensure it's not a duplicate, update metadata to be unique and resend |
AMOUNT_ZERO | The payout was recorded with an amount of $0.00 | A new payout with unique external_id will need to be created to retry with a non-zero amount. Log for potential system errors. |
Failed Disbursements
If the status of a disbursement is FAILED, the reason_code will contain an error cause that must be handled before expecting successful disbursement.
| Reason Code | Description | Suggested Action |
|---|---|---|
WORKER_NOT_FOUND | The worker was not found on the active roster. | Double check the worker ID to make sure that the worker ID has had a wallet or card successfully created. |
PAYMENT_PROFILE_NOT_FOUND | No destination account could be found for the provided worker. | Pay user via non-Branch payment mechanism and/or prompt them to finish set up for Direct/Wallet |
PAYMENT_PROFILE_SUSPENDED | The destination account is not payable due to suspension. | Worker needs to fix their account then org can retry disbursement. |
PAYMENT_PROFILE_NOT_ACTIVE | The destination account is not payable because it is closed or otherwise inactive. | Stop sending disbursements for this worker. Direct user to account for details or to request reopening. |
PAYMENT_PROFILE_FRAUDULENT | The destination account is not payable because it has been closed for fraud. | User’s account is not payable due to fraud. Pay user via non-Branch payment mechanism. |
TRANSFER_FAILED | An error occurred while issuing the funds to the worker. | Retry won’t work. Reach out to Support or your Account Manager for details |
AMOUNT_EXCEEDS_ORG_SINGLE_DISBURSEMENT_LIMIT | The amount exceeds the organization's limit for a single disbursement. | If payment amount is correct, reach out to Support or your Account Manager to adjust the payout limit configuration |
AMOUNT_EXCEEDS_ORG_DAILY_DISBURSEMENT_LIMIT | The amount would exceed the organization's daily limit for disbursements. | Wait 24 hours to send additional payouts or reach out to Support or your Account Manager to review org daily limit |
AMOUNT_EXCEEDS_WORKER_DAILY_DISBURSEMENT_LIMIT | The amount would exceed the worker's daily limit for disbursements. | Wait 24 hours to send additional payouts or reach out to Support or your Account Manager to review worker payout limit |
AMOUNT_DOES_NOT_COVER_USER_FEES | The fee to be charged to the worker exceeds or is equal to the disbursement amount. | Allow additional funds to accumulate before sending payout so that it exceeds minimum user-paid fee |
UNEXPECTED_ERROR | Something unexpected occurred. Contact Branch support if this persists. | Retry the payout. If the problem persists reach out to Support or your Account Manager |
Retry a Disbursement
Before retrying a disbursement, first confirm that the status = FAILED or CANCELED. If status = COMPLETED, SKIPPED, SCHEDULED, or PENDING, the request will act as an idempotent GET.
To retry an existing disbursement, set retry = true, and set external_id and type to match the original request. This method is more resilient to temporary states and intermittent failures, as it will never result in accidental overpayment.
Alternatively, initiate a new disbursement using a different external_id. If temporary failure states aren't detected and handled correctly while using this method, duplicate payments could occur.
Updated about 6 hours ago
