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=successfulDo 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.