2C2P Payment Gateway
Use this skill for 2C2P (PGW v4.x) payment gateway integration work.
Source
Read references/2c2p-api.md first, before giving factual API guidance or writing integration code. It has environments, the four security schemes, the full endpoint catalogue, Payment Token fields, the redirect flow, backend and frontend notification formats, Payment Inquiry, amount rules, the settlement checklist and sandbox data.
Read references/2c2p-direct-api.md for an own checkout UI (Payment Option, Do Payment, Transaction Status, Secure Pay JS, Drop-In UI, Apple Pay, Google Pay, Malaysian channel shapes).
Read references/2c2p-maintenance.md for refund, void, settle, refund status, refund notification, recurring maintenance, card and customer token maintenance, and JWE + JWS key setup.
Read references/2c2p-codes.md for response codes, Malaysian channel, FPX and agent codes, cut-off times and test cards.
Read references/2c2p-mobile-sdk.md for Android, iOS, Flutter and React Native apps; references/2c2p-quickpay-payout.md for payment links and payouts; references/2c2p-batch-recon.md for SFTP batch, reconciliation, SoftPOS, plugins and SNAP.
Read references/account-setup.md for onboarding, keys, sandbox, pricing and settlement questions, and references/source-map.md to find the official page behind any fact.
Core Workflow
- Identify environment (sandbox or production) and surface: hosted redirect, Direct API, Drop-In UI, mobile SDK, plugin, QuickPay link, recurring plan, payout or SoftPOS.
- Confirm credentials and setup: Merchant ID, Secret Key, enabled channels, return URLs, and for maintenance the RSA key pair and 2C2P public key.
- Create a local pending order with a unique
invoiceNo, expected amount and currency before calling 2C2P. - Call Payment Token server-side with a JWT HS256
{"payload"}body. Continue only ifrespCodeis0000. - Redirect to
webPaymentUrl, or run the Direct API / SDK flow with thepaymentToken. - Treat the frontend return (
paymentResponse, unsigned base64url) and Transaction Status as UX only. - Verify the backend notification JWT with the Secret Key, then check merchant, invoice, amount, currency and
respCode. - Settle idempotently. Use Payment Inquiry for missing, late or doubtful results.
- Run refunds, voids and captures through Payment Maintenance with JWE + JWS, with idempotency and status checks.
Core Facts
- PGW API hosts: sandbox
https://sandbox-pgw.2c2p.com, productionhttps://pgw.2c2p.com. - Payment Token:
POST /payment/4.5/paymentToken(docs pages) or/payment/4.3/paymenttoken(OpenAPI 4.3). Use one version consistently. - Payment Inquiry:
POST /payment/4.5/paymentInquirywithmerchantIDplusinvoiceNoorpaymentToken. - PGW signing: JWT HS256 with the merchant Secret Key string; request and response bodies are
{"payload":"<jwt>"}. - Payment Token mandatory fields:
merchantID,invoiceNo,description,amount,currencyCode.paymentTokenis valid 30 minutes. amountis a decimal in ringgit (150.00), not sen;currencyCodeisMYR.- Backend notification: POST
{"payload":"<JWT>"}tobackendReturnUrl(or the portal default); claims match Payment Inquiry. - Success is
respCode0000;0001pending; flow code2000means "completed, check backend or inquire". - Payment Maintenance:
https://demo2.2c2p.com/PaymentAction/2.0/action(sandbox),https://t.2c2p.com/PaymentAction/2.0/action(production); XMLPaymentProcessRequestv4.6, JWE RSA-OAEP + A256GCM with the 2C2P public key, then JWS PS256 with the merchant private key,text/plain. processType:Iinquiry,Rrefund,RSrefund status,Vvoid,Ssettle. MaintenancerespCode00is success.- FPX uses channel
123, agent channelWEBPAY, agent codesMY...(for exampleMYM2U); legacyFPX_*codes must be migrated. - Malaysian sandbox demo merchant
JT07(MYR); FPX test banksMYSBIA,MYSBIB,MYSBIC; test Visa4111111111111111, OTP123456.
Critical Rules
- Keep the Secret Key and merchant private key server-side only; never in browser, app or repo.
- Do not mark paid from the frontend return, Transaction Status, Do Payment response, SDK result, iframe
postMessageor QR display. - Verify every JWT with HS256 and reject other algorithms; verify JWS PS256 before decrypting maintenance responses.
- Match
merchantID,invoiceNo,amount,currencyCodeandrespCodeagainst the stored order before settling. - Make notification handling and settlement idempotent; notifications can repeat or arrive out of order.
- Never reuse an
invoiceNo; it triggers duplicate-invoice errors (9015,5005). - Refund only settled transactions; void only same day before the acquirer cut-off; send
idempotencyIDand checkRS/Ibefore retrying. - Treat REFUND_PENDING (
RP, code 42) as unfinished; poll refund status or verify thenotifyURLcallback. - Do not quote fees or settlement times; 2C2P publishes no Malaysian rate card.
- Say "Not documented in official docs" for rate limits, notification IP ranges and retry schedules instead of guessing.
Completion Criteria
A 2C2P integration is done only when:
- Payment Token runs server-side with JWT HS256, the correct host and one consistent API version.
- The browser or app only carries
webPaymentUrlorpaymentToken; no secrets reach the client. - The backend notification handler verifies the JWT and checks merchant, invoice, amount, currency and
respCode. - Payment Inquiry is used as the fallback for missing or doubtful results, with the same checks.
- Settlement, refunds and voids are idempotent and logged.
- Tests cover a forged or wrong-key JWT, a wrong amount or currency, a duplicate notification, a pending (
0001) result, a failed result, an expired token and a successful payment. - Deployment docs list Merchant ID, Secret Key, return URLs, maintenance keys and separate sandbox and production values.
Loophole Review Loop
When asked whether a 2C2P strategy is "100% confident", run this loop until no factual gaps remain:
- List trust boundaries: browser return, iframe, Drop-In UI, mobile SDK, Payment Token creator, PGW API, backend notification receiver, Payment Inquiry, maintenance client, key storage, database, fulfilment job, refund job, merchant portal settings and enabled channels.
- Check bypasses: forged
paymentResponse, unsigned oralg:noneJWT, wrong Secret Key, sandbox and live mix, 4.3 and 4.5 path mix, reusedinvoiceNo, wrong amount or currency, Transaction Status used for settlement, duplicate or late notification, pending FPX or wallet marked failed too early, refund retried after timeout, void after cut-off, legacyFPX_*agent codes, and a plugin notification blocked by the store firewall. - Add fixes: server-side token creation, local pending order first, strict JWT verification, amount, currency and invoice checks, durable event log, idempotency keys, Payment Inquiry fallback, maintenance status checks, separate environment config, and channel checks with Payment Option.
- Re-read the relevant sections of
references/2c2p-api.md,references/2c2p-maintenance.mdandreferences/2c2p-codes.mdfor any gap. - State remaining uncertainty where it depends on the merchant profile version, enabled channels, acquirer support for card-on-file, settlement terms, or anything marked "Not documented in official docs".


