Providers Paylinks API
Unified payment link management across all BNPL and direct payment providers
Unified Providers Paylinks API
A single, provider-agnostic API for creating and managing BNPL payment links (Tabby, Tamara, MisPay). GET /api/v1/providers also lists gateway sync processors (stripe, moyasar, tap, dinero, paypal, hyperpay); those IDs are not valid for POST .../paylinks — use Payments Orders or schedule the mapped integration app instead.
All endpoints require authentication via Bearer token. The provider field in create requests determines which payment provider to use.
Supported Providers
| Provider | Type | Checkout / role | Regions |
|---|---|---|---|
tabby | bnpl | QR code paylinks | KSA, UAE, Kuwait |
tamara | bnpl | SMS paylinks | KSA, UAE, Bahrain |
mispay | bnpl | QR code paylinks | KSA |
stripe | gateway_sync | Stripe PaymentIntents sync (stripe-payments) | Global (account) |
moyasar | gateway_sync | Moyasar payments sync (moyasar-payments) | MENA |
tap | gateway_sync | Tap charges list sync (tap-payments) | GCC / Tap markets |
dinero | gateway_sync | Dinero status refresh (dinero-payments) | KSA / Dinero markets |
paypal | gateway_sync | PayPal reporting sync (paypal-commerce) | Global (account) |
hyperpay | gateway_sync | OPPWA query sync (hyperpay-checkout) | Per acquirer / host |
List Providers
Returns all registered payment providers and their metadata.
GET /api/v1/providers
Authorization: Bearer <token>Response
Each entry includes id, name, description, type, regions, and when applicable app_slug (integration app used by Payments Orders).
{
"providers": [
{
"id": "dinero",
"name": "Dinero Pay",
"description": "Dinero Pay: refresh configured payment_ids…",
"type": "gateway_sync",
"regions": "KSA and supported Dinero markets",
"app_slug": "dinero-payments"
},
{
"id": "mispay",
"name": "MisPay",
"description": "Split-in-4 BNPL with QR code checkout for POS",
"type": "bnpl",
"regions": "KSA",
"app_slug": "mispay-pos-paylinks"
}
],
"total": 9
}Provider Configuration
Returns provider-specific configuration, required fields, and endpoint documentation.
GET /api/v1/providers/config/{provider}
Authorization: Bearer <token>Create Payment Link
Creates a BNPL payment link using the specified provider.
POST /api/v1/providers/paylinks
Authorization: Bearer <token>
Content-Type: application/jsonCommon Fields
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | ✅ | BNPL provider ID only: tabby, tamara, mispay (not stripe / moyasar / tap / dinero) |
org_app_id | string | ✅ | Organization app ID for the installed provider app |
order_id | string | ✅ | Your order reference ID |
amount | string/number | ✅ | Payment amount (e.g. "100.00") |
currency | string | ✅ | Currency code (SAR, AED, KWD) |
description | string | Order description | |
buyer_name | string | Customer name | |
buyer_email | string | Customer email | |
buyer_phone | string | Customer phone | |
lang | string | Checkout language (ar or en) | |
items | array | Line items | |
metadata | object | Provider-specific metadata |
Provider-Specific Fields
Tamara
| Field | Type | Description |
|---|---|---|
phone_number | string | Required. Customer phone for SMS checkout |
payment_type | string | pay_by_instalments (default) or pay_by_later |
store_code | string | Store identifier for multi-store setups |
locale | string | Locale for checkout page (defaults to ar_SA) |
Example — Tabby
curl -X POST "https://linkit.works/api/v1/providers/paylinks" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"provider": "tabby",
"org_app_id": "YOUR_ORG_APP_ID",
"order_id": "POS-1234",
"amount": "150.00",
"currency": "SAR",
"description": "In-store purchase",
"buyer_phone": "0500000001"
}'const res = await fetch('https://linkit.works/api/v1/providers/paylinks', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'tabby',
org_app_id: 'YOUR_ORG_APP_ID',
order_id: 'POS-1234',
amount: '150.00',
currency: 'SAR',
description: 'In-store purchase',
buyer_phone: '0500000001',
}),
});
const data = await res.json();
// data.checkout_url → redirect customer
// data.qr_code_url → display QR to customerResponse (201 Created)
{
"success": true,
"provider": "tabby",
"paylink_id": "abc123",
"session_id": "sess_xxxxx",
"payment_id": "pay_xxxxx",
"checkout_url": "https://checkout.tabby.sa/...",
"qr_code_url": "https://checkout.tabby.sa/qr/...",
"status": "created",
"order_id": "POS-1234"
}Example — Tamara
curl -X POST "https://linkit.works/api/v1/providers/paylinks" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"provider": "tamara",
"org_app_id": "YOUR_ORG_APP_ID",
"order_id": "POS-5678",
"amount": "200.00",
"currency": "SAR",
"phone_number": "+966500000001"
}'Get Payment Link Status
GET /api/v1/providers/paylinks/{id}
Authorization: Bearer <token>Retrieves the current status of a payment link. Automatically refreshes status from the provider API when possible.
Response
{
"id": "abc123",
"provider": "tabby",
"org_app_id": "...",
"order_id": "POS-1234",
"status": "authorized",
"amount": "150.00",
"currency": "SAR",
"checkout_url": "https://checkout.tabby.sa/...",
"qr_code_url": "https://checkout.tabby.sa/qr/..."
}List Payment Links
GET /api/v1/providers/paylinks?provider=tabby&org_app_id=YOUR_ORG_APP_ID
Authorization: Bearer <token>Optional query parameters:
provider— Filter by provider (e.g.tabby,tamara,mispay)org_app_id— Filter by organization app
Capture/Finalize Payment
Captures (Tabby/Tamara) or finalizes (MisPay) a payment. Call this after the customer has completed checkout.
POST /api/v1/providers/paylinks/{id}/capture
Authorization: Bearer <token>
Content-Type: application/jsonOptional Body
| Field | Type | Description |
|---|---|---|
amount | string | Capture amount (defaults to full order amount) |
reference_id | string | Idempotency key for the capture |
Response
{
"success": true,
"provider": "tabby",
"paylink_id": "abc123",
"payment_id": "pay_xxxxx",
"status": "CLOSED",
"amount": "150.00"
}Cancel Payment Link
Cancels a pending payment link. Attempts to cancel on the provider side if possible.
POST /api/v1/providers/paylinks/{id}/cancel
Authorization: Bearer <token>Response
{
"success": true,
"paylink_id": "abc123",
"provider": "tabby",
"status": "cancelled"
}Migration from Legacy Endpoints
The provider-specific legacy endpoints (/api/v1/tabby/paylinks, /api/v1/tamara/paylinks, /api/v1/mispay/paylinks) have been permanently removed. All payment link operations must use the unified /api/v1/providers/paylinks endpoints.
Migration Reference
If you were previously using legacy endpoints, update your integration as follows:
| Removed Endpoint | Replacement |
|---|---|
POST /api/v1/{provider}/paylinks | POST /api/v1/providers/paylinks with "provider": "{provider}" |
GET /api/v1/{provider}/paylinks/{id} | GET /api/v1/providers/paylinks/{id} |
POST /api/v1/{provider}/paylinks/{id}/capture | POST /api/v1/providers/paylinks/{id}/capture |
POST /api/v1/{provider}/paylinks/{id}/cancel | POST /api/v1/providers/paylinks/{id}/cancel |
GET /api/v1/providers/{provider}/config | GET /api/v1/providers/config/{provider} |
POS Integration Flow
The typical POS integration flow using the unified API:
- Create — Cashier creates a payment link via
POST /api/v1/providers/paylinkswith the desiredprovider - Display — Show the QR code (Tabby/MisPay) or confirm SMS sent (Tamara)
- Wait — Customer completes checkout on their device
- Webhook — Provider sends status update to the provider-specific webhook endpoint
- Capture — Call
POST /api/v1/providers/paylinks/{id}/captureto finalize - Done — Order is paid, receipt is printed