Fasspay Payment Gateway
Use this skill for Fasspay (Soft Space) payment integration work.
Source
Read references/fasspay-api.md before giving factual guidance or writing code for online checkout. It holds the endpoint catalogue, environments, request signing, the create-payment fields, the callback format and its verification, status codes, requery, void, capture, and known gaps. Its facts come from the official Fasspay for WooCommerce plugin source (v1.0.14, published by Fasspay on WordPress.org), because Fasspay publishes no public e-commerce API document.
Read references/fasspay-in-person.md for card-present work: Fasstap SDK (tap on phone), Fasstap App-to-App, Smart Terminal SDK, and the provisioning Web API from developers.softspace.com.my. Field-level tables live in references/fasspay-fasstap-sdk.md, references/fasspay-app-to-app.md, references/fasspay-smart-terminal.md, and error codes in references/fasspay-fasstap-codes.md.
Read references/account-setup.md for registration, credentials, UAT vs production, payment method activation, settlement, and pricing links.
Read references/source-map.md to pick the right official page and to see coverage.
Core Workflow
- Identify surface: online checkout (e-commerce API), Fasstap SDK, Fasstap App-to-App, or Smart Terminal.
- Identify environment: UAT
https://wallet-uat.fasspay.comor productionhttps://ecom.fasspay.com. - Confirm credentials from Fasspay: Merchant ID (
mid) and the shared Secret Key for that environment. - Create a local pending payment with a unique
trxRefNoper attempt, expected amount in sen, and currencyMYR. - Call
POST /v3/ecom/webInitiateRequestserver-side with themessagesenvelope,X-Timestamp, andX-Signature. - Read
paymentURLfrom the JSON string in the responsemessagesfield and redirect the customer there. - Treat
responsePageURLas browser UX only; never mark paid from it. - On the
backendURLcallback, verifyX-Signatureover the raw body plusX-Timestamp, enforce the 300 second window, then parse. - Settle idempotently on
statusId100,104(or legacy00) only aftertrxRefNo, amount, currency, and environment match. - Use
POST /v3/ecom/checkTransactionStatusas a fallback when a callback is missing or unclear.
Core Facts
- Production API base:
https://ecom.fasspay.com. UAT base:https://wallet-uat.fasspay.com. - All e-commerce calls are
POSTJSON over HTTPS under/v3/ecom/. - Signature:
X-Signature = base64(HMAC-SHA256(secretKey, bodyJson + X-Timestamp)), headerX-Signature-Alg: HmacSHA256,X-Timestampin Unix seconds. - The secret is used as the literal string key; do not base64-decode it.
- Sign the exact bytes you send; the plugin uses
json_encode(..., JSON_UNESCAPED_SLASHES). - Create payment wraps fields in
{"messages": "<JSON string>", "sandboxMode": <bool>}. amountis an integer in sen (RM 1.00 is100). OnlyMYRis accepted by the plugin.- Callback headers:
X-Signature(orX-Fasspay-Signature) andX-Timestamp; body may be{"messages": "<JSON string>"}. - Paid statuses:
100APPROVED,104SETTLED, legacy00. Failed:102DECLINED, legacy02. Voided/cancelled:107, legacy03. Refunded:06. - Pending statuses:
101PROCESSING,106OPENED (pending from bank),111PROCESSING_VOID,123PROCESSING_CAPTURE,115PENDING_APPROVAL (FPX B2B),122AUTHORIZED (pre-auth). transactionMethodin callbacks:0FPX,5card,34e-wallet,35DuitNow QR.- Void:
POST /v3/ecom/auth/void; success isstatusId107; the plugin blocks FPX voids and voids after the order's calendar day. - No public refund-initiate endpoint is documented; refunds arrive as callback status
06. - In-person
statusId/response codes differ from e-commerce codes (for example102is VOIDED in Fasstap). Never share one status map across surfaces. - Public UAT credentials are embedded in the official plugin (values in
references/account-setup.md, sandbox only); production MID and secret come from Fasspay at onboarding.
Critical Rules
- Keep the Secret Key server-side only. Never call the e-commerce API from a browser or mobile client.
- Verify the callback signature on the raw request body before JSON parsing, using constant-time comparison.
- Reject callbacks whose
X-Timestampis more than 300 seconds from server time; reject a missing signature. - Check amount, currency,
trxRefNo, and environment yourself. The official plugin does not compare callback amount to order total. - Generate a new
trxRefNoper attempt and store it; ignore non-funds callbacks from superseded attempts. - Treat a second funds-moved callback (
00,100,104,122) on an already-paid order as a duplicate payment for manual refund or void. - Never let a late decline (
02,102) undo a recorded payment. - Return HTTP 200 only after the callback is durably recorded; return 401 for bad signatures and 400 for bad JSON.
- Use UAT and production MID, secret, base URL, and
sandboxModeas one set. Do not mix them. - Do not copy in-person status codes into e-commerce handlers.
Completion Criteria
A Fasspay integration is done only when:
webInitiateRequestruns server-side with correct envelope,X-Timestamp, andX-Signature.- The customer is redirected to
paymentURL; the return page does not fulfil. backendURLis public HTTPS and verifiesX-Signatureover raw body plus timestamp.- Settlement checks
trxRefNo,statusId, amount, currency, environment, and attempt. - Duplicate callbacks, superseded attempts, and status requery are idempotent.
- Tests cover bad signature, stale timestamp, duplicate callback, wrong amount, declined, pending (
101,106,115), and approved. - Deployment docs list
FASSPAY_MID,FASSPAY_SECRET_KEY,FASSPAY_BASE_URL,FASSPAY_SANDBOX, the callback URL, and the return URL.
Loophole Review Loop
When asked whether a Fasspay strategy is "100% confident", run this loop until no factual gaps remain:
- List trust boundaries: browser return page, Fasspay hosted page, backend initiator, Fasspay API, callback receiver, raw-body reader, database, fulfilment job, void job, admin tooling.
- Check bypasses: forged callback, signature over re-encoded JSON, base64-decoded secret, stale or replayed timestamp, UAT/production mix, reused
trxRefNo, wrong amount unit, late decline, duplicate capture, FPX void attempt, next-day void, out-of-order attempt callbacks. - Add fixes: raw-body HMAC, constant-time compare, 300 second window, per-attempt
trxRefNo, amount in sen check, idempotency key ontransactionId|statusId|trxRefNo, requery fallback, separate env config. - Re-read
references/fasspay-api.mdsections relevant to any gap. - State remaining uncertainty: callback amount unit,
checkTransactionStatusresponse shape,refundAmountunit, meaning oftransactionMethod100in requests, IP allowlists, rate limits, and anything confirmable only with Fasspay support.


