Reconcile payouts
Every payout instruction ends up either matched to a provider record or carrying an explicit, owned exception. Nothing is matched on amount and time alone.
Click any step to read what happens there and what can refuse it.
Uploading a report
curl -X POST "$API/v1/recon/files" -H "x-api-key: $KEY" -H "x-pehmen-organization: $ORG" \
-H "x-pehmen-environment: test" -H "idempotency-key: $(uuidgen)" -H "content-type: application/json" \
-d '{
"connection_id": "con_…",
"report_type": "GENERIC_PAYOUTS",
"business_date": "2026-09-05",
"csv": "ref,request,amount,currency,status\nTRF-1,po-req-1,1450.00,SGD,PAID\n",
"mapping": { "provider_transaction_ref": "ref", "request_id": "request", "gross_major": "amount", "currency": "currency", "provider_status": "status" }
}'
Amounts in the CSV are in major units and converted at the boundary. An empty report is refused. The response carries the file, whether it was a duplicate, and the match run.
Provider statuses
| Airwallex status | Outcome |
|---|---|
PAID | SETTLED |
FAILED, CANCELLED, APPROVAL_REJECTED | FAILED |
CREATED, IN_APPROVAL, SCHEDULED, PROCESSING, SENT | PENDING. SENT means the money left, not that it arrived. |
| anything else | UNKNOWN |
Amended files
Re-ingesting a changed report for the same date never overwrites. Every active match for that date is superseded first, so a payout is never reconciled twice. A payout the earlier report settled and the amended one omits gets an AMENDED_FILE exception; so does one whose amount or status changed, carrying both readings.
The aging table
Aging by class is counted server-side over the whole queue: per class and status, how many, how many nobody owns, and the oldest. An unowned column that is not zero is the queue's real problem. The list below it is sorted oldest first for the same reason.