Accept Payments

Initialize transactions, redirect customers to pay, and verify completed payments.

This guide covers the complete payment flow - from initializing a transaction to verifying the result. Credo supports two integration approaches: the hosted checkout (redirect) and direct card charge (API-only).

Payment flow overview

Step 1: Initialize a transaction

Send a POST request to create a payment session. The response includes a URL where the customer completes payment.

curl -X POST https://api.credodemo.com/transaction/initialize \
  -H "Authorization: YOUR_PUBLIC_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 150000,
    "email": "customer@example.com",
    "currency": "NGN",
    "bearer": 0,
    "channels": ["CARD", "BANK"],
    "initializeAccount": 0,
    "reference": "ORD-20260207-001",
    "callbackUrl": "https://yoursite.com/payment/callback"
  }'

Response

{
  "status": 200,
  "message": "Transaction initialized successfully",
  "data": {
    "authorizationUrl": "https://pay.credocentral.com/checkout/xxx",
    "reference": "ORD-20260207-001",
    "credoReference": "vs_xxxxxxxxxxxx",
    "crn": "0000298483"
  }
}

Required fields

FieldTypeDescription
amountintegerAmount in lowest currency unit (kobo for NGN, cents for USD)
emailstringCustomer's email address
currencystringNGN or USD
bearerinteger0 = customer bears fee, 1 = merchant bears fee
channelsarrayPayment methods: Card, bank, USSD, WALLET, OPAY, PAYOUTLET
initializeAccountinteger0 = No, 1 = Yes (generate virtual account for bank transfer)

Optional fields

FieldTypeDescription
referencestringYour unique reference for the transaction. Auto-generated if omitted.
callbackUrlstringWhere to redirect the customer after payment.
customerPhoneNumberstringCustomer phone number.
customerFirstNamestringCustomer first name.
customerLastNamestringCustomer last name.
narrationstringDescription shown on the payment page.
metadataobjectCustom data attached to the transaction.
serviceCodestringPre-configured split settlement code.
splitConfigurationarrayDynamic split settlement config.
pauseSettlementinteger1 to hold funds in escrow.
pauseSettlementDatestringDate when paused funds will be settled (YYYY-MM-DD).

Step 2: Redirect to checkout

Send the customer to the authorizationUrl returned in step 1. Credo's hosted checkout handles card entry, bank transfer instructions, OTP verification, and 3D Secure - you don't need to build any of this.

// Express.js example
app.post("/pay", async (req, res) => {
  const response = await fetch("https://api.credocentral.com/transaction/initialize", {
    method: "POST",
    headers: {
      "Authorization": process.env.CREDO_PUBLIC_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: req.body.amount * 100, // Convert to kobo
      email: req.body.email,
      currency: "NGN",
      bearer: 0,
      channels: ["CARD", "BANK"],
      initializeAccount: 0,
      callbackUrl: `${process.env.BASE_URL}/payment/callback`,
    }),
  });

  const { data } = await response.json();
  res.redirect(data.authorizationUrl);
});

After payment, Credo redirects the customer to your callbackUrl with the transaction reference appended as a query parameter.

Step 3: Verify the transaction

Always verify server-side

Never trust the redirect alone. A customer could manipulate the callback URL or close their browser before the redirect. Always verify the transaction on your server using the secret key.

curl https://api.credodemo.com/transaction/vs_xxxxxxxxxxxx/verify \
  -H "Authorization: YOUR_SECRET_KEY"

Verification response

{
  "status": 200,
  "message": "Transaction fetched successfully",
  "data": {
    "transRef": "vs_xxxxxxxxxxxx",
    "businessRef": "ORD-20260207-001",
    "debitedAmount": 153250,
    "transAmount": 150000,
    "transFeeAmount": 3250,
    "settlementAmount": 150000,
    "customerId": "customer@example.com",
    "transactionDate": "2026-02-07T14:30:00.000Z",
    "currencyCode": "NGN",
    "status": 0
  }
}

Verification checklist

Before marking an order as paid, confirm:

  1. Status is 0 (successful) - see Concepts for all status codes
  2. Amount matches - compare transAmount to what you expected
  3. Currency matches - ensure currencyCode is what you charged
  4. Reference matches - businessRef should match your order reference
  5. Not already processed - check your database to avoid double-crediting
app.get("/payment/callback", async (req, res) => {
  const { transRef } = req.query;

  const response = await fetch(
    `https://api.credocentral.com/transaction/${transRef}/verify`,
    { headers: { "Authorization": process.env.CREDO_SECRET_KEY } }
  );

  const { data } = await response.json();

  if (data.status === 0 && data.transAmount === expectedAmount) {
    // Payment confirmed - fulfill the order
    await markOrderAsPaid(data.businessRef);
    res.redirect("/order/success");
  } else {
    res.redirect("/order/failed");
  }
});

Direct card charge

For PCI-DSS compliant merchants who want to collect card details on their own form, Credo offers a direct charge API. This is a two-step process.

Direct card charge requires PCI-DSS compliance. Most merchants should use the hosted checkout instead. Contact Credo support to enable this feature on your account.

Step 1: Initiate the charge

curl -X POST https://api.credodemo.com/transaction/direct/initiate \
  -H "Authorization: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 150000,
    "currency": "NGN",
    "reference": "ORD-20260207-002",
    "card": {
      "pan": "5399838383838381",
      "cvv": "470",
      "expiryYear": 2028,
      "expiryMonth": 10
    },
    "customer": {
      "email": "customer@example.com",
      "phoneNumber": "08012345678",
      "firstName": "John",
      "lastName": "Doe"
    },
    "authorization": {
      "mode": "PIN",
      "pin": "1234"
    },
    "callbackUrl": "https://yoursite.com/payment/callback"
  }'

If the card requires additional verification (OTP), the response will indicate this.

Step 2: Authorize with OTP

If prompted, submit the OTP the customer received:

curl -X POST https://api.credodemo.com/transaction/direct/authorize \
  -H "Authorization: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transRef": "vs_xxxxxxxxxxxx",
    "authorization": {
      "mode": "OTP",
      "otp": "123456"
    }
  }'

After authorization, verify the transaction using the same verification endpoint.

Adding metadata

Attach custom data to any transaction for your own record-keeping:

{
  "amount": 150000,
  "email": "customer@example.com",
  "currency": "NGN",
  "bearer": 0,
  "channels": ["CARD"],
  "initializeAccount": 0,
  "metadata": {
    "customFields": [
      {
        "variable_name": "order_id",
        "value": "ORD-001",
        "display_name": "Order ID"
      },
      {
        "variable_name": "product",
        "value": "Premium Plan",
        "display_name": "Product"
      }
    ]
  }
}

Metadata is returned in the verification response and webhook payload. Use it to link transactions to orders, products, or any business context.

Next steps

Was this page helpful?

Last updated on

On this page