API reference

FavePay Omni (FPO)

Accept payments online or in-store with Fave. Use these endpoints to create QR codes, look up transactions, cancel unpaid QRs, refund, and receive payment status via webhook.

MY SG ID
All paths are under /api/fpo/v1/<country_code>/.... Use my, sg, or id for the country.
Typical flow: authenticate → create a payment (QR or merchant scan) → handle the webhook → look up or acknowledge as needed → cancel the QR if unpaid, or refund if required.

Authentication

Sign every request with HMAC-SHA256 using the secret key Fave issued for your integration. Some setups use an outlet-specific secret instead, so use the key Fave confirms for your account.

Build the signing string from URL-encoded request fields. Always exclude sign and country_code. Also exclude:

  • outlet_id when the path includes /outlets/ (list transactions)
  • id when acknowledging via /transactions/<id>
  • details on merchant scan (metadata is not part of the signature)

Field order matters. Do not sort keys alphabetically; encode fields in the same order you send them. Nested objects flatten to bracket form (for example shopper_details[email]=…).

Signing string example
omni_reference=PL-0001&total_amount_cents=1000&app_id=a3osyvuayt&outlet_id=11637&format=txt
Example request body
{
  "omni_reference": "PL-0001",
  "total_amount_cents": 1000,
  "app_id": "a3osyvuayt",
  "outlet_id": 11637,
  "format": "txt",
  "sign": "4e23af6ca0c0831e9fe3524ac7943d5e8860f0843a343f7c9c4a3f172b408972"
}
Unknown app_id typically returns 404 resource_not_found. Invalid signature returns 401 Unauthorized.

Payment flows

These sequence diagrams match the three API implementation flows in the FavePay Omni documentation: dynamic QR online, dynamic QR offline, and static QR. Actors: Vendor (integrating system), Customer, Fave Omni API, and where needed Fave app or Payment page.

1. Dynamic QR online (web_url)

E-commerce / hosted checkout. Customer pays on Fave’s payment page, then returns to the Vendor redirect_url.

sequenceDiagram
  autonumber
  actor Customer
  participant Vendor as Vendor
  participant Fave as Fave Omni API
  participant Pay as Payment page

  Customer->>Vendor: Checkout / choose Fave
  Vendor->>Fave: POST /qr_codes (web_url)
  Fave-->>Vendor: Hosted payment URL
  Vendor->>Customer: Redirect to payment URL
  Customer->>Pay: Complete payment
  Pay-->>Customer: Return via redirect_url
  Fave->>Vendor: Webhook (successful or rejected)
  Vendor-->>Fave: HTTP under 400
  Note over Vendor,Fave: Optional GET /transactions
  Vendor->>Customer: Show order result

2. Dynamic QR offline (txt / base64)

Retail point of sale. The Vendor Client displays a one-time QR; the customer scans it with the Fave app.

sequenceDiagram
  autonumber
  actor Customer
  participant Vendor as Vendor
  participant Fave as Fave Omni API
  participant App as Fave app

  Customer->>Vendor: Start payment
  Vendor->>Fave: POST /qr_codes (txt or base64)
  Fave-->>Vendor: QR payload or image
  Vendor->>Customer: Show QR
  Customer->>App: Scan QR and pay
  App->>Fave: Payment completed
  Fave->>Vendor: Webhook (successful or rejected)
  Vendor-->>Fave: HTTP under 400
  Note over Vendor,Fave: Optional GET /transactions
  Vendor->>Customer: Confirm sale

3. Static QR

Vendor fetches one combined static QR for the outlet (POST /qr_codes/static). Response includes supported_apms (e.g. favepay, wcp, paynow, alipay) for logos. Customer scans and pays with any listed wallet; amount is entered on the phone. After the webhook, the Vendor must call Acknowledge. Static QR is not auto-acknowledged.

sequenceDiagram
  autonumber
  actor Customer
  participant Vendor
  participant Fave

  Vendor->>Fave: POST /qr_codes/static (outlet_id, app_id, sign[, format])
  Fave->>Fave: Resolve enabled APMs / Assemble combined EMVCo string
  Fave-->>Vendor: 200 { code, format, supported_apms }
  Note over Vendor,Fave: format = txt|base64 encoding only\nsupported_apms = APMs in the QR
  Vendor->>Customer: Display static QR (and show icons)
  Customer->>Fave: Scan QR, enter amount, pay (Fave / WeChat / PayNow / Alipay)
  Fave->>Vendor: POST callback_url (successful)
  Vendor-->>Fave: HTTP 200
  Vendor->>Fave: POST /transactions/{id}
  Fave-->>Vendor: 200 transaction
  Vendor->>Customer: Receipt / close sale
  opt Webhook missed
    Vendor->>Fave: GET /outlets/{outlet_id}/transactions (ack=false)
    Fave-->>Vendor: Unacknowledged list
    Vendor->>Fave: POST /transactions/{id}
  end
After a successful webhook response, Fave may auto-acknowledge the payment for dynamic QR flows. Static QR still requires the Acknowledge API (Step 8). Always verify webhook sign before trusting the payload. Fetch static QR with POST /qr_codes/static (sign in the request body — do not use GET query params for auth).

QR code formats

The format you send on Request a QR code controls what code returns and how the customer pays. Choose the format that matches your channel (online checkout, POS display, or a specific wallet QR).

Default is base64 if you omit format.

format What you get Typical use How payment happens
txt Plaintext QR payload. You encode it into a QR image yourself. POS that can generate QR images Customer scans the displayed QR with the Fave app (dynamic offline flow).
base64 PNG QR image as a Base64 string. Render with a data URL, or decode to a file. POS / apps that cannot build QR images Same as txt: customer scans with the Fave app (dynamic offline flow).
web_url Hosted Fave payment URL (tokenized gateway link). Online / e-commerce checkout Customer opens the URL, pays on Fave’s page, then returns via redirect_url (dynamic online flow).
favepay FavePay QR payload. In-store FavePay Customer scans with the Fave app (dynamic offline flow).
grab GrabPay QR payload. GrabPay acceptance Customer scans with Grab / GrabPay.
paynow SGQR containing PayNow payload only. Singapore PayNow Customer pays via a PayNow-capable banking app.
alipay Alipay QR payload. Alipay acceptance Customer scans with Alipay.
wcp SGQR containing Fave payload (WeChat Pay can detect it). WeChat Pay Customer scans with WeChat Pay.
shopeepay ShopeePay QR payload. ShopeePay acceptance Customer scans with ShopeePay.
atome Atome QR payload. Atome acceptance Customer scans with Atome.
Pick by channel: online checkout → web_url; in-store Fave app scan → txt, base64, or favepay; wallet-specific QR → grab, paynow, alipay, wcp, shopeepay, or atome. Availability can depend on country and what Fave enabled for your account. Unsupported formats return an error (for example service_not_supported). See Payment flows for the online and offline sequences.

Request a QR code

Creates a single-use QR (or payment URL) for an outlet. Currency follows the country code in the path.

POST
/api/fpo/v1/<country_code>/qr_codes
Request body
{
  "omni_reference": "PL-0001",
  "total_amount_cents": 1000,
  "app_id": "a3osyvuayt",
  "outlet_id": 11637,
  "format": "web_url",
  "redirect_url": "https://partner.example/return",
  "callback_url": "https://partner.example/webhook",
  "sign": "<hmac_sha256_sign>"
}
Sample response
{
  "code": "https://omni.myfave.com/web_views/favepay_online/gateway?omni_ref=<token>",
  "format": "web_url",
  "expires_in": 900
}
code depends on format (see QR code formats): payment URL for web_url, plaintext payload for txt, Base64 PNG for base64, FavePay payload for favepay, or a wallet-specific QR payload. expires_in is seconds until expiry. Default format is base64.
FieldRequiredNotes
omni_referenceRequiredYour unique payment reference. Format [prefix]-[id], max 28 characters. Use the prefix Fave assigned to your integration.
total_amount_centsRequiredAmount in cents (positive integer). Singapore max: 1999900.
app_idRequiredYour integration App ID from Fave.
outlet_idRequiredFave outlet ID for this payment.
formatOptionalSee QR code formats. Default base64. Accepted: txt, base64, web_url, favepay, grab, paynow, alipay, wcp, shopeepay, atome.
redirect_urlOptionalRecommended for web_url so customers return to your site after payment. Fave appends encrypted transaction details as omni_ref. See Omni_ref in redirect URL.
callback_urlOptionalOptional per-payment webhook URL (overrides your default callback when enabled for your account; kept for a few hours).
payment_optionOptionalboth (default), app, or pwa.
expiry_timeOptionalUnix timestamp for QR expiry.
shopper_detailsOptionalObject with optional email, phone, location.
testOptionalWhen true, returns a test page URL in code for dynamic formats only. See Use of test parameter.
signRequiredHMAC-SHA256 signature.

Use of test parameter

When test=true is provided, the API returns a test page URL in the code field so partners can simulate success or failure without the Fave app.

Supported formats: base64, txt, web_url, favepay, and paynow. Wallet-specific formats do not support test mode.

In test mode, the code field is always a test page URL (for example /web_views/favepay_online/test?omni_ref=...), regardless of the requested format.

Partners can simulate a payment success or failure scenario by clicking the corresponding buttons on the test payment page.

Partners can simulate a promo-applied payment by ticking the Promo code applied checkbox on the test payment page. This sends promo_code=true and applies promo fpoms.

Production: Never include the test parameter in a production environment — the test page is blocked there. This mode is strictly reserved for testing purposes. Under normal circumstances, a user would use the Fave app to make payment instead.

Omni_ref in redirect URL

After payment on Fave’s payment page, the customer is redirected back to your site using the redirect_url provided in the QR code request.

Fave appends encrypted transaction details as the omni_ref query parameter:

Redirect URL pattern
<redirect_url>?omni_ref=<encrypted_value>
Example
https://your-site.com/payment/complete?omni_ref=7gxyZxBRE6wARrTJNx5Fe6VH/...

Decrypt omni_ref using your private API key (the same key used to sign API requests).

  • Algorithm: AES-128-CBC
  • Encoding: Base64
Decrypted value example
receipt_id=0871-5110&omni_reference=PL-000023&status=successful&total_amount_cents=1000
FieldDescription
receipt_idFave receipt ID for the payment.
omni_referenceYour payment reference from the QR code request.
statusPayment status (for example successful).
total_amount_centsCharged amount in cents.
This encrypted omni_ref flow applies to standard integrations. Magento, WooCommerce, Jocom, and EasyStore use different redirect formats.

Fetch static QR

Returns one persistent (static) EMVCo / SGQR payload for an outlet. Schemes enabled on the outlet (for example Fave, WeChat Pay via the Fave slot, PayNow, Alipay) are assembled into a single QR string. Unlike Request a QR code, this does not create a payment, does not take an amount or omni_reference, and does not expire.

Status: Planned for partner integration (target Q3). Spec below is the agreed contract for early preparation. Confirm go-live with your Fave technical contact before production use.
POST
/api/fpo/v1/<country_code>/qr_codes/static
Request body
{
  "outlet_id": 11637,
  "app_id": "a3osyvuayt",
  "format": "txt",
  "sign": "<hmac_sha256_sign>"
}
Sample response
{
  "code": "<EMVCo SGQR payload or base64 PNG>",
  "format": "txt",
  "supported_apms": ["favepay", "paynow", "alipay", "wcp"]
}
FieldRequiredNotes
outlet_idRequiredFave outlet ID. Outlet must belong to your app_id.
app_idRequiredYour integration App ID from Fave.
formatOptionalEncoding only. txt (default) = plaintext QR payload string; base64 = PNG image. Not used to select payment methods.
signRequiredHMAC-SHA256 signature. Send in the request body (POST). Do not put sign on the query string.

Which APMs are included is decided by Fave from the outlet’s enabled payment methods. You do not pass APM filters in v1.

Response fields

FieldNotes
codeOne static QR (plaintext or Base64 PNG per request format). Multiple APM payloads may be embedded in the EMVCo string.
formatEcho of encoding: txt or base64.
supported_apmsAPM keys payable via this QR, using the same keys as dynamic QR format values where applicable: favepay, paynow, alipay, wcp. Use for on-screen logos. Only schemes enabled for the outlet and embedded in code are listed.
format vs APMs: On this endpoint, format means encoding only (txt / base64). APM membership is always supported_apms. If a future revision lets partners request a subset of APMs, that will be a new request key — not format. WeChat Pay (wcp) uses the Fave merchant-account slot in the combined SGQR when both are enabled. After payment, handle the webhook and call Acknowledge. If the webhook is missed, list unacknowledged payments with List transactions (ack=false), then acknowledge. See Payment flows → Static QR.

Merchant scan

Charge a customer-presented QR or barcode (your POS scans the customer’s code). Returns a transaction object after the charge attempt.

POST
/api/fpo/v1/<country_code>/merchant_scan
Request body
{
  "omni_reference": "PL-0001",
  "total_amount_cents": 1000,
  "app_id": "a3osyvuayt",
  "outlet_id": 11637,
  "code": "<customer_qr_or_barcode>",
  "callback_url": "https://partner.example/webhook",
  "details": { "order_id": "ORD-1001" },
  "sign": "<hmac_sha256_sign>"
}
Sample response
{
  "id": "FP_792619",
  "receipt_id": "0118-7347",
  "outlet_name": "TTDI Shop",
  "total_amount_cents": "1000",
  "currency": "MYR",
  "outlet_id": "11637",
  "mid": "1166",
  "omni_reference": "PL-0001",
  "status": "successful",
  "status_code": "2",
  "created_at": "2026-07-10T10:15:22.100+08:00",
  "charged_amount_cents": "1000",
  "user_id": "2818771",
  "fpl_transaction": "false"
}
FieldRequiredNotes
omni_referenceRequiredUnique reference, max 28 characters.
total_amount_centsRequiredPositive integer in cents.
app_idRequiredYour integration App ID from Fave.
outlet_idRequiredFave outlet ID for this payment.
codeRequiredCustomer QR or barcode payload.
callback_urlOptionalOptional per-payment webhook URL.
detailsOptionalArbitrary JSON metadata (excluded from signature).
signRequiredHMAC-SHA256 signature over fields excluding details.

Webhooks

Fave posts the transaction object (including sign) to your callback URL when payment status changes. The callback body uses the same fields as Get a transaction, plus sign for verification.

Accepting webhook callback

The webhook callback notifies you of Fave payment status. Two statuses are sent via webhook:

StatusDefinition
successfulPayment has been completed and accepted.
rejectedPayment has been completed but not successful.

Return any HTTP 2XX status from your webhook URL to accept the notification. Accept the callback quickly, then process the payload in the background (for example verify sign, update your order system).

Provide your webhook URL to Fave during the technical kick-off meeting. Alternatively, pass it per payment as callback_url in the Request a QR code API (or on merchant scan when supported).

If your endpoint does not return HTTP 2XX, Fave retries delivery at increasing intervals. Keep your handler idempotent — the same payment may be posted more than once.

Callback body

Sample callback body
{
  "id": "FP_792619",
  "receipt_id": "0118-7347",
  "outlet_name": "TTDI",
  "total_amount_cents": "2100",
  "payment_type": "Credit Card",
  "payment_type_variant": "Visa",
  "currency": "MYR",
  "outlet_id": "1593",
  "mid": "1166",
  "omni_reference": "PL-0001",
  "status": "successful",
  "status_code": "2",
  "created_at": "2021-03-26T18:14:59.698+08:00",
  "campaign_credit_amount_cents": "0",
  "campaign_funded_by": "N/A",
  "aabig_points_used_amount_cents": "0",
  "merchant_cashback_amount_cents": "350",
  "fave_credits_amount_cents": "200",
  "promo_code_value_cents": "0",
  "e_card_credits_used_cents": "0",
  "charged_amount_cents": "1550",
  "cashback_rate": "0.0",
  "merchant_cashback_issued_cents": "0",
  "promo_code": "apicbpartner2",
  "promo_code_cashback_value": "2.00",
  "promo_code_cashback_type": "absolute_cashback",
  "promo_code_cashback_issued_cents": "200",
  "promo_code_cashback_funded_by": "merchant",
  "fave_fees_percentage": "1.0",
  "fave_fees_cents": "18",
  "sst_on_total_fees_cents": "1",
  "merchant_takeback_cents": "1881",
  "user_id": "2818771",
  "fpl_transaction": "false",
  "fpl_fees_percentage": "N/A",
  "fpl_fees_cents": "N/A",
  "fpl_merchant_cashback_reduction_percentage": "N/A",
  "sign": "56f6054ed61a3a3eb3dff2c06c320339044a4562f63f7d53cee0ff010df561a8"
}
FieldDescription
idTransaction ID (max 35 characters). Prefix indicates payment type — see Transaction IDs.
receipt_idFave receipt ID (max 35 characters).
outlet_nameOutlet display name.
total_amount_centsOrder total in cents (string).
payment_typePayment method category (for example Credit Card, Debit Card, DuitNow). Present when payment-method reporting is enabled.
payment_type_variantPayment method variant (for example Visa, MasterCard, Touch N’Go eWallet).
currencyISO currency code (for example MYR).
outlet_idFave outlet ID.
midMerchant ID.
omni_referenceYour payment reference from the original request.
statusWebhook status: successful or rejected. See Accepting webhook callback.
status_codeNumeric status code. See Transaction IDs & statuses.
created_atPayment timestamp (ISO 8601).
campaign_credit_amount_centsCampaign credit redeemed amount.
campaign_funded_byWho funded the campaign credit.
aabig_points_used_amount_centsAABig points redeemed amount.
merchant_cashback_amount_centsMerchant cashback redeemed amount.
fave_credits_amount_centsFave credit redeemed amount.
promo_code_value_centsPromo code discount amount.
e_card_credits_used_centsUser’s eCard membership credits amount.
charged_amount_centsCredit card or e-wallet charged amount.
cashback_rateCashback rate offered by the merchant.
merchant_cashback_issued_centsCashback amount the user earned.
promo_codePromo code used by the user.
promo_code_cashback_valuePromo cashback value.
promo_code_cashback_typePromo cashback type (for example absolute_cashback).
promo_code_cashback_issued_centsPromo cashback amount the user earned.
promo_code_cashback_funded_byWho funded the promo cashback (for example merchant).
fave_fees_percentageFave fee percentage.
fave_fees_centsTotal fee charged by Fave.
sst_on_total_fees_centsGovernment tax on fees (mandated by country).
merchant_takeback_centsTotal amount the merchant receives.
user_idFave unique user ID.
fpl_transactiontrue if this is a FavePay Later transaction.
fpl_fees_percentageFavePay Later fee percentage (when applicable).
fpl_fees_centsFavePay Later fee amount (when applicable).
fpl_merchant_cashback_reduction_percentageFPL merchant cashback reduction percentage (when applicable).
signHMAC-SHA256 signature over the callback fields. See Payload verification.
Most amount fields are returned as strings. Promo and FPL fields may be N/A when not applicable. payment_type / payment_type_variant (and sometimes minimum_fee_applied) appear when Fave has enabled payment-method reporting for your account. shopper_details may appear when your integration supports it. On a successful delivery response (HTTP 2XX), Fave may auto-acknowledge the payment for dynamic QR flows, so you may not need the Acknowledge API unless the callback failed or you use static QR. Expired unpaid QRs can trigger a rejected callback.

Get a transaction

Look up one payment by omni_reference or receipt_id (at least one required). Optional outlet_id must match the payment’s outlet when provided.

If the QR was created but not yet paid, you may receive a pending transaction object with many fields set to null. When looking up by receipt_id, use the same app_id that created the payment.
GET
/api/fpo/v1/<country_code>/transactions
Parameters (provide omni_reference or receipt_id)
{
  "app_id": "a3osyvuayt",
  "omni_reference": "PL-0001",
  "receipt_id": "0118-7347",
  "outlet_id": 11637,
  "sign": "<hmac_sha256_sign>"
}
Sample response
{
  "id": "FP_792619",
  "receipt_id": "0118-7347",
  "outlet_name": "TTDI Shop",
  "total_amount_cents": "2100",
  "payment_type": "Credit Card",
  "payment_type_variant": "Visa",
  "currency": "MYR",
  "outlet_id": "1593",
  "mid": "1166",
  "omni_reference": "PL-0001",
  "status": "successful",
  "status_code": "2",
  "created_at": "2021-03-26T18:14:59.698+08:00",
  "campaign_credit_amount_cents": "0",
  "campaign_funded_by": "N/A",
  "aabig_points_used_amount_cents": "0",
  "merchant_cashback_amount_cents": "350",
  "fave_credits_amount_cents": "200",
  "promo_code_value_cents": "0",
  "e_card_credits_used_cents": "0",
  "charged_amount_cents": "1550",
  "cashback_rate": "0.0",
  "merchant_cashback_issued_cents": "0",
  "promo_code": "N/A",
  "promo_code_cashback_value": "N/A",
  "promo_code_cashback_type": "N/A",
  "promo_code_cashback_issued_cents": "0",
  "promo_code_cashback_funded_by": "N/A",
  "fave_fees_percentage": "1.0",
  "fave_fees_cents": "18",
  "sst_on_total_fees_cents": "1",
  "merchant_takeback_cents": "1881",
  "user_id": "2818771",
  "fpl_transaction": "false",
  "fpl_fees_percentage": "N/A",
  "fpl_fees_cents": "N/A",
  "fpl_merchant_cashback_reduction_percentage": "N/A"
}
FieldRequiredNotes
app_idRequiredYour integration App ID from Fave.
omni_referenceOptionalAt least one of omni_reference or receipt_id is required.
receipt_idOptionalAt least one of omni_reference or receipt_id is required. Use the same app_id that created the payment.
outlet_idOptionalWhen provided, must match the payment’s outlet.
signRequiredHMAC-SHA256 signature.
Most amount fields are returned as strings. payment_type / payment_type_variant (and sometimes minimum_fee_applied) appear when Fave has enabled payment-method reporting for your account. shopper_details may appear when your integration supports it.

Acknowledge a transaction

Marks a payment as acknowledged on your side. Use this for static-QR flows, or when a webhook was missed and the payment was not auto-acknowledged.

id in the path is the transaction id prefix form: FP_, RPP_, GRAB_, PAYNOW_, or EXT_.

POST
/api/fpo/v1/<country_code>/transactions/<id>
Request body
{
  "omni_reference": "PL-0001",
  "app_id": "a3osyvuayt",
  "outlet_id": 11637,
  "sign": "<hmac_sha256_sign>"
}
Sample response
{
  "id": "FP_792619",
  "receipt_id": "0118-7347",
  "outlet_name": "TTDI Shop",
  "total_amount_cents": "2100",
  "currency": "MYR",
  "outlet_id": "1593",
  "mid": "1166",
  "omni_reference": "PL-0001",
  "status": "successful",
  "status_code": "2",
  "created_at": "2021-03-26T18:14:59.698+08:00",
  "charged_amount_cents": "1550",
  "merchant_takeback_cents": "1881",
  "user_id": "2818771",
  "fpl_transaction": "false"
}
FieldRequiredNotes
id (path)RequiredTransaction ID with prefix: FP_, RPP_, GRAB_, PAYNOW_, or EXT_. Excluded from signature.
omni_referenceRequiredYour payment reference.
app_idRequiredYour integration App ID from Fave.
outlet_idRequiredFave outlet ID for this payment.
signRequiredHMAC-SHA256 signature. Path id is excluded from signature.

Cancel a QR payment

Invalidates an unpaid QR so the customer can no longer pay with it. Use when an order is abandoned or the amount changes before payment completes. This applies to QR flows only; use Refund after a successful payment.

POST
/api/fpo/v1/<country_code>/transactions/cancel
Request body
{
  "omni_reference": "PL-0001",
  "app_id": "a3osyvuayt",
  "outlet_id": 11637,
  "sign": "<hmac_sha256_sign>"
}
Sample response (accepted)
{
  "cancellation_status": "accepted"
}
Sample response (rejected)
{
  "cancellation_status": "rejected",
  "error": "QR_PAID",
  "error_description": "Payment has been received. QR cannot be cancelled. Query the transaction with omni_reference.",
  "omni_reference": "PL-0001"
}
FieldRequiredNotes
omni_referenceRequiredThe reference used when creating the QR.
app_idRequiredYour integration App ID from Fave.
outlet_idOptionalWhen provided, must match the outlet for this payment.
signRequiredHMAC-SHA256 signature.
Accepted (200): the QR is cancelled. Pending or processing payments are marked rejected. If no payment record exists for omni_reference, the API still returns accepted (safe to retry).

Rejected (409): cancellation is not allowed. Response includes cancellation_status: "rejected", an error code, error_description, and omni_reference.
errorMeaning
QR_PAIDPayment received (including acknowledged). Query the transaction instead.
QR_CANCELLEDQR was already cancelled.
QR_REFUNDEDPayment was refunded. QR cannot be cancelled.

Wrong app_id for the payment → 404 resource_not_found. A cancelled QR may trigger a rejected webhook if one was configured at QR creation.

List transactions

Returns recent transactions for an outlet as a JSON array. Use timestamp and limit to narrow results.

GET
/api/fpo/v1/<country_code>/outlets/<outlet_id>/transactions
Parameters
{
  "app_id": "a3osyvuayt",
  "limit": 20,
  "ack": true,
  "timestamp": 1720512000,
  "sign": "<hmac_sha256_sign>"
}
Sample response
[
  {
    "id": "FP_792619",
    "receipt_id": "0118-7347",
    "outlet_name": "TTDI Shop",
    "total_amount_cents": "2100",
    "currency": "MYR",
    "outlet_id": "1593",
    "mid": "1166",
    "omni_reference": "PL-0001",
    "status": "successful",
    "status_code": "2",
    "created_at": "2021-03-26T18:14:59.698+08:00",
    "charged_amount_cents": "1550",
    "merchant_takeback_cents": "1881",
    "user_id": "2818771",
    "fpl_transaction": "false"
  },
  {
    "id": "FP_792620",
    "receipt_id": "0118-7348",
    "outlet_name": "TTDI Shop",
    "total_amount_cents": "1500",
    "currency": "MYR",
    "outlet_id": "1593",
    "mid": "1166",
    "omni_reference": "PL-0002",
    "status": "successful",
    "status_code": "2",
    "created_at": "2021-03-26T19:02:11.120+08:00",
    "charged_amount_cents": "1500",
    "merchant_takeback_cents": "1470",
    "user_id": "2819002",
    "fpl_transaction": "false"
  }
]
FieldRequiredNotes
outlet_id (path)RequiredFave outlet ID. Excluded from signature.
app_idRequiredYour integration App ID from Fave.
limitOptionalMax results to return (max 1000). See defaults below.
timestampOptionalUnix timestamp. Must not be earlier than ~31 days.
ackOptionalDefault true (all payments). Set false for unacknowledged only.
signRequiredHMAC-SHA256 signature. Path outlet_id is excluded from signature.
Defaults & limits: if both limit and timestamp are omitted → last 10 since 24 hours ago. If only limit is set → since 30 days ago. timestamp must not be earlier than ~31 days. Max limit is 1000. ack defaults to true (return all payments in range). Set ack=false to return only unacknowledged payments. Empty result → 404 with error: "error" and description No records were found that match your query. Response is a bare array (not wrapped in a transactions key).

Refund a transaction

Refunds a successful payment. Set status to refunded. Optional partial_refund_cents for a partial refund.

POST
/api/fpo/v1/<country_code>/transactions
Request body
{
  "omni_reference": "PL-0001",
  "app_id": "a3osyvuayt",
  "status": "refunded",
  "partial_refund_cents": 500,
  "sign": "<hmac_sha256_sign>"
}
Sample response
{
  "id": "FP_792619",
  "receipt_id": "0118-7347",
  "outlet_name": "TTDI Shop",
  "total_amount_cents": "2100",
  "refund_amount_cents": "500",
  "currency": "MYR",
  "outlet_id": "1593",
  "mid": "1166",
  "omni_reference": "PL-0001",
  "status": "refunded",
  "status_code": "5",
  "created_at": "2021-03-26T18:14:59.698+08:00",
  "charged_amount_cents": "1550",
  "fave_fees_cents": "18",
  "sst_on_total_fees_cents": "1",
  "merchant_takeback_cents": "1881",
  "user_id": "2818771",
  "fpl_transaction": "false",
  "fpl_fees_percentage": "N/A",
  "fpl_fees_cents": "N/A",
  "fpl_merchant_cashback_reduction_percentage": "N/A"
}
FieldRequiredNotes
omni_referenceRequiredPayment reference to refund.
app_idRequiredYour integration App ID from Fave.
statusRequiredMust be refunded.
partial_refund_centsOptionalPartial refund amount in cents. Cannot exceed charged_amount_cents. Not supported for DuitNow or PayNow.
signRequiredHMAC-SHA256 signature.
Refund window: Refunds are typically allowed only on the same calendar day as the payment (stale_transaction after that). Some merchants may have a different policy window. Partial refunds cannot exceed charged_amount_cents, and are not supported for DuitNow or PayNow. If already refunded, the API returns the transaction object with HTTP 200 (not an error body).

Transaction IDs & statuses

Transaction id values use a type prefix:

PrefixPayment type
FP_FavePay / in-app payment
RPP_DuitNow
GRAB_Grab
PAYNOW_PayNow
EXT_External wallet or other payment method

Common payment status / status_code values (FavePay / in-app):

statusstatus_code
pending_payment0
payment_processing1
successful2
disputed3
rejected4
refunded5

Payment type fields

Transaction responses may include payment_type and payment_type_variant so you can show how the customer paid. For Fave in-app payments these fields are returned when payment-method reporting is enabled for your account.

Common values
Fave in-app: type and variant from the payment method used (when enabled)
DuitNow: payment_type="DuitNow", variant=bank name or BIC
Grab: payment_type="grab", variant from Grab payment method
PayNow: type and variant from PayNow payment method details
Other wallets: payment_type=provider name, variant from channel when available

Payload verification

The value of sign in webhook callbacks is computed using the HMAC-SHA256 algorithm. To verify payload integrity, generate an HMAC-SHA256 hash using your private API key (secret key) from Fave together with the URL-safe encoded content body of the payload on your side, then compare it with the sign value in the callback payload.

Build the signing string from all payload fields in the exact order received, excluding sign. Use URL encoding for values, and replace spaces with + rather than %20.

This is a sample transaction and values might not be entirely accurate. Always generate sign from all fields in the actual payload you receive.
Example private API key
d25f1p1zf6ww8eja
Example payload
{
  "id": "FP_792619",
  "receipt_id": "0118-7347",
  "outlet_name": "TTDI Shop",
  "total_amount_cents": "2100",
  "currency": "MYR",
  "outlet_id": "1593",
  "mid": "1166",
  "omni_reference": "PL-0001",
  "status": "successful",
  "status_code": "2",
  "created_at": "2021-03-26T18:14:59.698+08:00",
  "campaign_credit_amount_cents": "0",
  "campaign_funded_by": "N/A",
  "aabig_points_used_amount_cents": "0",
  "merchant_cashback_amount_cents": "350",
  "fave_credits_amount_cents": "200",
  "promo_code_value_cents": "0",
  "e_card_credits_used_cents": "0",
  "charged_amount_cents": "1550",
  "cashback_rate": "0.0",
  "merchant_cashback_issued_cents": "0",
  "promo_code": "apicbpartner2",
  "promo_code_cashback_value": "2.00",
  "promo_code_cashback_type": "absolute_cashback",
  "promo_code_cashback_issued_cents": "200",
  "promo_code_cashback_funded_by": "merchant",
  "fave_fees_percentage": "1.0",
  "fave_fees_cents": "18",
  "sst_on_total_fees_cents": "1",
  "merchant_takeback_cents": "1881",
  "user_id": "2818771",
  "fpl_transaction": "false",
  "fpl_fees_percentage": "N/A",
  "fpl_fees_cents": "N/A",
  "fpl_merchant_cashback_reduction_percentage": "N/A",
  "sign": "fc12259055f146e8bf0b587cbd8dbb9283e4db6a525243bc608e5762e43c6b29"
}
Signing string (exclude sign)
id=FP_792619&receipt_id=0118-7347&outlet_name=TTDI+Shop&total_amount_cents=2100&currency=MYR&outlet_id=1593&mid=1166&omni_reference=PL-0001&status=successful&status_code=2&created_at=2021-03-26T18%3A14%3A59.698%2B08%3A00&campaign_credit_amount_cents=0&campaign_funded_by=N%2FA&aabig_points_used_amount_cents=0&merchant_cashback_amount_cents=350&fave_credits_amount_cents=200&promo_code_value_cents=0&e_card_credits_used_cents=0&charged_amount_cents=1550&cashback_rate=0.0&merchant_cashback_issued_cents=0&promo_code=apicbpartner2&promo_code_cashback_value=2.00&promo_code_cashback_type=absolute_cashback&promo_code_cashback_issued_cents=200&promo_code_cashback_funded_by=merchant&fave_fees_percentage=1.0&fave_fees_cents=18&sst_on_total_fees_cents=1&merchant_takeback_cents=1881&user_id=2818771&fpl_transaction=false&fpl_fees_percentage=N%2FA&fpl_fees_cents=N%2FA&fpl_merchant_cashback_reduction_percentage=N%2FA

Generate an HMAC-SHA256 hash using the private API key as the secret and the signing string above as the message. For this example, the generated sign is fc12259055f146e8bf0b587cbd8dbb9283e4db6a525243bc608e5762e43c6b29.

Errors

Error responses use error and error_description.

Example
{
  "error": "validation",
  "error_description": "Omni reference already exists. Please provide unique omni reference."
}
HTTPerrorMeaning
400validation / stale_transactionInvalid params, or refund outside the allowed window.
401UnauthorizedInvalid signature, or outlet not linked to this app_id.
409QR_PAID / QR_CANCELLED / QR_REFUNDEDCancel rejected — payment already received, cancelled, or refunded. Body includes cancellation_status: "rejected".
404resource_not_foundUnknown app_id, or missing transaction/outlet.
404errorEmpty transaction history for the query window.
422provider / format codesQR format not supported, amount limit, or payment provider rejection.
500internal_error / unexpected_errorUnexpected server failure.
Already-refunded payments return HTTP 200 with the transaction object (not an error). Named codes you may also see include failed_request and already_refunded (handled as success body).

Support

Need credentials, sandbox access, or help with an integration issue? Contact your Fave technical contact.

Platform-specific checkout integrations (for example certain e-commerce plugins) are separate from the core Omni REST endpoints above. Ask Fave if your integration needs them.