Create invoices & verify payment status
Use TikiPay from your backend to create hosted payment sessions, redirect customers, receive callbacks and verify the final payment status before fulfillment.
http://payment.tikipay.inPOST /api/payment/createPOST /api/payment/verifyAPI-KEYQuick Start
Minimal cURL example
curl -X POST "http://payment.tikipay.in/api/payment/create" \ -H "Content-Type: application/json" \ -H "API-KEY: YOUR_BRAND_API_KEY" \ -d '{ "cus_name": "John Doe", "cus_email": "john@example.com", "amount": 1200, "success_url": "https://merchant.example/payment/success", "cancel_url": "https://merchant.example/payment/cancel", "webhook_url": "https://merchant.example/api/tikipay/webhook", "metadata": {"order_id":"ORDER-1001"} }'Complete Payment Integration Flow
Follow this sequence from the first local order to final fulfillment. Every step is arranged vertically so developers can read and implement the integration without horizontal scrolling.
PENDING. Do not mark it paid yet.metadata. Authenticate with the Brand API Key.invoice_id against your local order. This is the safest reference to use when you verify later.invoice_id or transaction_id to TikiPay Verify using the Brand API Key. This is the authoritative backend check.COMPLETED = fulfill once. PENDING = keep open and re-check later. ERROR = do not fulfill.Brand API Key vs Device Key
Brand API Key
Use this key on your website/server for Create, Verify and compatible payment API routes. Create it from Dashboard → Brands.
API-KEY: YOUR_BRAND_API_KEYDevice Key
Use this key only for the TikiPay device/SMS connector that forwards eligible payment information into your TikiPay account. Do not use a Device Key as the website payment API key.
Device Key → Dashboard → DevicesCreate Invoice
Create a hosted payment session from your server. Save the returned invoice_id, then redirect your customer to payment_url.
http://payment.tikipay.in/api/payment/create API-KEY: YOUR_BRAND_API_KEYapplication/jsoninvoice_id with your order.Request fields
| Field | Type | Required | Description |
|---|---|---|---|
amount | number | Yes | Payment amount. Must be greater than 0 and within the configured limit. |
success_url | URL | Yes | Browser return URL after checkout. |
cus_name | string | Recommended | Customer name. |
cus_email | string | Recommended | Customer email. |
cancel_url | URL | Recommended | Cancel/failure destination. If omitted, TikiPay can fall back to the success URL. |
webhook_url | URL | Recommended | Your server callback endpoint for payment automation. |
metadata | object | No | Your own references such as order_id, user_id or product_id. |
return_type | GET/POST | No | Optional return style for compatible checkout routes. |
Request examples
Choose your backend language. These examples all create the same TikiPay payment session. JavaScript examples are intended for a trusted server runtime - never expose the Brand API Key in public browser code.
curl -X POST "http://payment.tikipay.in/api/payment/create" \ -H "Content-Type: application/json" \ -H "API-KEY: YOUR_BRAND_API_KEY" \ -d '{ "cus_name": "John Doe", "cus_email": "john@example.com", "amount": 1200, "success_url": "https://merchant.example/payment/success", "cancel_url": "https://merchant.example/payment/cancel", "webhook_url": "https://merchant.example/api/tikipay/webhook", "metadata": { "order_id": "ORDER-1001" } }' const response = await fetch("http://payment.tikipay.in/api/payment/create", { method: "POST", headers: { "Content-Type": "application/json", "API-KEY": process.env.TIKIPAY_API_KEY }, body: JSON.stringify({ cus_name: "John Doe", cus_email: "john@example.com", amount: 1200, success_url: "https://merchant.example/payment/success", cancel_url: "https://merchant.example/payment/cancel", webhook_url: "https://merchant.example/api/tikipay/webhook", metadata: { order_id: "ORDER-1001" } })
});
const data = await response.json();
if (!response.ok || !data.payment_url) { throw new Error(data.message || "Unable to create payment");
}
console.log(data.invoice_id);
console.log(data.payment_url); <?php
$payload = [ "cus_name" => "John Doe", "cus_email" => "john@example.com", "amount" => 1200, "success_url" => "https://merchant.example/payment/success", "cancel_url" => "https://merchant.example/payment/cancel", "webhook_url" => "https://merchant.example/api/tikipay/webhook", "metadata" => [ "order_id" => "ORDER-1001" ]
];
$ch = curl_init("http://payment.tikipay.in/api/payment/create");
curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "API-KEY: YOUR_BRAND_API_KEY" ], CURLOPT_POSTFIELDS => json_encode($payload)
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($response, true);
if ($httpCode >= 400 || empty($data["payment_url"])) { throw new RuntimeException($data["message"] ?? "Unable to create payment");
}
$invoiceId = $data["invoice_id"];
$paymentUrl = $data["payment_url"]; <?php
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([ "API-KEY" => config("services.tikipay.key"),
])->acceptJson()->post("http://payment.tikipay.in/api/payment/create", [ "cus_name" => "John Doe", "cus_email" => "john@example.com", "amount" => 1200, "success_url" => route("payment.success"), "cancel_url" => route("payment.cancel"), "webhook_url" => route("tikipay.webhook"), "metadata" => [ "order_id" => "ORDER-1001" ],
]);
$response->throw();
$invoiceId = $response->json("invoice_id");
$paymentUrl = $response->json("payment_url");
return redirect()->away($paymentUrl); import os
import requests
payload = { "cus_name": "John Doe", "cus_email": "john@example.com", "amount": 1200, "success_url": "https://merchant.example/payment/success", "cancel_url": "https://merchant.example/payment/cancel", "webhook_url": "https://merchant.example/api/tikipay/webhook", "metadata": { "order_id": "ORDER-1001" }
}
response = requests.post( "http://payment.tikipay.in/api/payment/create", headers={ "Content-Type": "application/json", "API-KEY": os.environ["TIKIPAY_API_KEY"] }, json=payload, timeout=20
)
response.raise_for_status()
data = response.json()
invoice_id = data["invoice_id"]
payment_url = data["payment_url"] const https = require("https");
const payload = JSON.stringify({ cus_name: "John Doe", cus_email: "john@example.com", amount: 1200, success_url: "https://merchant.example/payment/success", cancel_url: "https://merchant.example/payment/cancel", webhook_url: "https://merchant.example/api/tikipay/webhook", metadata: { order_id: "ORDER-1001" }
});
const url = new URL("http://payment.tikipay.in/api/payment/create");
const req = https.request({ hostname: url.hostname, path: url.pathname, method: "POST", headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload), "API-KEY": process.env.TIKIPAY_API_KEY }
}, (res) => { let body = ""; res.on("data", chunk => body += chunk); res.on("end", () => { const data = JSON.parse(body); if (res.statusCode >= 400 || !data.payment_url) { throw new Error(data.message || "Unable to create payment"); } console.log(data.invoice_id); console.log(data.payment_url); });
});
req.on("error", console.error);
req.write(payload);
req.end(); { "status": 1, "message": "Payment Link", "payment_url": "http://payment.tikipay.in/api/execute/SESSION_ID", "invoice_id": "SESSION_ID"
} Verify Payment
Verify from your backend before you mark an order paid. You can send either invoice_id or transaction_id. The invoice ID returned by Create is the recommended reference.
http://payment.tikipay.in/api/payment/verify invoice_idtransaction_idstatus = COMPLETEDRequest examples
curl -X POST "http://payment.tikipay.in/api/payment/verify" \ -H "Content-Type: application/json" \ -H "API-KEY: YOUR_BRAND_API_KEY" \ -d '{ "invoice_id": "SESSION_ID" }' const response = await fetch("http://payment.tikipay.in/api/payment/verify", { method: "POST", headers: { "Content-Type": "application/json", "API-KEY": process.env.TIKIPAY_API_KEY }, body: JSON.stringify({ invoice_id: "SESSION_ID" })
});
const payment = await response.json();
if (!response.ok) { throw new Error(payment.message || "Verification failed");
}
if (payment.status === "COMPLETED") { // Mark the local order paid exactly once.
} else if (payment.status === "PENDING") { // Keep the local order open and retry later.
} else { // Do not fulfill.
} <?php
$ch = curl_init("http://payment.tikipay.in/api/payment/verify");
curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "API-KEY: YOUR_BRAND_API_KEY" ], CURLOPT_POSTFIELDS => json_encode([ "invoice_id" => "SESSION_ID" ])
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$payment = json_decode($response, true);
if ($httpCode >= 400) { throw new RuntimeException($payment["message"] ?? "Verification failed");
}
if (($payment["status"] ?? "") === "COMPLETED") { // Mark order paid once.
} <?php
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([ "API-KEY" => config("services.tikipay.key"),
])->acceptJson()->post("http://payment.tikipay.in/api/payment/verify", [ "invoice_id" => $order->tikipay_invoice_id,
]);
$response->throw();
$payment = $response->json();
if (($payment["status"] ?? null) === "COMPLETED") { DB::transaction(function () use ($order, $payment) { if (!$order->is_paid) { $order->update([ "is_paid" => true, "transaction_id" => $payment["transaction_id"] ?? null, ]); } });
} import os
import requests
response = requests.post( "http://payment.tikipay.in/api/payment/verify", headers={ "Content-Type": "application/json", "API-KEY": os.environ["TIKIPAY_API_KEY"] }, json={ "invoice_id": "SESSION_ID" }, timeout=20
)
response.raise_for_status()
payment = response.json()
if payment["status"] == "COMPLETED": # Mark the local order paid exactly once. pass
elif payment["status"] == "PENDING": # Retry later. pass
else: # Do not fulfill. pass const https = require("https");
const payload = JSON.stringify({ invoice_id: "SESSION_ID"
});
const url = new URL("http://payment.tikipay.in/api/payment/verify");
const req = https.request({ hostname: url.hostname, path: url.pathname, method: "POST", headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload), "API-KEY": process.env.TIKIPAY_API_KEY }
}, (res) => { let body = ""; res.on("data", chunk => body += chunk); res.on("end", () => { const payment = JSON.parse(body); if (payment.status === "COMPLETED") { // Mark the order paid exactly once. } });
});
req.on("error", console.error);
req.write(payload);
req.end(); { "cus_name": "John Doe", "cus_email": "john@example.com", "amount": 1200, "invoice_id": "SESSION_ID", "transaction_id": "TXN123456789", "metadata": { "order_id": "ORDER-1001" }, "payment_method": "bkash", "status": "COMPLETED"
} How to decide what your website should do
Webhook & Return Flow
Use the browser return for customer experience and the webhook for automation. Always finish by verifying the payment server-to-server.
invoice_id and transactionId/transaction_id to locate your local order.COMPLETED payment should update the order as paid.Native webhook payload
paymentMethod=bkash
transactionId=TXN123456789
paymentAmount=1200
paymentFee=0
invoice_id=SESSION_ID
status=COMPLETED Example webhook handler (PHP)
<?php
$invoiceId = $_POST["invoice_id"] ?? null;
if (!$invoiceId) { http_response_code(400); exit("Missing invoice_id");
}
/* * 1. Find the local order by the saved TikiPay invoice ID. * 2. Call TikiPay Verify from your backend. * 3. Fulfill only when Verify returns COMPLETED. * 4. Make the fulfillment idempotent. */
http_response_code(200);
echo "OK"; Status, HTTP Errors & Recovery
A production integration should handle both HTTP-level errors and payment-level statuses.
Read the JSON body. For Verify, inspect status before fulfillment.
Check amount, required URL fields, invoice ID and request JSON.
Confirm the Brand API Key and the authentication header.
Check the invoice/transaction reference and make sure it belongs to the same TikiPay account.
Do not fulfill. Log the response and retry safely when appropriate.
Do not assume failure or success. Re-run Verify using the saved invoice ID.
Recommended retry logic
Existing Integration Compatibility
TikiPay accepts three API shapes. New integrations should use the Native API. Existing compatible integrations can keep their current field mapping and response parser.
/api/payment/create/api/payment/verifyAPI-KEY/api/checkout-v2/api/verify-paymentBrand API Key/v1/payment/create/v1/payment/verifyBrand API Keyhttp://payment.tikipay.in/api/checkout-v2http://payment.tikipay.in/api/verify-paymenthttp://payment.tikipay.in/v1/payment/createhttp://payment.tikipay.in/v1/payment/verifyApps, Plugins & Modules
Start with the TikiPay app or install a ready-made integration for your platform. The most commonly used packages are highlighted below; the full library includes SDKs, ecommerce, billing, CRM, SMM, LMS and automation modules.
TikiPay Official App
Android app for supported TikiPay device/SMS connector workflows and account-side automation.
Download AppTikiPay WooCommerce Plugin
Hosted checkout and backend verification for WooCommerce stores.
DownloadWordPress API Plugin
Reusable API client and helper package for custom WordPress payment flows.
DownloadTikiPay WHMCS Module
Invoice checkout integration with server-side payment verification.
DownloadPerfex CRM Plugin
Payment gateway module for Perfex CRM invoices and customer payments.
DownloadTikiPay Laravel SDK
Laravel configuration, service client, controller examples and routes.
Download