Ummah
Payment Gateway API
A robust, developer-friendly REST API for integrating payments into your application. Built for e-commerce, subscriptions, and enterprise billing workflows.
Go live in 5 minutes with our REST API and client libraries.
Accept PaymentsOne-time charges, pre-auth & capture, tokenized recurring payments.
SubscriptionsFull recurring billing with templates, webhooks, and lifecycle management.
Webhooks & SecurityHMAC-SHA256 verification, idempotency keys, and secure key management.
Authentication
All API requests must include your secret key in the Authorization header using
Bearer scheme.
Authorization: Bearer YOUR_SECRET_KEYsk_test_* key to make sandbox
requests. No real payments are processed. Switch to sk_live_* for production.
API Keys
Retrieve your API keys from the dashboard under Settings → API Keys. Keep your secret key confidential — never expose it in client-side code.
Quickstart — Accept a Payment in 5 Minutes
Copy-paste this example into your project. Uses Node.js but the same flow applies to any language.
npm install @ummah/payments# Set your key in the environment
export UMMAH_SECRET_KEY=sk_test_your_key_hereimport Ummah from '@ummah/payments';
const ummah = new Ummah(process.env.UMMAH_SECRET_KEY);import ummah
import os
client = ummah.Client(api_key=os.environ['UMMAH_SECRET_KEY'])curl -X POST "https://gate.ummah.com/api/v1/purchases/" \
-H "Authorization: Bearer $UMMAH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
"client": { "email": "user@example.com" },
"purchase": {
"products": [{ "name": "T-Shirt", "price": 5000, "quantity": 1 }],
"currency": "USD"
},
"success_redirect": "https://yourapp.com/success",
"failure_redirect": "https://yourapp.com/failure"
}'const purchase = await ummah.purchases.create({
brand_id: '409eb80e-3782-4b1d-afa8-b779759266a5',
client: { email: 'user@example.com' },
purchase: {
products: [{ name: 'T-Shirt', price: 5000, quantity: 1 }],
currency: 'USD',
},
success_redirect: 'https://yourapp.com/success',
failure_redirect: 'https://yourapp.com/failure',
});
console.log(purchase.checkout_url);
// → https://pay.ummah.com/checkout/pur_abc123import requests, os
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/',
headers={'Authorization': f'Bearer {os.environ["UMMAH_SECRET_KEY"]}'},
json={
'brand_id': '409eb80e-3782-4b1d-afa8-b779759266a5',
'client': {'email': 'user@example.com'},
'purchase': {
'products': [{'name': 'T-Shirt', 'price': 5000, 'quantity': 1}],
'currency': 'USD',
},
'success_redirect': 'https://yourapp.com/success',
'failure_redirect': 'https://yourapp.com/failure',
}
)
purchase = response.json()
print(purchase['checkout_url'])purchase.checkout_url — a PCI-compliant hosted page. They enter their card details there; your server never handles raw card data.purchase.paid event to your callback URL. Verify the X-Signature header and fulfill the order. See the Webhook Verification Guide.Why Ummah
Ummah is purpose-built for businesses that require ethical, Shariah-aligned payment processing — without sacrificing the modern developer experience you expect from leading gateways.
| Feature | Ummah | Stripe |
|---|---|---|
| Halal-compliant processing — no interest, no prohibited industries | ✓ Built-in | ✕ Not applicable |
| Shariah-aligned profit-sharing — revenue model reviewed by scholars | ✓ Yes | ✕ Conventional interest model |
| Built-in billing templates — reusable subscription plans | ✓ Native | ∼ Requires Stripe Billing add-on |
| Transparent, flat-rate pricing — one rate, no hidden fees | ✓ Yes | ∼ Tiered, plus add-on fees |
| Marketplace-ready — split payments between sellers | ✓ Roadmap | ✓ Stripe Connect |
| Hosted checkout (PCI DSS Level 1) | ✓ Yes | ✓ Yes |
| Multi-currency support | ✓ Yes | ✓ Yes |
| HMAC-SHA256 signed webhooks | ✓ Yes | ✓ Yes |
| Idempotency keys — safe request retries | ✓ Yes | ✓ Yes |
| Dedicated Muslim-majority market focus | ✓ Core mission | ✕ Not a focus |
Core Objects
The API is built around five key objects that work together:
erDiagram
PURCHASE ||--o{ CLIENT : "belongs to"
PURCHASE }o--|| BRAND : "created for"
BILLING_TEMPLATE ||--o{ SUBSCRIBER : "has"
SUBSCRIBER ||--|| CLIENT : "is a"
WEBHOOK ||--o{ DELIVERY : "sends"
The core transaction object. Holds product details, payment status, checkout URL, and client info.
A customer record with contact details and optional saved payment methods (recurring tokens).
A reusable invoice or subscription plan. Generates purchases automatically for each subscriber.
Test Mode & Sandbox
Use your sk_test_* key to test the full API without processing real payments. All endpoints behave identically in test and live mode.
Test Card Numbers
| Card Number | Result | CVC | Expiry |
|---|---|---|---|
| 4242 4242 4242 4242 | Success | Any 3 digits | Any future date |
| 4000 0000 0000 0002 | Declined | Any 3 digits | Any future date |
| 4000 0000 0000 3220 | 3D Secure required | Any 3 digits | Any future date |
sk_test_* keys. Never use real card numbers in test mode.
Webhook Testing Tips
Use tools like ngrok to expose your local server for webhook testing. Set your callback URL to the ngrok tunnel URL during development.
Callbacks & Webhooks
When a payment event occurs, the gateway sends a signed POST request to your
configured callback URL. Verify the X-Signature header using HMAC-SHA256 and
your callback public key (see GET /public_key/).
Events
purchase.paid • purchase.payment_failure •
purchase.refunded • purchase.cancelled •
billing_template.client_activated
Best Practices
Return a 2xx response quickly to acknowledge receipt. Process the event
asynchronously to avoid gateway timeout. The gateway retries failed deliveries.
Accept Payments
Create purchases, redirect customers to checkout, and manage the full payment lifecycle — authorization, capture, refunds, and recurring charges.
Payment Flow
Every payment follows this lifecycle. Use skip_capture: true to authorize first and capture later.
stateDiagram-v2
[*] --> Created: POST /purchases/
Created --> Authorized: Customer pays (skip_capture)
Created --> Paid: Customer pays
Created --> Cancelled: POST /cancel/
Authorized --> Paid: POST /capture/
Authorized --> Released: POST /release/
Paid --> Refunded: POST /refund/
Create a Purchase
Register a new payment and receive a checkout_url to redirect your customer to. After payment, the gateway redirects back to your success_redirect / failure_redirect.
| Parameter | Description |
|---|---|
brand_idREQUIREDuuid | ID of the brand to create this Purchase for. |
client.emailREQUIREDstring | Customer email address. |
purchase.productsREQUIREDarray | Products array. Each item: {name, price, quantity}. |
purchase.currencyOPTIONALstring | 3-letter ISO currency code. Defaults to brand currency. |
success_redirectOPTIONALstring | URL to redirect to after successful payment. |
failure_redirectOPTIONALstring | URL to redirect to after payment failure. |
success_callbackOPTIONALstring | URL to POST a signed payment notification to. |
skip_captureOPTIONALboolean | Authorize only; capture funds later via POST /capture/. |
force_recurringOPTIONALboolean | Save payment method for future recurring charges. |
send_receiptOPTIONALboolean | Email a receipt to the client after payment. |
curl -X POST "https://gate.ummah.com/api/v1/purchases/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
"client": {
"email": "customer@example.com"
},
"purchase": {
"products": [
{
"name": "T-Shirt",
"price": 2999,
"quantity": 1
}
],
"currency": "USD"
},
"success_redirect": "https://myshop.com/success",
"failure_redirect": "https://myshop.com/failed"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
"client": {
"email": "customer@example.com"
},
"purchase": {
"products": [
{
"name": "T-Shirt",
"price": 2999,
"quantity": 1
}
],
"currency": "USD"
},
"success_redirect": "https://myshop.com/success",
"failure_redirect": "https://myshop.com/failed"
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
'brand_id': '409eb80e-3782-4b1d-afa8-b779759266a5',
'client': {'email': 'customer@example.com'},
'purchase': {
'products': [{'name': 'T-Shirt', 'price': 2999, 'quantity': 1}],
'currency': 'USD',
},
'success_redirect': 'https://myshop.com/success',
'failure_redirect': 'https://myshop.com/failed',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/',
headers=headers,
json=data
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
"client": {
"email": "customer@example.com"
},
"purchase": {
"products": [
{
"name": "T-Shirt",
"price": 2999,
"quantity": 1
}
],
"currency": "USD"
},
"success_redirect": "https://myshop.com/success",
"failure_redirect": "https://myshop.com/failed"
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/',
headers=headers,
json=data
)
print(response.json()){
"id": "d6c9e9e0-1b5a-4c6e-8b3a-0f1a2b3c4d5e",
"status": "created",
"checkout_url": "https://pay.ummah.com/checkout/d6c9...",
"invoice_url": "https://pay.ummah.com/invoice/d6c9...",
"client": { "email": "customer@example.com", "full_name": "John Doe" },
"purchase": { "total_amount": 2999, "currency": "USD" },
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Retrieve a Purchase
Retrieve the full details of a purchase by its ID, including current status, payment data, and client info.
curl -X GET "https://gate.ummah.com/api/v1/purchases/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/purchases/{id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/purchases/{id}/',
headers=headers
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/purchases/{id}/',
headers=headers
)
print(response.json()){
"id": "d6c9e9e0-1b5a-4c6e-8b3a-0f1a2b3c4d5e",
"status": "paid",
"checkout_url": "https://pay.ummah.com/checkout/d6c9...",
"purchase": { "total_amount": 2999, "currency": "USD" },
"payment": { "method": "card", "is_recurring_token": false },
"created_on": 1700000000
}{"error": "Not Found", "detail": "Object with this ID does not exist."}Cancel a Purchase
Cancel a pending or authorized purchase. Only purchases in created or authorized status can be cancelled.
curl -X POST "https://gate.ummah.com/api/v1/purchases/{id}/cancel/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/{id}/cancel/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/cancel/',
headers=headers
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/cancel/',
headers=headers
)
print(response.json()){"status": "cancelled"}{"error": "Not Found", "detail": "Object with this ID does not exist."}Void Authorization
Release funds that were authorized (held) on a purchase with skip_capture: true. This voids the authorization without capturing.
curl -X POST "https://gate.ummah.com/api/v1/purchases/{id}/release/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/{id}/release/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/release/',
headers=headers
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/release/',
headers=headers
)
print(response.json()){"status": "released"}{"error": "Not Found", "detail": "Object with this ID does not exist."}Capture a Purchase
Capture a previously authorized purchase. Optionally specify a partial amount in the smallest currency unit.
| Parameter | Description |
|---|---|
amountOPTIONALinteger | Amount to capture in smallest currency unit (e.g. cents). Defaults to full authorized amount. |
curl -X POST "https://gate.ummah.com/api/v1/purchases/{id}/capture/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"amount": 2999
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"amount": 2999
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/{id}/capture/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {'amount': 2999}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/capture/',
headers=headers,
json=data
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"amount": 2999
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/capture/',
headers=headers,
json=data
)
print(response.json()){
"id": "d6c9e9e0-1b5a-4c6e-8b3a-0f1a2b3c4d5e",
"status": "paid",
"checkout_url": "https://pay.ummah.com/checkout/d6c9...",
"purchase": { "total_amount": 2999, "currency": "USD" },
"payment": { "method": "card", "is_recurring_token": false },
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Charge Saved Payment Method
Charge or hold a purchase using a saved recurring token. Use this for subscription renewals or one-click payments.
| Parameter | Description |
|---|---|
recurring_tokenOPTIONALstring | ID of the recurring token to charge. |
curl -X POST "https://gate.ummah.com/api/v1/purchases/{id}/charge/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"recurring_token": "tok-a1b2c3d4-e5f6-7890"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"recurring_token": "tok-a1b2c3d4-e5f6-7890"
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/{id}/charge/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {'recurring_token': 'tok-a1b2c3d4-e5f6-7890'}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/charge/',
headers=headers,
json=data
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"recurring_token": "tok-a1b2c3d4-e5f6-7890"
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/charge/',
headers=headers,
json=data
)
print(response.json()){
"id": "d6c9e9e0-1b5a-4c6e-8b3a-0f1a2b3c4d5e",
"status": "paid",
"checkout_url": "https://pay.ummah.com/checkout/d6c9...",
"purchase": { "total_amount": 2999, "currency": "USD" },
"payment": { "method": "card", "is_recurring_token": false },
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Refund a Purchase
Refund a paid purchase in full or partially. Optionally pass an internal reference for your records.
| Parameter | Description |
|---|---|
amountOPTIONALinteger | Amount to refund in smallest currency unit. Defaults to full amount. |
referenceOPTIONALstring | Internal refund reference for your records. |
curl -X POST "https://gate.ummah.com/api/v1/purchases/{id}/refund/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"amount": 1500,
"reference": "REFUND-2024-001"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"amount": 1500,
"reference": "REFUND-2024-001"
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/{id}/refund/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
'amount': 1500,
'reference': 'REFUND-2024-001',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/refund/',
headers=headers,
json=data
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"amount": 1500,
"reference": "REFUND-2024-001"
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/refund/',
headers=headers,
json=data
)
print(response.json()){
"id": "d6c9e9e0-1b5a-4c6e-8b3a-0f1a2b3c4d5e",
"status": "paid",
"checkout_url": "https://pay.ummah.com/checkout/d6c9...",
"purchase": { "total_amount": 2999, "currency": "USD" },
"payment": { "method": "card", "is_recurring_token": false },
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Confirm Offline Payment
Manually mark a purchase as paid. Useful for cash/offline payments recorded in the system.
| Parameter | Description |
|---|---|
paid_onOPTIONALtimestamp | Unix timestamp of when payment was received. Defaults to now. |
curl -X POST "https://gate.ummah.com/api/v1/purchases/{id}/mark_as_paid/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"paid_on": 1700000000
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"paid_on": 1700000000
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/{id}/mark_as_paid/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {'paid_on': 1700000000}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/mark_as_paid/',
headers=headers,
json=data
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"paid_on": 1700000000
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/mark_as_paid/',
headers=headers,
json=data
)
print(response.json()){
"id": "d6c9e9e0-1b5a-4c6e-8b3a-0f1a2b3c4d5e",
"status": "paid",
"checkout_url": "https://pay.ummah.com/checkout/d6c9...",
"purchase": { "total_amount": 2999, "currency": "USD" },
"payment": { "method": "card", "is_recurring_token": false },
"created_on": 1700000000
}{"error": "Not Found", "detail": "Object with this ID does not exist."}Resend Invoice Email
Re-sends the invoice email for this purchase to the client.
curl -X POST "https://gate.ummah.com/api/v1/purchases/{id}/resend_invoice/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/{id}/resend_invoice/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/resend_invoice/',
headers=headers
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/resend_invoice/',
headers=headers
)
print(response.json()){"status": "sent"}{"error": "Not Found", "detail": "Object with this ID does not exist."}Detach Payment Method
Delete the recurring token associated with this purchase, preventing future recurring charges.
curl -X POST "https://gate.ummah.com/api/v1/purchases/{id}/delete_recurring_token/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/purchases/{id}/delete_recurring_token/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/delete_recurring_token/',
headers=headers
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/purchases/{id}/delete_recurring_token/',
headers=headers
)
print(response.json()){"status": "deleted"}{"error": "Not Found", "detail": "Object with this ID does not exist."}List Payment Methods
Get the list of payment methods available for your purchase, filtered by country and currency.
curl -X GET "https://gate.ummah.com/api/v1/payment_methods/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/payment_methods/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/payment_methods/',
headers=headers
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/payment_methods/',
headers=headers
)
print(response.json()){
"payment_methods": [
{ "name": "card", "countries": ["US", "GB", "AE"], "currencies": ["USD", "GBP", "AED"] },
{ "name": "apple_pay", "countries": ["US", "GB"], "currencies": ["USD", "GBP"] }
]
}List Payout Methods
Get the list of payout methods available for your brand.
curl -X GET "https://gate.ummah.com/api/v1/payout_methods/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/payout_methods/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/payout_methods/',
headers=headers
)
print(response.json())import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/payout_methods/',
headers=headers
)
print(response.json()){"payout_methods": [{"name": "bank_transfer", "countries": ["US","GB"], "currencies": ["USD","GBP"]}]}Recurring Billing
Create billing templates for subscription plans, add subscribers, and let the gateway handle automatic renewal charges on your schedule.
Subscription Lifecycle
Subscribers progress through these states. Use the template client endpoints to pause or resume billing.
stateDiagram-v2
[*] --> Template: POST /billing_templates/
Template --> Subscriber: POST /add_subscriber/
Subscriber --> Active: First payment
Active --> Renewal: Billing cycle
Renewal --> Active: Payment success
Renewal --> Failed: Payment failure
Active --> Paused: PATCH status=paused
Paused --> Active: PATCH status=active
One-Time Invoicing
Send invoices directly to clients or generate them from billing templates. Each client receives a unique checkout link.
Send an Invoice
Send a one-time invoice to one or several clients. Each client receives a unique checkout/invoice link.
| Parameter | Description |
|---|---|
brand_idREQUIREDuuid | ID of the brand issuing the invoice. |
clientsREQUIREDarray | Array of client objects or client IDs to invoice. |
purchase.productsREQUIREDarray | Products to include in the invoice. |
purchase.currencyOPTIONALstring | 3-letter ISO currency code. |
curl -X POST "https://gate.ummah.com/api/v1/billing/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"brand_id": "409eb80e-...",
"clients": [
{
"email": "client@example.com"
}
],
"purchase": {
"products": [
{
"name": "Consulting",
"price": 50000
}
],
"currency": "USD"
}
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"brand_id": "409eb80e-...",
"clients": [
{
"email": "client@example.com"
}
],
"purchase": {
"products": [
{
"name": "Consulting",
"price": 50000
}
],
"currency": "USD"
}
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/billing/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"brand_id": "409eb80e-...",
"clients": [
{
"email": "client@example.com"
}
],
"purchase": {
"products": [
{
"name": "Consulting",
"price": 50000
}
],
"currency": "USD"
}
}
response = requests.post(
'https://gate.ummah.com/api/v1/billing/',
headers=headers,
json=data
)
print(response.json())[{
"id": "d6c9e9e0-1b5a-4c6e-8b3a-0f1a2b3c4d5e",
"status": "created",
"checkout_url": "https://pay.ummah.com/checkout/d6c9...",
"invoice_url": "https://pay.ummah.com/invoice/d6c9...",
"client": { "email": "customer@example.com", "full_name": "John Doe" },
"purchase": { "total_amount": 2999, "currency": "USD" },
"created_on": 1700000000
}]{"error": "Bad Request", "details": {"field": ["This field is required."]}}Create Billing Template
Create a reusable billing template for one-time invoices or recurring subscriptions. Set is_subscription: true and specify subscription_period for recurring billing.
| Parameter | Description |
|---|---|
purchaseREQUIREDobject | PurchaseDetails object: products, currency, etc. |
is_subscriptionREQUIREDboolean | true for subscription, false for one-time invoicing. |
brand_idREQUIREDuuid | ID of the brand for this template. |
subscription_periodOPTIONALstring | Billing period: day, week, month, year. |
number_of_billing_cyclesOPTIONALinteger | Limit billing cycles per client. 0 = unlimited. |
curl -X POST "https://gate.ummah.com/api/v1/billing_templates/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"brand_id": "409eb80e-...",
"is_subscription": true,
"purchase": {
"products": [
{
"name": "Monthly Plan",
"price": 999
}
],
"currency": "USD"
},
"subscription_period": "month"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"brand_id": "409eb80e-...",
"is_subscription": true,
"purchase": {
"products": [
{
"name": "Monthly Plan",
"price": 999
}
],
"currency": "USD"
},
"subscription_period": "month"
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/billing_templates/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"brand_id": "409eb80e-...",
"is_subscription": True,
"purchase": {
"products": [
{
"name": "Monthly Plan",
"price": 999
}
],
"currency": "USD"
},
"subscription_period": "month"
}
response = requests.post(
'https://gate.ummah.com/api/v1/billing_templates/',
headers=headers,
json=data
)
print(response.json()){
"id": "bt-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"is_subscription": true,
"purchase": { "currency": "USD", "total_amount": 999 },
"subscription_period": "month",
"brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}List Billing Templates
List all billing templates for your account.
curl -X GET "https://gate.ummah.com/api/v1/billing_templates/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/billing_templates/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/billing_templates/',
headers=headers
)
print(response.json())[{
"id": "bt-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"is_subscription": true,
"purchase": { "currency": "USD", "total_amount": 999 },
"subscription_period": "month",
"brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
"created_on": 1700000000
}]Retrieve Billing Template
Retrieve a billing template by its ID.
curl -X GET "https://gate.ummah.com/api/v1/billing_templates/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/billing_templates/{id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/billing_templates/{id}/',
headers=headers
)
print(response.json()){
"id": "bt-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"is_subscription": true,
"purchase": { "currency": "USD", "total_amount": 999 },
"subscription_period": "month",
"brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
"created_on": 1700000000
}{"error": "Not Found", "detail": "Object with this ID does not exist."}Update Billing Template
Replace all fields of a billing template.
| Parameter | Description |
|---|---|
purchaseREQUIREDobject | Updated PurchaseDetails object. |
is_subscriptionREQUIREDboolean | Subscription mode flag. |
curl -X PUT "https://gate.ummah.com/api/v1/billing_templates/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"purchase": {
"products": [
{
"name": "Updated Plan",
"price": 1299
}
],
"currency": "USD"
},
"is_subscription": true
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"purchase": {
"products": [
{
"name": "Updated Plan",
"price": 1299
}
],
"currency": "USD"
},
"is_subscription": true
};
const { data: result } = await axios.put(
'https://gate.ummah.com/api/v1/billing_templates/{id}/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"purchase": {
"products": [
{
"name": "Updated Plan",
"price": 1299
}
],
"currency": "USD"
},
"is_subscription": True
}
response = requests.put(
'https://gate.ummah.com/api/v1/billing_templates/{id}/',
headers=headers,
json=data
)
print(response.json()){
"id": "bt-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"is_subscription": true,
"purchase": { "currency": "USD", "total_amount": 999 },
"subscription_period": "month",
"brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Delete Billing Template
Delete a billing template by its ID. This does not cancel active subscriptions.
curl -X DELETE "https://gate.ummah.com/api/v1/billing_templates/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.delete(
'https://gate.ummah.com/api/v1/billing_templates/{id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.delete(
'https://gate.ummah.com/api/v1/billing_templates/{id}/',
headers=headers
)
print(response.status_code)(empty — 204 No Content){"error": "Not Found", "detail": "Object with this ID does not exist."}Send Invoice from Template
Send an invoice by generating a purchase from the template's data. Pass client details to generate a unique invoice for them.
| Parameter | Description |
|---|---|
clientOPTIONALobject | Client details (email, full_name, etc.). |
client_idOPTIONALuuid | ID of an existing Client object. |
curl -X POST "https://gate.ummah.com/api/v1/billing_templates/{id}/send_invoice/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"client": {
"email": "client@example.com",
"full_name": "John Doe"
}
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"client": {
"email": "client@example.com",
"full_name": "John Doe"
}
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/billing_templates/{id}/send_invoice/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"client": {
"email": "client@example.com",
"full_name": "John Doe"
}
}
response = requests.post(
'https://gate.ummah.com/api/v1/billing_templates/{id}/send_invoice/',
headers=headers,
json=data
)
print(response.json()){
"id": "d6c9e9e0-1b5a-4c6e-8b3a-0f1a2b3c4d5e",
"status": "created",
"checkout_url": "https://pay.ummah.com/checkout/d6c9...",
"invoice_url": "https://pay.ummah.com/invoice/d6c9...",
"client": { "email": "customer@example.com", "full_name": "John Doe" },
"purchase": { "total_amount": 2999, "currency": "USD" },
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Subscribe
Add a client to a subscription billing template. This activates their recurring billing cycle.
| Parameter | Description |
|---|---|
clientOPTIONALobject | Client details for the subscriber. |
client_idOPTIONALuuid | ID of an existing Client to subscribe. |
curl -X POST "https://gate.ummah.com/api/v1/billing_templates/{id}/add_subscriber/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"client": {
"email": "subscriber@example.com"
}
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"client": {
"email": "subscriber@example.com"
}
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/billing_templates/{id}/add_subscriber/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"client": {
"email": "subscriber@example.com"
}
}
response = requests.post(
'https://gate.ummah.com/api/v1/billing_templates/{id}/add_subscriber/',
headers=headers,
json=data
)
print(response.json()){
"id": "btc-a1b2c3d4-e5f6-7890",
"client": { "email": "subscriber@example.com" },
"is_subscription": true,
"status": "active",
"next_billing_on": 1703000000,
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}List Subscribers
List all billing template clients (subscribers) associated with this template.
curl -X GET "https://gate.ummah.com/api/v1/billing_templates/{id}/clients/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/billing_templates/{id}/clients/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/billing_templates/{id}/clients/',
headers=headers
)
print(response.json())[{
"id": "btc-a1b2c3d4-e5f6-7890",
"client": { "email": "subscriber@example.com" },
"is_subscription": true,
"status": "active",
"next_billing_on": 1703000000,
"created_on": 1700000000
}]Get Subscriber
Retrieve details of a specific billing template client by their ID.
curl -X GET "https://gate.ummah.com/api/v1/billing_templates/{id}/clients/{client_id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/billing_templates/{id}/clients/{client_id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/billing_templates/{id}/clients/{client_id}/',
headers=headers
)
print(response.json()){
"id": "btc-a1b2c3d4-e5f6-7890",
"client": { "email": "subscriber@example.com" },
"is_subscription": true,
"status": "active",
"next_billing_on": 1703000000,
"created_on": 1700000000
}{"error": "Not Found", "detail": "Object with this ID does not exist."}Update Subscriber
Partially update a billing template client — for example, pause or resume their subscription.
| Parameter | Description |
|---|---|
statusOPTIONALstring | Subscription status: active or paused. |
curl -X PATCH "https://gate.ummah.com/api/v1/billing_templates/{id}/clients/{client_id}/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"status": "paused"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"status": "paused"
};
const { data: result } = await axios.patch(
'https://gate.ummah.com/api/v1/billing_templates/{id}/clients/{client_id}/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"status": "paused"
}
response = requests.patch(
'https://gate.ummah.com/api/v1/billing_templates/{id}/clients/{client_id}/',
headers=headers,
json=data
)
print(response.json()){
"id": "btc-a1b2c3d4-e5f6-7890",
"client": { "email": "subscriber@example.com" },
"is_subscription": true,
"status": "active",
"next_billing_on": 1703000000,
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Customer Management
Create and manage customer records with saved payment methods. Use recurring tokens for one-click payments and subscription renewals.
Create a Client
Create a new client record to store customer contact information.
| Parameter | Description |
|---|---|
emailREQUIREDstring (email) | Client email address. |
full_nameOPTIONALstring | Client full name. |
phoneOPTIONALstring | Client phone number in E.164 format. |
street_addressOPTIONALstring | Billing street address. |
countryOPTIONALstring | 2-letter ISO country code. |
cityOPTIONALstring | City. |
zip_codeOPTIONALstring | ZIP / postal code. |
curl -X POST "https://gate.ummah.com/api/v1/clients/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"email": "client@example.com",
"full_name": "John Doe",
"phone": "+1234567890",
"country": "US"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"email": "client@example.com",
"full_name": "John Doe",
"phone": "+1234567890",
"country": "US"
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/clients/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"email": "client@example.com",
"full_name": "John Doe",
"phone": "+1234567890",
"country": "US"
}
response = requests.post(
'https://gate.ummah.com/api/v1/clients/',
headers=headers,
json=data
)
print(response.json()){
"id": "c1a2b3c4-d5e6-f7a8-b9c0-d1e2f3a4b5c6",
"email": "client@example.com",
"full_name": "John Doe",
"phone": "+1234567890",
"country": "US",
"type": "personal",
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}List Clients
Retrieve a paginated list of all client records for your account.
curl -X GET "https://gate.ummah.com/api/v1/clients/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/clients/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/clients/',
headers=headers
)
print(response.json())[{
"id": "c1a2b3c4-d5e6-f7a8-b9c0-d1e2f3a4b5c6",
"email": "client@example.com",
"full_name": "John Doe",
"phone": "+1234567890",
"country": "US",
"type": "personal",
"created_on": 1700000000
}]Retrieve a Client
Retrieve a specific client by their ID.
curl -X GET "https://gate.ummah.com/api/v1/clients/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/clients/{id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/clients/{id}/',
headers=headers
)
print(response.json()){
"id": "c1a2b3c4-d5e6-f7a8-b9c0-d1e2f3a4b5c6",
"email": "client@example.com",
"full_name": "John Doe",
"phone": "+1234567890",
"country": "US",
"type": "personal",
"created_on": 1700000000
}{"error": "Not Found", "detail": "Object with this ID does not exist."}Update a Client
Replace all fields of a client record.
| Parameter | Description |
|---|---|
emailREQUIREDstring | Client email address. |
curl -X PUT "https://gate.ummah.com/api/v1/clients/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"email": "updated@example.com",
"full_name": "Jane Doe",
"country": "GB"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"email": "updated@example.com",
"full_name": "Jane Doe",
"country": "GB"
};
const { data: result } = await axios.put(
'https://gate.ummah.com/api/v1/clients/{id}/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"email": "updated@example.com",
"full_name": "Jane Doe",
"country": "GB"
}
response = requests.put(
'https://gate.ummah.com/api/v1/clients/{id}/',
headers=headers,
json=data
)
print(response.json()){
"id": "c1a2b3c4-d5e6-f7a8-b9c0-d1e2f3a4b5c6",
"email": "client@example.com",
"full_name": "John Doe",
"phone": "+1234567890",
"country": "US",
"type": "personal",
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Partially Update a Client
Update specific fields of a client record without replacing the entire object.
curl -X PATCH "https://gate.ummah.com/api/v1/clients/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"full_name": "Updated Name"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"full_name": "Updated Name"
};
const { data: result } = await axios.patch(
'https://gate.ummah.com/api/v1/clients/{id}/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"full_name": "Updated Name"
}
response = requests.patch(
'https://gate.ummah.com/api/v1/clients/{id}/',
headers=headers,
json=data
)
print(response.json()){
"id": "c1a2b3c4-d5e6-f7a8-b9c0-d1e2f3a4b5c6",
"email": "client@example.com",
"full_name": "John Doe",
"phone": "+1234567890",
"country": "US",
"type": "personal",
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Delete a Client
Permanently delete a client record and their associated data.
curl -X DELETE "https://gate.ummah.com/api/v1/clients/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.delete(
'https://gate.ummah.com/api/v1/clients/{id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.delete(
'https://gate.ummah.com/api/v1/clients/{id}/',
headers=headers
)
print(response.status_code)(empty — 204 No Content){"error": "Not Found", "detail": "Object with this ID does not exist."}List Payment Methods
List all saved recurring payment tokens for a client (e.g. saved card tokens).
curl -X GET "https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/',
headers=headers
)
print(response.json())[{
"id": "tok-a1b2c3d4-e5f6-7890",
"payment_method": "card",
"description": "Visa **** 4242",
"created_on": 1700000000
}]Get Payment Method
Retrieve a specific recurring payment token by its ID.
curl -X GET "https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/{token_id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/{token_id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/{token_id}/',
headers=headers
)
print(response.json()){
"id": "tok-a1b2c3d4-e5f6-7890",
"payment_method": "card",
"description": "Visa **** 4242",
"created_on": 1700000000
}{"error": "Not Found", "detail": "Object with this ID does not exist."}Delete Payment Method
Delete a saved recurring token, preventing it from being used for future charges.
curl -X DELETE "https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/{token_id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.delete(
'https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/{token_id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.delete(
'https://gate.ummah.com/api/v1/clients/{id}/recurring_tokens/{token_id}/',
headers=headers
)
print(response.status_code)(empty — 204 No Content){"error": "Not Found", "detail": "Object with this ID does not exist."}Webhook Verification Guide
Every webhook delivery includes an X-Signature header containing an HMAC-SHA256 digest of the raw request body, signed with your webhook secret. Always verify this header before processing any event.
whsec_). Store it in an environment variable.express.json()) will change whitespace and break the signature check.HMAC-SHA256(rawBody, webhookSecret) and compare it to the value in the X-Signature header using a constant-time comparison to prevent timing attacks.const express = require('express');
const crypto = require('crypto');
const app = express();
const SECRET = process.env.WEBHOOK_SECRET; // whsec_...
// IMPORTANT: use raw body parser — do NOT use express.json() here
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sigHeader = req.headers['x-signature'];
const rawBody = req.body; // Buffer
const expected = crypto
.createHmac('sha256', SECRET)
.update(rawBody)
.digest('hex');
const trusted = crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(sigHeader)
);
if (!trusted) {
return res.status(403).json({ error: 'Invalid signature' });
}
const event = JSON.parse(rawBody);
console.log('Event received:', event.type);
// Handle event types
switch (event.type) {
case 'purchase.paid':
// fulfil the order
break;
case 'purchase.failed':
// notify the customer
break;
default:
console.log('Unhandled event type:', event.type);
}
res.sendStatus(200);
});
app.listen(3000);import hmac
import hashlib
import os
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ['WEBHOOK_SECRET'].encode() # whsec_...
@app.route('/webhook', methods=['POST'])
def webhook():
sig_header = request.headers.get('X-Signature', '')
raw_body = request.get_data() # raw bytes — do NOT use request.json here
expected = hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, sig_header):
abort(403)
event = request.get_json(force=True)
print('Event received:', event.get('type'))
# Handle event types
if event['type'] == 'purchase.paid':
pass # fulfil the order
elif event['type'] == 'purchase.failed':
pass # notify the customer
return '', 200
if __name__ == '__main__':
app.run(port=3000)<?php
$secret = getenv('WEBHOOK_SECRET'); // whsec_...
$payload = file_get_contents('php://input'); // raw body
$sigHeader = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected, $sigHeader)) {
http_response_code(403);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
$event = json_decode($payload, true);
error_log('Event received: ' . $event['type']);
switch ($event['type']) {
case 'purchase.paid':
// fulfil the order
break;
case 'purchase.failed':
// notify the customer
break;
default:
error_log('Unhandled event: ' . $event['type']);
}
http_response_code(200);Security Best Practices
Follow these guidelines to keep your integration secure:
X-Signature header using your public key. Never trust unverified payloads.sk_live_* keys in environment variables. Never commit them to source control or expose in client-side code.id to deduplicate events and prevent double-processing.Webhook Endpoints
Register webhook endpoints to receive real-time notifications. The gateway signs each delivery with HMAC-SHA256 so you can verify authenticity.
Create a Webhook
Register a new webhook endpoint to receive event notifications.
| Parameter | Description |
|---|---|
callbackREQUIREDstring (url) | HTTPS URL to POST event payloads to. |
titleOPTIONALstring | Friendly name for this webhook. |
eventsOPTIONALarray | List of event types to subscribe to. e.g. ["purchase.paid"]. |
all_eventsOPTIONALboolean | Set to true to receive all event types. |
curl -X POST "https://gate.ummah.com/api/v1/webhooks/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"callback": "https://mysite.com/webhook",
"title": "Order Notifications",
"events": [
"purchase.paid",
"purchase.payment_failure"
]
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"callback": "https://mysite.com/webhook",
"title": "Order Notifications",
"events": [
"purchase.paid",
"purchase.payment_failure"
]
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/webhooks/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"callback": "https://mysite.com/webhook",
"title": "Order Notifications",
"events": [
"purchase.paid",
"purchase.payment_failure"
]
}
response = requests.post(
'https://gate.ummah.com/api/v1/webhooks/',
headers=headers,
json=data
)
print(response.json()){
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "My Webhook",
"callback": "https://mysite.com/webhook",
"events": ["purchase.paid", "purchase.payment_failure"],
"all_events": false,
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}List Webhooks
Retrieve all registered webhook endpoints for your account.
curl -X GET "https://gate.ummah.com/api/v1/webhooks/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/webhooks/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/webhooks/',
headers=headers
)
print(response.json())[{
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "My Webhook",
"callback": "https://mysite.com/webhook",
"events": ["purchase.paid", "purchase.payment_failure"],
"all_events": false,
"created_on": 1700000000
}]Retrieve a Webhook
Retrieve a specific webhook by its ID.
curl -X GET "https://gate.ummah.com/api/v1/webhooks/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/webhooks/{id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/webhooks/{id}/',
headers=headers
)
print(response.json()){
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "My Webhook",
"callback": "https://mysite.com/webhook",
"events": ["purchase.paid", "purchase.payment_failure"],
"all_events": false,
"created_on": 1700000000
}{"error": "Not Found", "detail": "Object with this ID does not exist."}Update a Webhook
Replace all fields of a webhook endpoint.
curl -X PUT "https://gate.ummah.com/api/v1/webhooks/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"callback": "https://mysite.com/new-webhook",
"title": "Updated Webhook",
"all_events": true
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"callback": "https://mysite.com/new-webhook",
"title": "Updated Webhook",
"all_events": true
};
const { data: result } = await axios.put(
'https://gate.ummah.com/api/v1/webhooks/{id}/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"callback": "https://mysite.com/new-webhook",
"title": "Updated Webhook",
"all_events": True
}
response = requests.put(
'https://gate.ummah.com/api/v1/webhooks/{id}/',
headers=headers,
json=data
)
print(response.json()){
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "My Webhook",
"callback": "https://mysite.com/webhook",
"events": ["purchase.paid", "purchase.payment_failure"],
"all_events": false,
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Partially Update a Webhook
Update specific fields of a webhook endpoint.
curl -X PATCH "https://gate.ummah.com/api/v1/webhooks/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"title": "Renamed Webhook"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"title": "Renamed Webhook"
};
const { data: result } = await axios.patch(
'https://gate.ummah.com/api/v1/webhooks/{id}/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"title": "Renamed Webhook"
}
response = requests.patch(
'https://gate.ummah.com/api/v1/webhooks/{id}/',
headers=headers,
json=data
)
print(response.json()){
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "My Webhook",
"callback": "https://mysite.com/webhook",
"events": ["purchase.paid", "purchase.payment_failure"],
"all_events": false,
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}Delete a Webhook
Delete a webhook endpoint. No further deliveries will be sent.
curl -X DELETE "https://gate.ummah.com/api/v1/webhooks/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.delete(
'https://gate.ummah.com/api/v1/webhooks/{id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.delete(
'https://gate.ummah.com/api/v1/webhooks/{id}/',
headers=headers
)
print(response.status_code)(empty — 204 No Content){"error": "Not Found", "detail": "Object with this ID does not exist."}List Webhook Deliveries
List recent webhook delivery attempts, including response codes and payloads. Useful for debugging missed events.
curl -X GET "https://gate.ummah.com/api/v1/webhooks/deliveries/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/webhooks/deliveries/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/webhooks/deliveries/',
headers=headers
)
print(response.json())[{
"id": "wh-delivery-a1b2",
"event": "purchase.paid",
"status": "delivered",
"response_code": 200,
"sent_at": 1700001234,
"payload": { "event": "purchase.paid", "object": { "id": "d6c9..." } }
}]Reporting & Financials
Access real-time balance data, transaction turnover reports, and generate downloadable financial statements in CSV or XLSX format.
Company Balance
Get the current balance of your company account, broken down by currency.
curl -X GET "https://gate.ummah.com/api/v1/account/json/balance/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/account/json/balance/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/account/json/balance/',
headers=headers
)
print(response.json()){
"balance": [
{ "currency": "USD", "amount": 125000 },
{ "currency": "EUR", "amount": 87500 }
]
}Company Turnover
Get transaction turnover data for your company, grouped by currency and time period.
curl -X GET "https://gate.ummah.com/api/v1/account/json/turnover/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/account/json/turnover/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/account/json/turnover/',
headers=headers
)
print(response.json()){
"turnover": [
{ "currency": "USD", "paid_amount": 1250000, "period": "2024-01" },
{ "currency": "USD", "paid_amount": 980000, "period": "2024-02" }
]
}Get Balance Data
Retrieve detailed balance data for your account.
curl -X GET "https://gate.ummah.com/api/v1/balance/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/balance/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/balance/',
headers=headers
)
print(response.json()){
"balance": [
{ "currency": "USD", "amount": 125000 },
{ "currency": "EUR", "amount": 87500 }
]
}Schedule Statement Generation
Schedule a financial statement for generation. Once processing completes, a download_url becomes available.
| Parameter | Description |
|---|---|
formatREQUIREDstring | Output format: csv or xlsx. |
timezoneOPTIONALstring | Timezone for timestamps, e.g. UTC, Asia/Dubai. |
query_stringOPTIONALstring | Query parameters to filter statement data. |
curl -X POST "https://gate.ummah.com/api/v1/company_statements/" \
-H "Authorization: Bearer $SECRET_KEY"
-H "Content-Type: application/json" \
-d '{
"format": "csv",
"timezone": "UTC"
}'const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const data = {
"format": "csv",
"timezone": "UTC"
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/company_statements/',
data,
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
'Content-Type': 'application/json',
}
data = {
"format": "csv",
"timezone": "UTC"
}
response = requests.post(
'https://gate.ummah.com/api/v1/company_statements/',
headers=headers,
json=data
)
print(response.json()){
"id": "stmt-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "company",
"format": "csv",
"status": "processing",
"download_url": null,
"timezone": "UTC",
"created_on": 1700000000
}{"error": "Bad Request", "details": {"field": ["This field is required."]}}List Statements
List all generated and pending statements for your account.
curl -X GET "https://gate.ummah.com/api/v1/company_statements/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/company_statements/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/company_statements/',
headers=headers
)
print(response.json())[{
"id": "stmt-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "company",
"format": "csv",
"status": "processing",
"download_url": null,
"timezone": "UTC",
"created_on": 1700000000
}]Retrieve a Statement
Retrieve a statement by its ID. Check status and download_url.
curl -X GET "https://gate.ummah.com/api/v1/company_statements/{id}/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/company_statements/{id}/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/company_statements/{id}/',
headers=headers
)
print(response.json()){
"id": "stmt-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "company",
"format": "csv",
"status": "processing",
"download_url": "https://storage.ummah.com/stmt/...",
"timezone": "UTC",
"created_on": 1700000000
}{"error": "Not Found", "detail": "Object with this ID does not exist."}Cancel Statement
Cancel a pending statement generation.
curl -X POST "https://gate.ummah.com/api/v1/company_statements/{id}/cancel/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.post(
'https://gate.ummah.com/api/v1/company_statements/{id}/cancel/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.post(
'https://gate.ummah.com/api/v1/company_statements/{id}/cancel/',
headers=headers
)
print(response.json()){"status": "cancelled"}{"error": "Not Found", "detail": "Object with this ID does not exist."}Get Callback Public Key
Retrieve the public key used to verify HMAC-SHA256 signatures on callback payloads. Use this to validate that incoming callbacks genuinely come from the gateway.
curl -X GET "https://gate.ummah.com/api/v1/public_key/" \
-H "Authorization: Bearer $SECRET_KEY"const axios = require('axios');
// import axios from 'axios'; // ES Modules
const config = {
headers: {
Authorization: `Bearer ${process.env.SECRET_KEY}`,
'Content-Type': 'application/json',
},
};
const { data: result } = await axios.get(
'https://gate.ummah.com/api/v1/public_key/',
config
);
console.log(result);import requests
import os
headers = {
'Authorization': f'Bearer {os.environ["SECRET_KEY"]}',
}
response = requests.get(
'https://gate.ummah.com/api/v1/public_key/',
headers=headers
)
print(response.json()){
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----"
}Common Patterns
Recipes for common integration scenarios.
One-Click Checkout
Save a card on the customer's first purchase using force_recurring: true. On subsequent orders, charge them directly server-side — no redirect, no re-entry of card details.
force_recurring: true. After the customer completes checkout, the purchase object will contain a recurring_token.purchase.recurring_token and purchase.id in your database against the customer record.POST /purchases/{id}/charge/ with the saved recurring_token. No redirect needed.const axios = require('axios');
const client = axios.create({
baseURL: 'https://gate.ummah.com/api/v1',
headers: { Authorization: `Bearer ${process.env.SECRET_KEY}` }
});
// --- First purchase: save card ---
const first = await client.post('/purchases/', {
amount: '59.99',
currency: 'USD',
name: 'Order #1001',
force_recurring: true, // request card save
success_redirect: 'https://yourapp.com/success',
failure_redirect: 'https://yourapp.com/failure',
});
// Redirect customer to first.data.checkout_url
// After payment, first.data.recurring_token is available
// --- Future purchase: one-click charge ---
const newPurchase = await client.post('/purchases/', {
amount: '79.99',
currency: 'USD',
name: 'Order #1002',
skip_capture: false,
});
await client.post(`/purchases/${newPurchase.data.id}/charge/`, {
recurring_token: savedRecurringToken, // from first purchase
});import requests
import os
BASE = 'https://gate.ummah.com/api/v1'
headers = {'Authorization': f'Bearer {os.environ["SECRET_KEY"]}'}
# --- First purchase: save card ---
first = requests.post(f'{BASE}/purchases/', headers=headers, json={
'amount': '59.99',
'currency': 'USD',
'name': 'Order #1001',
'force_recurring': True,
'success_redirect': 'https://yourapp.com/success',
'failure_redirect': 'https://yourapp.com/failure',
}).json()
# Redirect customer to first['checkout_url']
# After payment, first['recurring_token'] is available
# --- Future purchase: one-click charge ---
new_purchase = requests.post(f'{BASE}/purchases/', headers=headers, json={
'amount': '79.99',
'currency': 'USD',
'name': 'Order #1002',
}).json()
requests.post(
f'{BASE}/purchases/{new_purchase["id"]}/charge/',
headers=headers,
json={'recurring_token': saved_recurring_token}
)Pre-Authorization & Capture
Hold funds at booking time with skip_capture: true and only settle when you ship or provide the service. Void the hold anytime before capture if the order is cancelled.
skip_capture: true. The customer is redirected to checkout. Funds are held but not settled — no money moves yet.POST /purchases/{id}/capture/ with the final amount (can be less than or equal to the authorized amount). Funds are now settled.POST /purchases/{id}/release/ to void the authorization. Funds are released back to the customer immediately.const axios = require('axios');
const client = axios.create({
baseURL: 'https://gate.ummah.com/api/v1',
headers: { Authorization: `Bearer ${process.env.SECRET_KEY}` }
});
// Step 1: Authorize (hold) funds
const purchase = await client.post('/purchases/', {
amount: '150.00',
currency: 'USD',
name: 'Hotel Booking #882',
skip_capture: true, // hold — do not settle yet
success_redirect: 'https://yourapp.com/success',
failure_redirect: 'https://yourapp.com/failure',
});
// Redirect customer: purchase.data.checkout_url
// Step 2: Capture when ready (e.g. at check-out)
await client.post(`/purchases/${purchase.data.id}/capture/`, {
amount: '135.00' // may differ from authorized amount
});
// --- OR ---
// Step 3: Void if cancelled
await client.post(`/purchases/${purchase.data.id}/release/`);import requests
import os
BASE = 'https://gate.ummah.com/api/v1'
headers = {'Authorization': f'Bearer {os.environ["SECRET_KEY"]}'}
# Step 1: Authorize (hold) funds
purchase = requests.post(f'{BASE}/purchases/', headers=headers, json={
'amount': '150.00',
'currency': 'USD',
'name': 'Hotel Booking #882',
'skip_capture': True,
'success_redirect': 'https://yourapp.com/success',
'failure_redirect': 'https://yourapp.com/failure',
}).json()
# Redirect customer: purchase['checkout_url']
# Step 2: Capture when ready
requests.post(
f'{BASE}/purchases/{purchase["id"]}/capture/',
headers=headers,
json={'amount': '135.00'}
)
# --- OR ---
# Step 3: Void if cancelled
requests.post(f'{BASE}/purchases/{purchase["id"]}/release/', headers=headers)Partial Refunds
Pass an amount to POST /purchases/{id}/refund/ to refund less than the full total. You can issue multiple partial refunds as long as the cumulative amount does not exceed the original captured amount.
Subscription with Trial Period
Create a billing template, subscribe the customer, then pause billing during the trial. Resume when the trial ends.
POST /billing_templates/ including amount, currency, and billing period.POST /billing_templates/{id}/add_subscriber/ to enrol the customer. Set status: "paused" if starting a free trial.PATCH /billing_templates/{id}/clients/{client_id}/ with {"status": "active"} to start billing.Webhook Event Simulator
Preview the exact JSON payload your server receives for each event. Copy the payload or replay it via cURL to test your webhook handler locally.
ngrok http 3000 to expose your local server, then set your webhook URL in the dashboard to the ngrok tunnel. Select an event above, copy the cURL replay command, and fire it against your handler to test end-to-end without a real payment.
Error Codes
All API errors return a consistent JSON body with a machine-readable code, a human-readable message, and an optional details object for field-level validation errors.
{
"error": "card_declined",
"message": "The card was declined by the issuing bank.",
"details": {
"decline_code": "insufficient_funds",
"param": "payment_method"
}
}Error Code Reference
| Code | HTTP Status | Description | Retryable? |
|---|---|---|---|
insufficient_funds | 402 | The card or account has insufficient funds to complete the transaction. | No — ask customer to use a different payment method |
card_declined | 402 | The card was declined by the issuing bank. Check details.decline_code for more info. | No — ask customer to contact their bank |
invalid_card | 400 | Card number, expiry, or CVV is invalid or malformed. | No — fix the card details and retry |
expired_card | 402 | The card's expiry date has passed. | No — ask customer for a new card |
authentication_required | 402 | 3D Secure authentication is required. Redirect the customer to the checkout URL. | Yes — redirect to checkout_url |
invalid_api_key | 401 | The API key is missing, malformed, or revoked. | No — check your Authorization header |
rate_limit_exceeded | 429 | Too many requests in a short window. Slow down and retry. | Yes — retry with exponential backoff |
server_error | 500 | Unexpected internal error. Our team is automatically notified. | Yes — retry after a short delay |
HTTP Status Summary
| HTTP Status | Meaning | Common Cause |
|---|---|---|
400 | Bad Request | Missing required field, invalid format, or validation error |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Key does not have permission for this resource |
404 | Not Found | Object ID does not exist |
409 | Conflict | Operation not allowed in current state (e.g. refunding an unpaid purchase) |
422 | Unprocessable Entity | Request is well-formed but semantically invalid (e.g. duplicate idempotency key with different body) |
429 | Rate Limited | Too many requests. Back off and retry with exponential delay |
500 / 503 | Server Error | Internal or temporary error. Retry after a short delay |
Retry Guidance
invalid_card, invalid_api_key, or 400 Bad Request indicate a problem with your request data. Retrying without fixing the issue will always fail.Retry-After response header, when present, gives the minimum wait time.Idempotency-Key: <uuid> header on all POST requests. If your request times out and you are unsure whether it succeeded, retry with the same key — the gateway will return the original response without creating a duplicate.Full API Reference
Quick index of all 47 endpoints. Click any row to jump to the full documentation.