Skip to main content

Payment Flow 🔁

High-level Overview

  1. The merchant creates a payment and redirects a customer to pay.o2pay.co/... (exact link is provided in the payment object)
  2. The customer specifies payment options and pays with crypto
  3. OxygenPay receives "in progress" transaction
  4. The customer receives "payment successful" in the UI. Right after that "back to site" button is enabled and it points to "success url" that was provided when creating a payment
  5. OxygenPay sends "inProgress" webhook to the merchant's backend
  6. OxygenPay receives transaction confirmation and marks the payment as successful
  7. OxygenPay sends "success" webhook to the merchant's backend

Detailed Flow

This diagram illustrates the process of a payment lifecycle


info

At step 11 customer can click "back to site" and proceed to $payment.redirectUrl, but at this moment transaction is not confirmed yet

Payment creation

You can create a payment with several ways:

  • By creating a payment link
  • Using API (e.g. from your backend) using createPayment
  • Manually via Merchant Dashboard (Payments > New Payment). Minimal payment entity consists of ID, fiat currency (USD / EUR), and price
info

To prevent duplicate requests and keep the flow idempotent, ID generation is led by the merchant side i.e. you should provide a unique id in the request

curl -X POST 'https://api.o2pay.co/api/merchant/v1/merchant/{merchantId}/payment' \
-H 'X-O2PAY-TOKEN: {token}' \
-H 'Content-Type: application/json' \
--data '{
"id": "8263313B-08C8-4855-8FAC-3A4CCBA7EAC2",
"currency": "USD",
"price": 30,
"redirectUrl": "https://my-store.com/success",
"description": "Sample Payment"
}'

The response would be:

{
"createdAt": "2023-04-25T21:19:29.358Z",
"currency": "USD",
"description": "Sample Payment",
"id": "8263313b-08c8-4855-8fac-3a4ccba7eac2",
"isTest": false,
"orderId": null,
"paymentUrl": "https://pay.o2pay.co/pay/<uuid>",
"price": "30",
"redirectUrl": "https://my-store.com/success",
"status": "pending",
"type": "payment"
}

Right after that you should redirect a customer to the $.paymentURL:

Sample payment

Payment status lifecycle

Notes on expiration

  • When a customer selects a currency, the payment is locked for 20 minutes.
    After that period it expires and payment is marked as Failed
  • Created and untouched payment link expires automatically after 6 hours

Test payments

It's possible to create test payments, in that case, we will process transactions on testnets (e.g. Ethereum Goerli) and top-up test balances as well. To create a test payment, simply specify "isTest": true.

note

Not all ERC20/TRC20 tokens are supported, see supported currencies section.