> ## Documentation Index
> Fetch the complete documentation index at: https://docs.centipidbilling.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OPay

> Configure OPay hosted checkout for Nigerian cards, bank transfers, and wallet payments.

# Collect payments with OPay

`OPAY` uses a **hosted cashier**: Centipid Billing creates a checkout session,
sends the payer to OPay's page, and confirms the result on a signed callback.

Offered in the country catalog for **Nigeria (NG)** and **Pakistan (PK)**.

## Before you start

1. Complete OPay merchant onboarding in an account owned by the ISP.
2. From the OPay dashboard collect the **merchant ID**, the **public key**, and
   the **private key**.
3. Plan the walled garden: the payer's browser must reach OPay's cashier page,
   so a Hotspot subscriber who is not yet online cannot pay unless OPay is
   reachable pre-authentication.

## Configure the gateway

<Steps>
  <Step title="Open Settings → Payments → OPay">
    Select OPay from the payment marketplace.
  </Step>

  <Step title="Enter the merchant ID">
    **Merchant ID** (required) is sent as a header on every request.
  </Step>

  <Step title="Enter the public key">
    **Public key** (required) authenticates outgoing checkout requests.
  </Step>

  <Step title="Enter the private key">
    **Private key** (required, stored as a secret) is what validates the
    callback signature. Without the right value, confirmations are rejected.
  </Step>

  <Step title="Register the callback, return, and cancel URLs">
    See [Callback URLs](#callback-urls) below.
  </Step>

  <Step title="Run a controlled test payment">
    Pay a small amount from the captive portal on an unauthenticated device, and
    confirm both the cashier page loads and the payment reaches the ledger.
  </Step>
</Steps>

## Credentials

| Field       | Required | Notes                                                 |
| ----------- | -------- | ----------------------------------------------------- |
| Merchant ID | Yes      | Sent as the `MerchantId` header.                      |
| Public key  | Yes      | Bearer token on checkout requests.                    |
| Private key | Yes      | Secret. Validates the HMAC-SHA512 callback signature. |

Requests go to OPay's live API. There is no sandbox switch on this form, so test
with a small real amount rather than with test credentials.

## Callback URLs

Settings → Payments shows three:

| Name        | Path                                    |
| ----------- | --------------------------------------- |
| Webhook URL | `https://<your-host>/api/opay/callback` |
| Return URL  | `https://<your-host>/api/opay/return`   |
| Cancel URL  | `https://<your-host>/api/opay/cancel`   |

All three are also sent with every checkout request. Register them in the OPay
dashboard where OPay requires it, and confirm they are not blocked by a firewall
or WAF rule.

<Warning>
  Callbacks are verified with an HMAC-SHA512 signature computed with your
  **private key**. A wrong private key means every callback is rejected — payers
  are charged and never provisioned. If checkout works but the ledger stays
  empty, suspect this key first.
</Warning>

## What the payer must provide

Whatever OPay's cashier page asks for — bank transfer, card, or the OPay wallet.
The payer's email, phone number, and name are sent with the request when known,
so keep subscriber profiles accurate.

The country and currency come from your account's country. A checkout session
expires **30 minutes** after it is created.

## How a payment completes

<Steps>
  <Step title="Request">
    Centipid Billing creates the cashier session with the amount in minor units,
    the reference, and the return, cancel, and callback URLs.
  </Step>

  <Step title="Payment">
    The payer completes the payment on OPay's page.
  </Step>

  <Step title="Confirmation">
    OPay posts a signed callback. The signature is verified, the transaction
    matched on its reference, and the payment status re-read from OPay rather
    than trusted from the callback body alone. Repeated callbacks for a
    transaction already recorded are ignored, not double-credited.
  </Step>
</Steps>

## Troubleshooting

| Symptom                                                | What it means                                                                                                    | What to do                                                                                                                              |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| *"Failed to initiate OPay payment"*                    | OPay refused the checkout request; its own message is shown when it sends one.                                   | Verify the merchant ID and public key, and that the account is live for your country.                                                   |
| *"An error occurred while processing your payment: …"* | The request threw before completing.                                                                             | Check outbound connectivity to OPay, then retry.                                                                                        |
| The cashier page never loads on a Hotspot device       | The walled garden does not allow OPay.                                                                           | Allow OPay's cashier domain pre-authentication — see [Captive device cannot reach checkout](/billing/payment-gateways/troubleshooting). |
| Payments complete at OPay, ledger stays empty          | Callbacks are being rejected — most often a wrong private key, or a callback URL that is not publicly reachable. | Re-copy the private key, confirm the URL is reachable, then re-test.                                                                    |
| The payer waited too long and the page expired         | Sessions expire after 30 minutes.                                                                                | Start a fresh checkout rather than reusing the old page.                                                                                |
| *"Failed to verify payment status"*                    | The status query to OPay failed.                                                                                 | Retry the verification; check the reference on the OPay dashboard before recording anything by hand.                                    |

For every gateway's fields in one place, see the
[credential reference](/billing/payment-gateways/credentials-reference).
