Shulker Payment Gateway v1.0.0
Programmatically create payment links, track status, and handle webhooks. Built for startups & merchants — one API to rule them all.
Introduction
The Shulker Payment Gateway API lets you generate payment requests, track their status,
and receive webhook notifications when payments succeed. It powers the branded checkout
page at /payment-gateway/ and handles all the heavy lifting.
https://shulker.in/api/shulker-pg-v1.0/Authentication
All endpoints except ping, log_event, and complete_payment
require an API key. Pass it via the X-API-Key header, the
Authorization: Bearer header, or the api_key query parameter.
X-API-Key: spgk_your_secret_key_hereAuthorization: Bearer spgk_your_secret_key_here🔐 Keep it secret — API keys grant full access to your payment requests. Never expose them in client‑side code. Rotate regularly.
Rate limits
Per‑API‑key limits are soft and can be raised on request.
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 45 X-RateLimit-Reset: 1697385645
Error handling
| Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request — invalid parameter |
| 401 | Missing or invalid API key |
| 403 | Forbidden — insufficient permissions |
| 404 | Resource not found |
| 409 | Conflict — already processed |
| 410 | Gone — payment request expired |
| 422 | Unprocessable entity — validation failed |
| 429 | Too many requests — rate limit |
| 500 | Internal server error |
{
"success": false,
"message": "amount_usd must be between 0.01 and 10000.00"
}Create payment request
Generates a new payment link. The request is valid for 24 hours.
?action=create_request
| Parameter | Type | Required | Description |
|---|---|---|---|
| amount_usd | float | ✅ | Amount in USD (min 0.01, max depends on key) |
| redirect_url | string | ✅ | Valid http/https URL for post‑payment redirection |
| description | string | ✅ | Max 500 chars, shown on checkout |
| currency_override | string | ❌ | USD, INR, GBP, EUR, CAD, AUD (defaults to payer's geo) |
| metadata | object | ❌ | Up to 20 keys, stored for webhook use |
curl -X POST https://shulker.in/api/shulker-pg-v1.0/ \ -H "X-API-Key: spgk_..." \ -H "Content-Type: application/json" \ -d '{ "action": "create_request", "amount_usd": 49.99, "redirect_url": "https://myapp.com/success", "description": "Pro plan subscription", "metadata": { "user_id": 12345 } }'
{
"success": true,
"message": "Payment request created.",
"data": {
"payment_request_id": "SPGR_A1B2C3D4E5F6",
"checkout_url": "https://shulker.in/payment-gateway/?payment_request=SPGR_A1B2C3D4E5F6",
"amount_usd": 49.99,
"amount_inr": 4699.06,
"expires_at": "2026-09-09 16:30:00",
"status": "pending"
}
}Get payment status
?action=get_status&payment_request_id=SPGR_...
curl "https://shulker.in/api/shulker-pg-v1.0/?action=get_status&payment_request_id=SPGR_A1B2C3&api_key=spgk_..."
{
"success": true,
"data": {
"payment_request_id": "SPGR_A1B2C3",
"status": "completed",
"amount_usd": 49.99,
"payer": {
"name": "John Doe",
"email": "[email protected]",
"country_code": "IN"
},
"txn_id": "pay_xyz",
"completed_at": "2026-09-09 14:20:00"
}
}List payment requests
?action=list_requests&page=1&limit=20&status=pending
📄 Pagination — page and limit (max 100) are optional. Filter by status: pending, completed, expired, failed.
Manually expire a request
?action=expire_request
curl -X POST https://shulker.in/api/shulker-pg-v1.0/ \ -H "X-API-Key: spgk_..." \ -d "action=expire_request&payment_request_id=SPGR_A1B2C3"
Log analytics event
Internal endpoint used by the checkout page to track user behaviour. No API key required — uses the payment request ID as a token.
?action=log_event
| Parameter | Description |
|---|---|
| payment_request_id | Required |
| event_type | page_view, form_started, form_completed, payment_initiated, payment_success, payment_failed, payment_cancelled |
| payload | Optional JSON object |
Complete payment
Called by the checkout page after a successful Razorpay payment. No API key required — uses a checkout token for authorisation.
?action=complete_payment
✅ Auto‑webhook — after completion, a webhook is fired to the merchant’s configured URL with the full payment payload.
Checkout flow (frontend)
- Create a payment request via the API → get
checkout_url. - Redirect the user to that URL (or embed it).
- The checkout page automatically detects the user’s country & currency (via ipapi.co) and shows the branded form.
- User fills in name, email, phone → selects payment method (UPI / card / net banking / wallet).
- Razorpay modal opens → user completes payment.
- On success, the page calls
complete_payment→ logs data, fires webhook, redirects to yourredirect_url.
💡 Customisation — all colours, logo, and business name are pulled from the API key record. Update them via the dashboard.
Webhooks
When a payment is completed, Shulker sends a POST request to your configured webhook_url
with a JSON payload and a X-SPG-Signature header (HMAC‑SHA256 of the raw body using your webhook_secret).
{
"event": "payment.completed",
"payment_request_id": "SPGR_A1B2C3",
"amount_usd": 49.99,
"currency": "INR",
"display_amount": 4699.06,
"payment_method": "card",
"txn_id": "pay_xyz",
"payer": {
"name": "John Doe",
"email": "[email protected]",
"country": "IN"
},
"metadata": { "user_id": 12345 },
"completed_at": "2026-09-09T14:20:00+00:00"
}🔐 Verify signatures — always compute hash_hmac('sha256', raw_body, your_secret) and compare with the X-SPG-Signature header to avoid forged calls.
Best practices
🔐 Security — store API keys in environment variables, never in version control. Use the webhook_secret to verify signatures. Rotate keys every 90 days.
⚡ Performance — cache API key details if you make many requests. Use list_requests with pagination for bulk operations.
🔄 Error handling — implement exponential backoff for 5xx errors. Store payment_request_id and txn_id for reconciliation.
📊 Analytics — leverage the built‑in analytics tables (shulker_pg_analytics_events) to understand your payer funnel.