ECASHPAYECASHPAYDocumentation
Back to site

Introduction

  • EcashPay API
  • Quickstart

Core concepts

  • Environments and API keys
  • Signing requests
  • Errors

Accept payments

  • Creating a payment
  • Payment methods
  • Confirming the outcome
  • Refunds, capture and cancel

Testing

  • Testing

API reference

  • API reference

Creating a payment

The one endpoint that creates every payment, the fields it takes, what comes back, and the statuses a payment moves through.

Creating a payment

One endpoint creates every payment — POST /v1/payments — and one field decides how it behaves:

  • method — one of CARD_CREDIT, CARD_DEBIT, QR or EWALLET. It says how the customer pays, and it is the only choice you make about the payment itself.
  • customerEmail — required. The receipt and any payment instructions go there.

We answer with a paymentLinkUrl to send the customer to — or, for a QR payment, the code itself, because a QR is completed by scanning and the customer never has to leave.

You never name a payment service

Which of EcashPay's rails clears a method is arranged for your account and can change without any change to your integration — that is the point of naming the method rather than the rail. The body is the same either way. See Payment methods, and the reference for the exact shape.

The body

Four required fields — referenceId, method, amount and customerEmail — and the rest is polish:

POST /v1/payments — plaintext body
{
  "referenceId": "order-1001",
  "method": "EWALLET",
  "amount": 1500,
  "currency": "PHP",
  "customerEmail": "payer@example.com",
  "description": "Order #1001",
  "successReturnUrl": "https://your-shop.example/orders/1001/paid",
  "cancelReturnUrl": "https://your-shop.example/orders/1001/cancelled"
}
  • referenceId — your order id. Required, and unique per payment; see below.
  • amount — in the major unit. 1500 is ₱1,500.00, not ₱15.00. There are no minor units anywhere in this API.
  • currency — ISO-4217. Defaults to your account's currency; send it anyway, so the intent is in your own logs.
  • description — shown to the customer during checkout. Write it for them, not for your database.
  • successReturnUrl / cancelReturnUrl — where the customer lands afterwards. Read Confirming the outcome before you rely on either.

method and customerEmail are required alongside referenceId and amount. There is no flow to choose and no rail to name: those were fields once, and sending them now changes nothing.

What you get back

A payment comes back in one of two shapes, and which one you get follows from the method — so branch on the field that is present, never on the method itself.

Most methods: somewhere to send the customer
{
  "id": "9f2b41c7-de8a-4f05-9c3e-1a2b3c4d5e6f",
  "referenceId": "order-1001",
  "status": "PENDING",
  "method": "EWALLET",
  "amount": 1500,
  "currency": "PHP",
  "qrString": null,
  "paymentLinkUrl": "https://checkout.ecashpay.example/9f2b41c7"
}

Redirect the customer to paymentLinkUrl — do not iframe it, because the pages behind it redirect to banks and wallet apps that refuse to be framed.

QR: the payload itself, and no link
{
  "id": "3d7c9a10-5b2e-4c81-9f40-7e6d5c4b3a21",
  "referenceId": "order-1002",
  "status": "PENDING",
  "method": "QR",
  "amount": 1500,
  "currency": "PHP",
  "qrString": "00020101021228670011ph.ppmi.p2m…6304ABCD",
  "paymentLinkUrl": null
}

A QR payment is completed by scanning, so it publishes qrString and sets paymentLinkUrl to null. Render the payload as a QR code on your own page; the customer never leaves it. The payload is a string to draw, not an address to fetch.

Never both

qrString and paymentLinkUrl are never both set. A client that checks which one is present keeps working if a method ever changes shape.

Either way the payment starts PENDING. Nothing about the response tells you it succeeded — read Confirming the outcome for the one source of truth on that.

referenceId and double charges

referenceId is the double-charge guard, and it is the one field worth designing deliberately. Sending one you have used before is refused with DUPLICATE_REFERENCE_ID (409) rather than creating a second payment.

That makes the safe pattern for an unreliable network: reuse the same reference when you retry. Either you get the payment, or you get a 409 that proves it already exists — and in both cases your customer is charged once. Generating a fresh reference per attempt gives away exactly this protection.

One reference, one payment, forever

A reference is spent even if the payment ends up EXPIRED or FAILED. To let a customer try again after a failure, create a new payment with a new reference — order-1001-retry-2 keeps the tie to the order legible.

Payment statuses

status is what you act on. Everything else on a payment is detail:

StatusMeaning
PENDINGCreated, not yet paid. Every payment starts here. A customer who has not finished checkout sits here.
REQUIRES_ACTIONThe rail needs something from the customer — a redirect, an app confirmation, an OTP. Not a failure.
AUTHORIZEDFunds are held but not taken. Only appears on flows that separate authorization from capture; call capture to settle it or cancel to release it.
SUCCEEDEDPaid. This is the only status that means money is yours, and the only one to fulfil on.
FAILEDThe rail refused it — insufficient funds, a declined card, a rejected mandate. Terminal; create a new payment to try again.
EXPIREDThe customer never completed it in time. Terminal, and the most common non-success outcome for over-the-counter and e-wallet rails.
CANCELLEDAbandoned by the customer, or voided by you while it was authorized. Terminal.
REFUNDEDSucceeded, then returned in full.
PARTIALLY_REFUNDEDSucceeded, then partly returned. Still a payment you were paid for — the remainder is yours.

Treat this list as open. A rail we add later may introduce a status you have not seen, so write the check as "is it SUCCEEDED" and "is it one of the terminal failures I know" — never as an exhaustive switch that throws on the unexpected.

PreviousErrorsNextPayment methods

On this page

  • Creating a payment
  • The body
  • What you get back
  • referenceId and double charges
  • Payment statuses