A simple payment integration from one request.
Your server creates a payment intent and receives a checkout_url. Redirect the customer, then track status through the API or a webhook.
Base URL: https://payunit.co/api/v1
Send the API key from your server only. Never expose it in browser JavaScript or a client application.
Amount format
All API amounts are decimal USD strings, not cents. Use at most two decimal places.
"1"$1.00
One dollar
"1.75"$1.75
One dollar and 75 cents
"74.00"$74.00
Seventy-four dollars
POST /payment-intents
Send Authorization and a unique Idempotency-Key for each commercial operation. Reusing the same key with the same body returns the same intent.
curl -X POST "https://payunit.co/api/v1/payment-intents" \
-H "Authorization: Bearer pay_live_YOUR_KEY" \
-H "Idempotency-Key: order-1048" \
-H "Content-Type: application/json" \
--data '{
"amount": "74.00",
"currency": "USD",
"external_ref": "ORDER-1048",
"description": "Order payment",
"success_url": "https://merchant.example/success",
"cancel_url": "https://merchant.example/cancel",
"methods": ["crypto", "togo", "lahza"]
}'PHP
<?php
$payload = [
'amount' => '74.00',
'currency' => 'USD',
'external_ref' => 'ORDER-1048',
'success_url' => 'https://merchant.example/success',
'cancel_url' => 'https://merchant.example/cancel',
'methods' => ['crypto', 'togo', 'lahza'],
];
$ch = curl_init('https://payunit.co/api/v1/payment-intents');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer pay_live_YOUR_KEY',
'Idempotency-Key: order-1048',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException(curl_error($ch));
}
$data = json_decode($response, true, 32, JSON_THROW_ON_ERROR);
header('Location: ' . $data['checkout_url']);Minimal response
{
"id": "pi_live_...",
"status": "requires_payment_method",
"amount": "74.00",
"checkout_url": "https://payunit.co/checkout/..."
}GET /payment-intents/{id}
Use the intent ID to retrieve current status, amount, fees, and payment method. Do not rely only on the browser return URL to fulfil an order.
curl "https://payunit.co/api/v1/payment-intents/pi_live_EXAMPLE" \ -H "Authorization: Bearer pay_live_YOUR_KEY"
Webhooks
PAYUNIT sends a signed JSON event to the configured HTTPS URL. Verify X-Payunit-Signature with HMAC-SHA256 over timestamp + "." + the raw request body.
$raw = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_PAYUNIT_SIGNATURE'] ?? '';
parse_str(str_replace(',', '&', $header), $parts);
$timestamp = (string)($parts['t'] ?? '');
$received = (string)($parts['v1'] ?? '');
$expected = hash_hmac('sha256', $timestamp . '.' . $raw, $webhookSecret);
if ($timestamp === '' || !hash_equals($expected, $received)) {
http_response_code(401);
exit;
}
$event = json_decode($raw, true, 32, JSON_THROW_ON_ERROR);Verify the signature, prevent event replay, and return HTTP 200 quickly after persisting the event. Run heavy processing separately.
Payment statuses
| Status | Meaning |
|---|---|
requires_payment_method | Created; the customer has not selected a method yet. |
processing | Payment started and final confirmation is pending. |
succeeded | Payment succeeded and the order can be fulfilled. |
failed | The payment attempt failed. |
cancelled | The payment was cancelled. |
expired | The checkout session expired. |
Operational security
Server-side key
Never expose the API key in browser or app code.
Idempotency
Use one stable key per order to prevent duplicate payment intents.
Verify status
Fulfil only after succeeded from the API or a verified webhook.