Get started · 10 minutes
From zero to a settled payment.
The fastest path from no account to your first payment_intent.succeeded webhook. Everything here works against the sandbox; flip a flag when you're ready to go live.
- 1
Create a merchant account
Sign up at merchant.merashub.com/signup and complete KYC. Sandbox auto-approves in minutes; live merchants take 1-2 business days. - 2
Mint a sandbox API key
In the portal: Settings → Keys → Issue API key. Choose thesandboxenvironment. Copy thesk_test_…string — it's shown exactly once. - 3
Create your first PaymentIntent
POST to /v1/payment_intents from your server with the sandbox key. We accept your call, route to a mock provider, and return an intent that needs an OTP confirm. - 4
Confirm with the sandbox OTP
Sandbox OTP123456always succeeds. Confirm the intent and watch it transition tosucceeded. - 5
Register a webhook endpoint
Add your URL in the portal. We sign every body with an HMAC-SHA256 secret. Verify on your side; we retry with exponential backoff for up to 12h.
Sample request
One curl. Replace the secret key and send. Always pass an Idempotency-Key — same key in the next 24h returns the same response without double-charging.
curlbash
curl -X POST https://api.merashub.com/v1/payment_intents \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: order_42" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"currency": "DJF",
"provider": "mock",
"customer_msisdn": "+25377xxxxxxx",
"description": "Quickstart test"
}'Response — 201 Createdjson
{
"id": "pi_01HZF8AYJX3D8M7QK0E5V4WJ9K",
"client_secret": "pi_01HZF8AYJX3D8M7QK0E5V4WJ9K_secret_xyz",
"amount_minor": 50000,
"currency": "DJF",
"status": "requires_action",
"next_action": { "type": "collect_otp", "otp_length": 6 },
"created_at": "2026-05-25T10:15:30Z"
}ℹ
Sandbox vs live
Every URL, header, and shape is identical between sandbox and live — only the key prefix differs (
sk_test_* vs sk_live_*). Move to live by re-issuing keys; no code change needed.⚠
OTP test cards
In sandbox:
123456 always succeeds, 000000always fails (test the error path), any other 6-digit OTP returns "expired".