Weav Docsv1

API reference / Payments

Create a payment

POST/v1/payments

Creates a payment on one channel and returns what the customer does next (next_action): scan a QR code, go to a checkout page, or pay at a counter with a payment code.

With a test key, the checkout page is Weav's test checkout, where you pay, decline or expire the payment. Live payments run through the providers.

Never treat a redirect to your success_url as proof of payment. Wait for the PAYMENT_COMPLETED webhook, or read the payment with GET.

What your customer does next

By default every payment comes back as a payment link: send your customer to next_action.checkout_url, Weav’s payment page. Weav sets the payment up with the provider when your customer opens it, so expires_at starts as the link’s lifetime (24 hours) and becomes the provider’s window (for example 15 minutes for a QR Ph code) from that moment. For QR Ph the page shows the code and how-to-pay steps for their bank or e-wallet app (set qr_ph_app to start with one). The QR Ph and Pay & Go examples ask for the raw QR string or payment code instead, with "next_action_format": "DIRECT".

Your customer’s name. Weav needs it on every payment, for anti-money-laundering and fraud checks. Send it in customer.name if you have it. If you don’t, leave customer out: Weav’s payment page asks your customer before anything is set up. With DIRECT there’s no Weav page, so customer.name is required.

Webhooks for this payment. They go to your webhook URL. To send one payment’s webhooks somewhere else, set webhook_url on it.

QR Ph, shown by you

With the raw string, render qr_string as a QR code and show the steps in next_action.instructions. Any QR Ph bank or e-wallet app can scan it. A QR Ph code expires 15 or 60 minutes after it’s made, depending on your account’s QR Ph provider; expires_at has the exact time.

Lay it out the QR Ph way, with the QR Ph symbol in the center: bank and e-wallet apps expect it, so a code that’s off may not scan. See Showing a QR Ph code for the exact layout and a sample.

Redirect: GCash, Maya and cards

Send your customer to next_action.checkout_url. After they pay or cancel there, they come back through Weav first: Weav checks the result with the provider right away, then sends them to your success_url (paid) or cancel_url (failed, expired or canceled). Both are optional: without them, your customer stays on Weav’s result page. If the provider is still confirming, they see a Weav page that updates by itself. Always rely on the webhook or GET /v1/payments/{reference_id} for the final status, not on which URL they land on.

A GCash payment expires 10 minutes after it’s created, Pay with Maya after 15 minutes and a card payment after 60.

Mobile apps. The GCash page has an “Open in GCash” button that uses a gcash:// link. If you load checkout_url in a WebView, hand gcash:// links to the operating system. On Android, use shouldOverrideUrlLoading. On iOS, use decidePolicyForNavigationAction. Otherwise the customer sees an unknown-scheme error.

Over the counter

Give the customer the payment_code. At a Pay & Go kiosk they choose Eplayment on the screen, enter the code and pay in cash. With PALAWANPAY and BAYAD they go to a Palawan or Bayad counter, pay to Eplayment and show the code. Counter payments expire after 48 hours.

Headers

  • AuthorizationstringRequired
    Bearer plus your API key. See Authentication.
  • Idempotency-Keystring
    Optional. A unique value per new payment, such as a UUID. Retrying with the same key and body returns the stored response; a different body returns 409. Without it, your external_reference_id is the key.
    Up to 255 characters

Body

JSON, with Content-Type: application/json.

  • channelstring
    Required, unless you send payment_method_id. One of QR_PH, GCASH, MAYA, CARD, PAY_AND_GO, PALAWANPAY, BAYAD. The channel must be on for your account, or the response is 422 (4220101).
    One of: QR_PH GCASH MAYA CARD PAY_AND_GO PALAWANPAY BAYAD
  • payment_method_idstring | null
    Charge a saved payment method instead (auto-debit), with no payer present. Leave out channel and customer. Only an ACTIVE one, or 422 4220103. A card is usually paid at once (COMPLETED); if the bank asks your customer to confirm again, it's PENDING with next_action.type REDIRECT.
  • save_payment_methodboolean | null
    CARD only. Also saves your customer's card for later charges (auto-debit), so you don't need POST /v1/payment-methods first. Send customer.id. On Weav's payment page, your customer agrees to future charges and pays; their bank's check (3DS) for this payment also confirms the card. The response's payment_method_id is the new method, PENDING until the payment is paid. You get PAYMENT_COMPLETED, then PAYMENT_METHOD_SAVED. If the payment isn't paid, the card isn't kept (PAYMENT_METHOD_FAILED). Off until Weav turns on saving cards for your account (422 4220401).
  • currencystringRequired
    ISO 4217. PHP today; more as they're enabled for your account.
    One of: PHP
  • amountnumberRequired
    Major unit, up to the currency's decimals (2 for PHP). Must be within your payment limits (GET /v1/channels; by default ₱0.01 to ₱50,000.00), or the response is 422.
    More than 0
  • external_reference_idstringRequired
    Your order or invoice reference. Unique across your payments in this mode (test and live are separate); reusing one returns 422.
    Up to 64 characters
  • descriptionstring | null
    Up to 255 characters. Your customer sees it on their emailed receipt (sent when you give their email).
    Up to 255 characters
  • next_action_formatstring | null
    HOSTED (default, every channel) returns next_action.checkout_url, Weav's payment page; the payment is set up with the provider when the customer opens it. DIRECT sets it up right away and returns the raw qr_string (with instructions), the provider's checkout_url or the payment_code.
    One of: HOSTED DIRECT
  • qr_ph_appstring | null
    QR Ph only. Tailors the how-to-pay steps to one bank or e-wallet app; any QR Ph app can still pay.
    One of: BDO CHINABANK GOTYME LANDBANK METROBANK PNB RCBC ROBINSONS_BANK SECURITY_BANK UNIONBANK GRABPAY SHOPEEPAY
  • customerobject | null
    The person paying. Stored encrypted; with an email, Weav emails them a receipt once the payment is paid. Weav needs the name for every payment (anti-money-laundering and fraud checks). Leave it out with HOSTED and Weav's payment page asks your customer before they pay; with DIRECT there's no Weav page, so name is required.
    4 fields in customer
    • idstring
      With save_payment_method only, and required then: your own ID for this customer. Their saved cards are listed by it (GET /v1/payment-methods?customer_id=).
      Up to 64 charactersPattern: ^[A-Za-z0-9._:@-]+$
    • namestring
      One field; not split into first and last name.
      Up to 255 characters
    • emailstring (email) | null
      Up to 255 characters
    • mobile_nostring | null
      A Philippine mobile number.
      Up to 20 characters
  • webhook_urlstring | null
    Optional. All of this payment's webhooks go here instead of your webhook URL, whatever its events list says. Public HTTPS only, signed with your signing key.
    Up to 2048 characters
  • success_urlstring (uri) | null
    Optional, HTTPS. Where your customer goes once the payment is paid. Without it, they stay on Weav's result page. Never treat this redirect as proof of payment.
    Up to 2048 characters
  • cancel_urlstring (uri) | null
    Optional, HTTPS. Where your customer goes if they leave without paying (the payment failed, expired or was canceled). Without it, they stay on Weav's result page.
    Up to 2048 characters

Responses

201 Created

Payment created (code 2010100).

What data holds
  • paymentobject
    32 fields in payment
    • reference_idstring
    • external_reference_idstring | null
      Yours. For a checkout's payment, the checkout's (null when it has none).
    • checkout_reference_idstring | null
      The checkout this payment was started from, if any.
    • payment_method_idstring | null
      The saved payment method it was charged to, or the one it saves the card to (save_payment_method), if any.
    • provider_reference_idstring | null
      The provider's transaction ID, once the provider has one.
    • channel_reference_idstring | null
      A reference from the channel that is unique to this payment, once the payment completes. Null for channels whose numbers can repeat; those are in references.
    • referencesobject
      The provider's other numbers for this payment, keyed by type: invoice_number (the 6-digit QR Ph invoice number), receipt_number (Maya) or transaction_id (GCash). Saved once the provider confirms the payment; {} until then. They can repeat across payments: search with them, never identify a payment by one alone.
      3 fields in references
      • invoice_numberstring
      • receipt_numberstring
      • transaction_idstring
    • channelstring
      One of QR_PH, GCASH, MAYA, CARD, PAY_AND_GO, PALAWANPAY, BAYAD.
      One of: QR_PH GCASH MAYA CARD PAY_AND_GO PALAWANPAY BAYAD
    • customerobject
      The person paying, as you sent it. The email and mobile number turn null once Weav's retention period ends.
      3 fields in customer
      • namestring | null
      • emailstring | null
      • mobile_nostring | null
    • currencystring
      ISO 4217. PHP today; more as they're enabled for your account.
      One of: PHP
    • amountnumber
    • feenumber | null
      Null until a rate applies.
    • totalnumber | null
      amount plus fee, calculated by Weav. Null while fee is null.
    • fee_bearerstring
      MERCHANT, the fee comes out of amount (default). PAYER (fees on top), the customer is charged amount + fee and you receive the full amount.
      One of: MERCHANT PAYER
    • amount_chargednumber
      What the customer is charged. amount, or total when fee_bearer is PAYER.
    • amount_refundednumber
      The total refunded so far. The payment turns REFUNDED once it equals amount.
    • refundsarray of objects
      Refunds Weav recorded for this payment, oldest first. Refunds are made by Weav support on request.
      4 fields in refunds
      • reference_idstring
      • amountnumber
      • provider_reference_idstring | null
      • refunded_atstring (date-time)
    • statusstring
      PENDING, COMPLETED, FAILED, CANCELLED, REVERSED or REFUNDED. See Statuses.
      One of: PENDING COMPLETED FAILED CANCELLED REVERSED REFUNDED
    • descriptionstring | null
      As you sent it.
    • success_urlstring (uri) | null
    • cancel_urlstring (uri) | null
    • webhook_urlstring | null
      Where this payment's webhooks go, when not your webhook URL.
    • next_actionobject
      What your customer does next. type is DISPLAY_QR, REDIRECT, PAY_AT_COUNTER, or null once the payment is final. qr_string, checkout_url and payment_code are each null unless they apply. With HOSTED (the default), type is REDIRECT and checkout_url is Weav's payment page (the test checkout with a test key), for every channel. For QR Ph, qr_ph_app is the app you chose, and instructions lists the how-to-pay steps (title, description) when you asked for DIRECT.
      6 fields in next_action
      • typestring | null
        One of: DISPLAY_QR REDIRECT PAY_AT_COUNTER
      • qr_stringstring | null
        QR Ph payload to render as a QR code: error correction Q (M at minimum), a white quiet zone of at least 4 modules, and the full-color QR Ph symbol on a white box 23.81% of the code width (quiet zone excluded) in the exact center.
      • checkout_urlstring (uri) | null
      • payment_codestring | null
        For over-the-counter channels.
      • qr_ph_appstring | null
        QR Ph only. The bank or e-wallet app the steps are tailored to.
      • instructionsarray of objects | null
        QR Ph with next_action_format DIRECT only. How-to-pay steps to show the customer.
        2 fields in instructions
        • titlestring
        • descriptionstring
    • test_checkout_urlstring (uri) | null
      Test mode only: the test checkout page, where you pay, decline or let this payment expire, for every channel (a counter payment with DIRECT has no other way to finish). Anyone with the link can open it. Null in live mode.
    • failureobject | null
      code and message when the payment failed. Codes: EXPIRED, DECLINED, PROVIDER_ERROR.
      2 fields in failure
      • codestring
        One of: EXPIRED DECLINED PROVIDER_ERROR
      • messagestring
    • expires_atstring (date-time)
      When an unpaid payment fails (failure.code EXPIRED).
    • completed_atstring (date-time) | null
      When the customer paid, as the provider reports it.
    • failed_atstring (date-time) | null
      When the payment failed.
    • cancelled_atstring (date-time) | null
      When the payment was canceled.
    • reversed_atstring (date-time) | null
      When the payment was reversed.
    • created_atstring (date-time)
      When Weav created the payment.
    • updated_atstring (date-time)
      When the payment last changed.

401 Unauthorized

Missing, malformed or unknown API key (code 4010000).

403 Forbidden

The key can't make this request (code 4030000): an address outside the key's IP allowlist, a live key before your live mode is on, or an account that isn't active. A live key sent from a browser is refused (code 4030001): keep live keys on your server.

409 Conflict

The request conflicts with the current state, e.g. an Idempotency-Key reused with a different body (4090001), a request still in progress (4090002), a payment that can't be canceled (4090101) or can't be canceled at the provider yet (4090102, retry shortly), or a webhook still being sent (4090201).

422 Unprocessable Content

One or more fields are invalid (code 4220000), or the channel is off (4220101) or doesn't take the currency (4220102).

429 Too Many Requests

Rate limited (code 4290000). Wait for Retry-After seconds.

501 Not Implemented

This channel isn't live for your account yet (code 5010100); use a test key.

POST

Try it: Create a payment

Test mode
Authorization
Headers
Body
Valid JSON
cURL

Uses $WEAV_API_KEY, never your key. Paste it into a terminal, or import it into Postman.

Response

Send the request to see Weav's answer here.

curl -X POST https://api.weavpayments.com/v1/payments \
    -H "Authorization: Bearer $WEAV_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "channel": "QR_PH",
    "currency": "PHP",
    "amount": 1250.00,
    "external_reference_id": "ORD-10541",
    "description": "Order ORD-10541",
    "next_action_format": "DIRECT",
    "customer": {
        "name": "Juan dela Cruz",
        "email": null,
        "mobile_no": null
    }
}'
{
    "code": "2010100",
    "success": true,
    "message": "Payment created",
    "data": {
        "payment": {
            "reference_id": "PY7K3Q9M2X4TBA",
            "external_reference_id": "ORD-10541",
            "checkout_reference_id": null,
            "payment_method_id": null,
            "provider_reference_id": null,
            "channel_reference_id": null,
            "references": {},
            "channel": "QR_PH",
            "customer": {
                "name": "Juan dela Cruz",
                "email": null,
                "mobile_no": null
            },
            "currency": "PHP",
            "amount": 1250.0,
            "fee": 31.25,
            "total": 1281.25,
            "fee_bearer": "MERCHANT",
            "amount_charged": 1250.0,
            "amount_refunded": 0.0,
            "refunds": [],
            "status": "PENDING",
            "description": "Order ORD-10541",
            "success_url": null,
            "cancel_url": null,
            "webhook_url": null,
            "next_action": {
                "type": "DISPLAY_QR",
                "qr_string": "00020101021228…6304A1B2",
                "checkout_url": null,
                "payment_code": null,
                "qr_ph_app": null,
                "instructions": [
                    {
                        "title": "Open your bank or e-wallet app",
                        "description": "Any app that supports QR Ph works."
                    },
                    {
                        "title": "Scan the QR code",
                        "description": "Use the app's QR scanner on the code on your screen, or upload a saved copy."
                    },
                    {
                        "title": "Confirm the payment",
                        "description": "Check the amount and the merchant's name, then confirm."
                    }
                ]
            },
            "test_checkout_url": null,
            "failure": null,
            "expires_at": "2026-10-26T10:27:00+08:00",
            "completed_at": null,
            "failed_at": null,
            "cancelled_at": null,
            "reversed_at": null,
            "created_at": "2026-10-26T10:12:00+08:00",
            "updated_at": "2026-10-26T10:12:00+08:00"
        }
    }
}