Operations#
Running a live integration: callback delivery and verification, status queries, chargebacks, settlement and reconciliation, testing and go-live.
Settlement#
Settlement Cycle
CentaPay settles to clients on a T+1 (next business day) cycle. Transactions that reach SETTLED status before the daily cutoff are included in the next business day's settlement batch.
| Parameter | Value |
|---|---|
| Cycle | T+1 (next business day) |
| Settlement currency | Agreed at onboarding (typically USD) |
Transaction Status Lifecycle
How a transaction moves through the system toward settlement:
| Status | Meaning |
|---|---|
PENDING | AUTH hold placed. Funds reserved on cardholder's account but not yet captured |
PREPARE | Processing in progress. Final status not yet determined |
3DS | Awaiting cardholder 3DS authentication |
REDIRECT | Awaiting redirect completion |
SETTLED | Transaction completed successfully. Funds will be included in the next settlement batch to you. |
DECLINED | Transaction rejected by issuer or risk engine |
VOID | Same-day cancellation. No funds movement |
REFUND | Full refund processed. Amount deducted from your settlement balance |
REVERSAL | AUTH hold released (no capture occurred) |
CHARGEBACK | Issuer-initiated dispute. Amount debited from your settlement balance |
SETTLED status. The partial refund amount is deducted from your settlement balance. Use GET_TRANS_DETAILS to see the full transaction history including partial refund entries.FX & Currency Conversion
When the transaction currency differs from your settlement currency, CentaPay applies a foreign exchange conversion. The applicable rate is included in callback parameters:
| Callback Field | Description |
|---|---|
exchange_rate | FX rate applied to the transaction |
exchange_rate_base | Base conversion rate (if double conversion applies) |
exchange_currency | Original transaction currency |
exchange_amount | Original transaction amount before conversion |
Settlement Reports
Settlement reports will be available via the admin panel and will include transaction-level detail for reconciliation against your callback records. Contact [email protected] for details on report format, delivery schedule, and available export options for your account.
Querying Settlement Status
Use GET_TRANS_STATUS or GET_TRANS_DETAILS to check whether a transaction has settled.
GET_TRANS_STATUS returns the current status field. A value of SETTLED confirms the transaction completed successfully and will be included in settlement.
GET_TRANS_DETAILS returns the full order history including an array of all sub-transactions (sale, 3ds, auth, capture, credit, chargeback, reversal, refund) with individual dates, statuses, and amounts.
GET_TRANS_STATUS for settlement confirmation. Use callbacks as the authoritative source. Reserve status queries for reconciliation or when a callback has not arrived within your expected window.Settlement & Reporting#
PSP clients receive a single aggregated settlement per cycle covering all sub-merchant transactions.
| Parameter | Value |
|---|---|
| Cycle | T+1 (next business day) |
| Settlement currency | Agreed at onboarding (typically USD) |
| Scope | All sub-merchants under your account, aggregated |
Each transaction callback includes order_id (your reference), trans_id (CentaPay reference), and channel_id (if provided) for sub-merchant-level reconciliation.
Use GET_TRANS_DETAILS to retrieve the full history of any transaction, including payer details, masked card, and all status transitions.
rrn, approval_code, connector_name, and other acquirer-level fields in callbacks, useful for cross-referencing with upstream acquirer reports.For details on sub-merchant settlement breakdowns and report formats, contact [email protected].
Transaction Status (GET_TRANS_STATUS)#
Query the current status of a transaction. Use when a callback hasn't arrived or for reconciliation.
| Parameter | Description | Required |
|---|---|---|
action | GET_TRANS_STATUS | Yes |
client_key | Your account key | Yes |
trans_id | CentaPay transaction ID | Yes |
hash | Formula 2 (or Formula 6 for CREDIT2CARD) | Yes |
Response includes status (one of: 3DS, REDIRECT, PENDING, PREPARE, DECLINED, SETTLED, REVERSAL, REFUND, VOID, CHARGEBACK), plus decline_reason if declined, and recurring_token / schedule_id / digital_wallet if applicable, arn* if configured.
SETTLED is the terminal success status, the transaction has been authorised and captured, and will be included in the next settlement batch to you. For the full settlement lifecycle and status definitions, see Settlement.Transaction Details (GET_TRANS_DETAILS)#
Returns full order history including payer details, card mask, and an array of all transactions in the order.
| Parameter | Description | Required |
|---|---|---|
action | GET_TRANS_DETAILS | Yes |
client_key | Your account key | Yes |
trans_id | CentaPay transaction ID | Yes |
hash | Formula 2 (or Formula 6 for CREDIT2CARD) | Yes |
Response includes: name, mail, ip, amount, currency, card (masked), decline_reason if declined, recurring_token, schedule_id, pan_type, digital_wallet, arn* if configured, and a transactions array with entries containing date, type (sale, 3ds, auth, capture, credit, chargeback, reversal, refund), status, and amount.
Status by Order ID (GET_TRANS_STATUS_BY_ORDER)#
Look up the most recent transaction status using your order_id instead of trans_id. Useful when trans_id is lost or for reconciliation.
| Parameter | Description | Required |
|---|---|---|
action | GET_TRANS_STATUS_BY_ORDER | Yes |
client_key | Your account key | Yes |
order_id | Your order ID | Yes |
hash | Formula 7 (or Formula 6 for CREDIT2CARD) | Yes |
Response: status (3DS/REDIRECT/PENDING/PREPARE/DECLINED/SETTLED/REVERSAL/REFUND/VOID/CHARGEBACK), decline_reason if declined, recurring_token, schedule_id, digital_wallet if applicable. With cascading enabled, returns most recent transaction only.
Chargebacks#
Chargebacks are initiated by the issuing bank, not by API request. CentaPay sends a callback notification when a chargeback occurs.
| Callback Parameter | Description |
|---|---|
action | CHARGEBACK |
result | SUCCESS |
status | CHARGEBACK |
order_id | Your order ID |
trans_id | CentaPay transaction ID |
amount | Chargeback amount |
chargeback_date | System date of the chargeback |
bank_date | Bank date of the chargeback |
reason_code | Chargeback reason code |
connector_name* | Payment gateway name |
rrn* | Retrieval Reference Number |
approval_code* | Issuer authorisation code |
gateway_id* / extra_gateway_id* | Gateway transaction identifiers |
merchant_name* / mid_name* | Merchant and MID names |
issuer_country* / issuer_bank* | Card issuer details |
hash | Formula 2 |
* Extended data fields - included only if configured in admin panel (Configuration → Protocol Mappings → "Add Extended Data to Callback").
Callback Delivery Rules#
CentaPay sends HTTP POST callbacks to your notification URL as transaction states change. Always use callbacks, not the synchronous response, as the authoritative result.
Content Type
Callbacks are sent as application/x-www-form-urlencoded.
Required Response
Your endpoint must return the plain string OK, nothing else. Any other content, HTML, or timeout is treated as a failure.
When Callbacks Are Sent
| Transaction Type | Callback Sent On |
|---|---|
| SALE, CREDITVOID, RECURRING_SALE | SUCCESS, FAIL, WAITING, UNDEFINED |
| CAPTURE, VOID, CREDIT2CARD | SUCCESS, FAIL, UNDEFINED |
| CHARGEBACK | Always (platform-initiated) |
Hash Verification#
Always verify the callback hash before processing. For most actions, use Formula 2. For CREDIT2CARD, use Formula 6. For VOID callbacks, use the Void signature: md5(strtoupper(strrev(trans_id)) . PASSWORD).
email is not included in callback parameters. You must store it from the original SALE request. For SUCCESS callbacks, the card field provides the masked PAN (first 6 + last 4 visible). For DECLINED callbacks, card is not present, use the card mask stored from your original request.$data = $_POST;
// Use card from callback if present (SUCCESS), otherwise use stored mask (DECLINED)
$cardMask = isset($data['card']) ? $data['card'] : $storedCardMask;
$cardPart = substr($cardMask,0,6).substr($cardMask,-4);
$expected = md5(strtoupper(
strrev($storedEmail) . PASSWORD . $data['trans_id'] . strrev($cardPart)
));
if (!hash_equals($expected, $data['hash'])) {
http_response_code(400);
exit('ERROR');
}
// Process based on result
if ($data['result'] === 'SUCCESS') {
fulfillOrder($data['order_id'], $data['trans_id']);
}
echo 'OK';import hashlib, hmac
data = request.form.to_dict()
# Use card from callback if present (SUCCESS), otherwise use stored mask (DECLINED)
card_mask = data.get('card', stored_card_mask)
card_part = card_mask[:6] + card_mask[-4:]
raw = stored_email[::-1] + PASSWORD + data['trans_id'] + card_part[::-1]
expected = hashlib.md5(raw.upper().encode()).hexdigest()
if not hmac.compare_digest(expected, data.get('hash','')):
return 'ERROR', 400
if data['result'] == 'SUCCESS':
fulfill_order(data['order_id'])
return 'OK'const rev = s => s.split('').reverse().join('');
app.post('/webhook', express.urlencoded({extended:false}), (req,res) => {
const d = req.body;
// Use card from callback if present (SUCCESS), otherwise use stored mask (DECLINED)
const cardMask = d.card || storedCardMask;
const cp = cardMask.slice(0,6) + cardMask.slice(-4);
const raw = rev(storedEmail) + PASSWORD + d.trans_id + rev(cp);
const exp = crypto.createHash('md5').update(raw.toUpperCase()).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(exp), Buffer.from(d.hash||'')))
return res.status(400).send('ERROR');
if (d.result === 'SUCCESS') fulfillOrder(d.order_id);
res.send('OK');
});Cascading Behaviour#
When cascading is enabled (auto-retry across MIDs on decline):
- General case: You receive only a callback for the last payment attempt with the final status.
- Particular case: If a redirect is required (e.g. 3DS), you also receive a callback for the first attempt with redirect data. The last-attempt callback includes only the final status.
- Intermediate attempts are not sent. The
trans_idmay differ between first and final callbacks. Do not assume you will receive a first-attempt callback.
Extended Callback Data#
Additional fields if configured in admin panel (Configuration → Protocol Mappings → "Add Extended Data to Callback"): connector_name, rrn, approval_code, gateway_id / extra_gateway_id, merchant_name / mid_name, issuer_country / issuer_bank, brand, arn, extended_data.
Go-Live Checklist#
Complete these items before requesting production credentials.
Technical
| Item | Detail |
|---|---|
| SALE tested. Success | Card 4111111111111111 exp 01/2038 returns SUCCESS/SETTLED |
| SALE tested. Decline | Exp 02/2038 returns DECLINED |
| 3DS redirect handled | Exp 05/2038 → redirect → return → SUCCESS. Exp 06/2038 → DECLINED |
| Callback handler implemented | Endpoint returns plain OK. Hash verified using Formula 2. Tested with all result types. |
| CREDITVOID tested | Full and partial refunds work correctly |
| VOID tested (if used) | Same-day cancellation on SETTLED transaction |
| GET_TRANS_STATUS tested | Status polling works as fallback when callback delayed |
| Error handling implemented | All error codes handled gracefully. User sees meaningful messages. |
| Idempotent order IDs | Each payment attempt uses a unique order_id. Duplicates handled. |
| IP addresses provided | Production server IPs sent to CentaPay for whitelisting |
| Callback URL configured | Production callback URL registered with CentaPay |
| HTTPS everywhere | All endpoints use TLS. No plain HTTP. |
If Using Recurring
| Item | Detail |
|---|---|
| RECURRING_SALE tested | Initial SALE with recurring_init=Y, then RECURRING_SALE with token |
| RETRY tested | Soft decline → RETRY → final result via callback |
| Schedule ops tested (if used) | CREATE, PAUSE, RUN, DELETE, SCHEDULE_INFO, DESCHEDULE |
If Using Payouts
| Item | Detail |
|---|---|
| CREDIT2CARD tested | Test card 4601541833776519 returns SUCCESS |
| Formula 5 hash verified | Request hash uses Formula 5 (not Formula 1) |
| Formula 6 callback hash | Callback verification uses Formula 6 (not Formula 2) |
If Using Digital Wallets
| Item | Detail |
|---|---|
| Apple Pay: Merchant ID configured | Certificates and keys uploaded to admin panel |
| Apple Pay: Domains verified | All payment domains registered in Apple Developer |
| Google Pay: Integration checklist | Completed per Google's requirements |
| Google Pay: Domains verified | Verified in Google Business Console |
| Formula 8 hash used | Wallet SALE uses email + PASSWORD only |
Compliance
| Item | Detail |
|---|---|
| PCI DSS evidence | SAQ D or full assessment (for raw card S2S). Reduced scope for wallet-only. |
| KYB complete | Business verification documents submitted and approved |
| Prohibited MCCs reviewed | Business model confirmed against prohibited categories |
| Client agreement signed | Executed with CentaPay |
Commercial
| Item | Detail |
|---|---|
| Production credentials received | Separate CLIENT_KEY, PASSWORD, PAYMENT_URL for production |
| Settlement currency confirmed | USD or preferred currency agreed with CentaPay |
| MID configured | Production MID mapped to your account by CentaPay ops |
Contact [email protected] when all items are complete to begin the go-live process.
Which formula verifies which callback#
The request and the callback almost never sign with the same construction. This is the fact that costs integrators the most time, because a single shared verification routine passes on most callbacks and fails on a few, which reads as a problem with those operations rather than with the hashing.
| Callback | Request signs with | Callback verifies with |
|---|---|---|
SALE, card | Formula 1 | Formula 2 |
SALE, stored token | Formula 1, token variant | Formula 2 |
SALE, wallet | Formula 8 | Formula 2 |
CAPTURE | Formula 2 | Formula 2 |
CREDITVOID | Formula 2 | Formula 2 |
VOID | Formula 2 | the Void signature |
CREDIT2CARD | Formula 5 | Formula 6 |
RECURRING_SALE, RETRY | Formula 1 | Formula 2 |
CHARGEBACK | platform-initiated | Formula 2 |
When each callback fires is not documented. This table shows how to verify a callback once it has arrived. It does not say what causes one to arrive, and neither does anything else on this site, because the platform has not specified it.
What is published: every callback names an action and an outcome, and all 19 callback messages with their full field sets are in the AsyncAPI document, generated from the same schemas as the API reference. What is not: the event that triggers each callback, and when it is sent.
This has been raised with the platform and an answer is expected. Until it arrives this page states the gap rather than filling it, because a wrong statement about when money moves is worse than an incomplete one.
Write your handler to be driven by what a callback contains rather than by when you expect it. Verify the signature, read the status, and treat the callback as the authoritative outcome of the transaction.
The two marked rows are the ones a shared routine gets wrong. A VOID callback uses the Void signature, which is a plain MD5 with no email and no card fragment, and CREDIT2CARD is the only action whose callback formula differs from Formula 2 by adding the trans_id.
Every formula, with a worked vector for each, is on the API reference. The field set each callback carries is under Callback Parameters by Action above.
Where to go next#
Operations covers what happens after a payment is taken. If something is not behaving as described here, troubleshooting lists the symptoms and their causes.
Troubleshooting
Symptoms you will actually hit, and what causes them.
API reference
Every parameter of every action, callback parameters and the error code table.
Guides
Task-oriented walkthroughs, one job end to end.
Technical questions go to [email protected].