Skip to content
HitchPay API Docs

Guides & Recipes

Accept Your First Payment

This guide walks you through the complete flow for accepting a domestic payment — from initiating a checkout session to verifying the result and handling the webhook.


Overview

1. Generate Access Token    POST /v1/oauth/token
2. Initiate Payment         POST /v1/payments/initiate
3. Redirect Customer        → payment_url
4. Verify Payment           GET  /v1/payments/verify/{reference}
5. Receive Webhook          POST {your-webhook-url}

Step 1 — Generate an Access Token

Before making any API call, exchange your credentials for a Bearer token.

const axios = require("axios");
const qs = require("querystring");

const { data } = await axios.post(
  "https://sandbox.hitchpay.ng/v1/oauth/token",
  qs.stringify({
    client_id: process.env.CLIENT_ID,
    client_secret: process.env.CLIENT_SECRET,
    grant_type: "client_credentials"
  }),
  { headers: { "Content-Type": "application/x-www-form-urlencoded" } }
);

const accessToken = data.data.access_token;
<?php

$ch = curl_init();
curl_setopt_array($ch, [
  CURLOPT_URL => "https://sandbox.hitchpay.ng/v1/oauth/token",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => http_build_query([
    "client_id"     => "YOUR_CLIENT_ID",
    "client_secret" => "YOUR_CLIENT_SECRET",
    "grant_type"    => "client_credentials"
  ]),
  CURLOPT_HTTPHEADER => ["Content-Type: application/x-www-form-urlencoded"]
]);

$result = json_decode(curl_exec($ch), true);
curl_close($ch);

$accessToken = $result["data"]["access_token"];
import requests

res = requests.post(
    "https://sandbox.hitchpay.ng/v1/oauth/token",
    data={
        "client_id": "YOUR_CLIENT_ID",
        "client_secret": "YOUR_CLIENT_SECRET",
        "grant_type": "client_credentials"
    }
)

access_token = res.json()["data"]["access_token"]

Step 2 — Initiate a Payment

Create a payment session and get a hosted checkout URL to redirect your customer to.

const { data: payment } = await axios.post(
  "https://sandbox.hitchpay.ng/v1/payments/initiate",
  {
    amount: 100,
    currency: "USD",
    reference: "REF_ORDER_001",
    callback_url: "https://yourapp.com/payment/callback",
    allow_currency_selection: true,
    customer: {
      name: "John Doe",
      email: "[email protected]",
      phone: "08012345678"
    }
  },
  { headers: { Authorization: `Bearer ${accessToken}` } }
);

const paymentUrl = payment.data.payment_url;
const reference  = payment.data.reference;

// Redirect your customer to paymentUrl
console.log("Redirect to:", paymentUrl);
<?php

$ch = curl_init();
curl_setopt_array($ch, [
  CURLOPT_URL => "https://sandbox.hitchpay.ng/v1/payments/initiate",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => json_encode([
    "amount" => 100,
    "currency" => "USD",
    "reference" => "REF_ORDER_001",
    "callback_url" => "https://yourapp.com/payment/callback",
    "allow_currency_selection" => true,
    "customer" => [
      "name"  => "John Doe",
      "email" => "[email protected]",
      "phone" => "08012345678"
    ]
  ]),
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer {$accessToken}",
    "Content-Type: application/json"
  ]
]);

$payment = json_decode(curl_exec($ch), true);
curl_close($ch);

$paymentUrl = $payment["data"]["payment_url"];
$reference  = $payment["data"]["reference"];

// Redirect your customer
header("Location: {$paymentUrl}");
payment = requests.post(
    "https://sandbox.hitchpay.ng/v1/payments/initiate",
    json={
        "amount": 100,
        "currency": "USD",
        "reference": "REF_ORDER_001",
        "callback_url": "https://yourapp.com/payment/callback",
        "allow_currency_selection": True,
        "customer": {
            "name": "John Doe",
            "email": "[email protected]",
            "phone": "08012345678"
        }
    },
    headers={"Authorization": f"Bearer {access_token}"}
).json()

payment_url = payment["data"]["payment_url"]
reference   = payment["data"]["reference"]

# Redirect your customer to payment_url
print("Redirect to:", payment_url)

Step 3 — Redirect the Customer

Send your customer to the payment_url. HitchPay handles the checkout UI. After payment, the customer is redirected back to your callback_url with the reference and status appended as query parameters:

https://yourapp.com/payment/callback?reference=HCHK248EBF3863&status=successful

Do not rely on the redirect status alone — always verify via the API in Step 4.


Step 4 — Verify the Payment

Once the customer returns to your callback_url, verify the payment status server-side.

const { data: verification } = await axios.get(
  `https://sandbox.hitchpay.ng/v1/payments/verify/${reference}`,
  { headers: { Authorization: `Bearer ${accessToken}` } }
);

if (verification.data.status === "successful") {
  console.log("Payment confirmed! Amount:", verification.data.amount);
  // fulfil the order
} else {
  console.log("Payment not successful:", verification.data.status);
}
<?php

$ch = curl_init();
curl_setopt_array($ch, [
  CURLOPT_URL => "https://sandbox.hitchpay.ng/v1/payments/verify/{$reference}",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ["Authorization: Bearer {$accessToken}"]
]);

$verification = json_decode(curl_exec($ch), true);
curl_close($ch);

if ($verification["data"]["status"] === "successful") {
  echo "Payment confirmed! Amount: " . $verification["data"]["amount"];
  // fulfil the order
} else {
  echo "Payment not successful: " . $verification["data"]["status"];
}
verification = requests.get(
    f"https://sandbox.hitchpay.ng/v1/payments/verify/{reference}",
    headers={"Authorization": f"Bearer {access_token}"}
).json()

if verification["data"]["status"] == "successful":
    print("Payment confirmed! Amount:", verification["data"]["amount"])
    # fulfil the order
else:
    print("Payment not successful:", verification["data"]["status"])

Step 5 — Handle the Webhook

HitchPay also sends a real-time payment.success event to your configured webhook URL. Always verify the signature before processing.

const crypto = require("crypto");
const express = require("express");
const app = express();

app.post("/webhooks/hitchpay", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-hitchpay-signature"];
  const computed  = "sha256=" + crypto
    .createHmac("sha256", process.env.WEBHOOK_SECRET)
    .update(req.body)
    .digest("hex");

  if (signature !== computed) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(req.body);

  if (event.event === "payment.success") {
    console.log("Payment received:", event.data.reference);
    // fulfil the order
  }

  res.json({ status: "ok" });
});
<?php

$payload   = file_get_contents("php://input");
$signature = $_SERVER["HTTP_X_HITCHPAY_SIGNATURE"] ?? "";
$computed  = "sha256=" . hash_hmac("sha256", $payload, "YOUR_WEBHOOK_SECRET");

if (!hash_equals($computed, $signature)) {
  http_response_code(401);
  exit("Invalid signature");
}

$event = json_decode($payload, true);

if ($event["event"] === "payment.success") {
  error_log("Payment received: " . $event["data"]["reference"]);
  // fulfil the order
}

echo json_encode(["status" => "ok"]);
import hmac, hashlib
from flask import Flask, request, jsonify

app = Flask(__name__)
WEBHOOK_SECRET = "YOUR_WEBHOOK_SECRET"

@app.route("/webhooks/hitchpay", methods=["POST"])
def webhook():
    signature = request.headers.get("x-hitchpay-signature", "")
    computed  = "sha256=" + hmac.new(
        WEBHOOK_SECRET.encode(),
        request.get_data(),
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, computed):
        return "Invalid signature", 401

    event = request.get_json()

    if event["event"] == "payment.success":
        print("Payment received:", event["data"]["reference"])
        # fulfil the order

    return jsonify({"status": "ok"})

Summary

Step Action Endpoint
1 Get access token POST /v1/oauth/token
2 Create payment session POST /v1/payments/initiate
3 Redirect customer → payment_url
4 Verify on callback GET /v1/payments/verify/{reference}
5 Handle webhook event payment.success

💡 Always verify payment status server-side (Step 4). Never fulfil an order based solely on the redirect URL or webhook alone.

Questions? Email [email protected]. Also on GitBook.