CentaPay

Last updated

Operations#

Running a live integration: callback delivery and verification, status queries, chargebacks, settlement and reconciliation, testing and go-live.

Availability. CentaPay is pre-launch. Production is expected in Q4 2026, with sandbox access ahead of it. Coverage differs by market, and the payment methods available differ by market too. The coverage table on our main site is the single source for what is live where, and for current dates. Nothing in this documentation should be read as a service available today.

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.

ParameterValue
CycleT+1 (next business day)
Settlement currencyAgreed at onboarding (typically USD)

Transaction Status Lifecycle

How a transaction moves through the system toward settlement:

StatusMeaning
PENDINGAUTH hold placed. Funds reserved on cardholder's account but not yet captured
PREPAREProcessing in progress. Final status not yet determined
3DSAwaiting cardholder 3DS authentication
REDIRECTAwaiting redirect completion
SETTLEDTransaction completed successfully. Funds will be included in the next settlement batch to you.
DECLINEDTransaction rejected by issuer or risk engine
VOIDSame-day cancellation. No funds movement
REFUNDFull refund processed. Amount deducted from your settlement balance
REVERSALAUTH hold released (no capture occurred)
CHARGEBACKIssuer-initiated dispute. Amount debited from your settlement balance
After partial refund: The original transaction retains 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 FieldDescription
exchange_rateFX rate applied to the transaction
exchange_rate_baseBase conversion rate (if double conversion applies)
exchange_currencyOriginal transaction currency
exchange_amountOriginal 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.

Best practice: Do not poll 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.

ParameterValue
CycleT+1 (next business day)
Settlement currencyAgreed at onboarding (typically USD)
ScopeAll 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.

Tip: Enable Extended Data in your admin panel (Configuration → Protocol Mappings → "Add Extended Data to Callback") to receive 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.

ParameterDescriptionRequired
actionGET_TRANS_STATUSYes
client_keyYour account keyYes
trans_idCentaPay transaction IDYes
hashFormula 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.

ParameterDescriptionRequired
actionGET_TRANS_DETAILSYes
client_keyYour account keyYes
trans_idCentaPay transaction IDYes
hashFormula 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.

ParameterDescriptionRequired
actionGET_TRANS_STATUS_BY_ORDERYes
client_keyYour account keyYes
order_idYour order IDYes
hashFormula 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 ParameterDescription
actionCHARGEBACK
resultSUCCESS
statusCHARGEBACK
order_idYour order ID
trans_idCentaPay transaction ID
amountChargeback amount
chargeback_dateSystem date of the chargeback
bank_dateBank date of the chargeback
reason_codeChargeback 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
hashFormula 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.

Client Server CentaPay Platform Payer Browser Flow A, No 3DS POST /post sync response (SUCCESS / DECLINED / UNDEFINED) later callback POST to client callback URL client responds 200 OK Flow B, 3DS POST /post sync REDIRECT (redirect_url) client redirects payer browser payer completes 3DS at ACS payer returns to term_url_3ds callback POST with final result Callback delivery: response 200 with body OK required. Retry: up to 5 attempts, then blocked 5 min, then 15 min. The callback, not the sync response, is the authoritative outcome.

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.

Blocking: 5 consecutive timeouts within 5 minutes will block your callback URL for 15 minutes. All merchants sharing that URL are affected. The counter resets on any successful response. You can manually unblock via the admin panel (Configuration → Merchants → Edit Merchant).

When Callbacks Are Sent

Transaction TypeCallback Sent On
SALE, CREDITVOID, RECURRING_SALESUCCESS, FAIL, WAITING, UNDEFINED
CAPTURE, VOID, CREDIT2CARDSUCCESS, FAIL, UNDEFINED
CHARGEBACKAlways (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).

Formula 2 requires data not in the callback. The payer's 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_id may 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

ItemDetail
SALE tested. SuccessCard 4111111111111111 exp 01/2038 returns SUCCESS/SETTLED
SALE tested. DeclineExp 02/2038 returns DECLINED
3DS redirect handledExp 05/2038 → redirect → return → SUCCESS. Exp 06/2038 → DECLINED
Callback handler implementedEndpoint returns plain OK. Hash verified using Formula 2. Tested with all result types.
CREDITVOID testedFull and partial refunds work correctly
VOID tested (if used)Same-day cancellation on SETTLED transaction
GET_TRANS_STATUS testedStatus polling works as fallback when callback delayed
Error handling implementedAll error codes handled gracefully. User sees meaningful messages.
Idempotent order IDsEach payment attempt uses a unique order_id. Duplicates handled.
IP addresses providedProduction server IPs sent to CentaPay for whitelisting
Callback URL configuredProduction callback URL registered with CentaPay
HTTPS everywhereAll endpoints use TLS. No plain HTTP.

If Using Recurring

ItemDetail
RECURRING_SALE testedInitial SALE with recurring_init=Y, then RECURRING_SALE with token
RETRY testedSoft decline → RETRY → final result via callback
Schedule ops tested (if used)CREATE, PAUSE, RUN, DELETE, SCHEDULE_INFO, DESCHEDULE

If Using Payouts

ItemDetail
CREDIT2CARD testedTest card 4601541833776519 returns SUCCESS
Formula 5 hash verifiedRequest hash uses Formula 5 (not Formula 1)
Formula 6 callback hashCallback verification uses Formula 6 (not Formula 2)

If Using Digital Wallets

ItemDetail
Apple Pay: Merchant ID configuredCertificates and keys uploaded to admin panel
Apple Pay: Domains verifiedAll payment domains registered in Apple Developer
Google Pay: Integration checklistCompleted per Google's requirements
Google Pay: Domains verifiedVerified in Google Business Console
Formula 8 hash usedWallet SALE uses email + PASSWORD only

Compliance

ItemDetail
PCI DSS evidenceSAQ D or full assessment (for raw card S2S). Reduced scope for wallet-only.
KYB completeBusiness verification documents submitted and approved
Prohibited MCCs reviewedBusiness model confirmed against prohibited categories
Client agreement signedExecuted with CentaPay

Commercial

ItemDetail
Production credentials receivedSeparate CLIENT_KEY, PASSWORD, PAYMENT_URL for production
Settlement currency confirmedUSD or preferred currency agreed with CentaPay
MID configuredProduction 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.

CallbackRequest signs withCallback verifies with
SALE, cardFormula 1Formula 2
SALE, stored tokenFormula 1, token variantFormula 2
SALE, walletFormula 8Formula 2
CAPTUREFormula 2Formula 2
CREDITVOIDFormula 2Formula 2
VOIDFormula 2the Void signature
CREDIT2CARDFormula 5Formula 6
RECURRING_SALE, RETRYFormula 1Formula 2
CHARGEBACKplatform-initiatedFormula 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.

Technical questions go to [email protected].