Overview
REST API for approved business accounts. List plans, read the business balance, submit KYC, and request and manage cards. Requests and responses are JSON over HTTPS.
https://api.paymore.io/v1PublicService index
Returns the service name, version, and route list. GET https://api.paymore.io/ and GET https://api.paymore.io/v1/ return the same body. The status field describes the index. It is not an uptime guarantee.
Parameters
This route has no parameters.
curl "https://api.paymore.io/v1"Response
{
"name": "PayMore API",
"version": "v1",
"status": "operational",
"base_url": "https://api.paymore.io/v1",
"documentation": "https://paymore.io/developers",
"endpoints": {
"public": ["GET /plans"],
"account": ["GET /balance", "GET /account", "GET /transactions"],
"kyc": ["POST /kyc/submit", "GET /kyc/{external_user_id}", "GET /end-users"],
"cards": [
"POST /cards/issue",
"GET /cards",
"GET /cards/{card_id}",
"POST /cards/{card_id}/fund",
"POST /cards/{card_id}/unload",
"POST /cards/{card_id}/freeze",
"POST /cards/{card_id}/unfreeze"
]
}
}Authentication
Send the key in the X-API-Key header. Authorization: Bearer is also accepted. A live key starts with pm_live_. Public routes do not require a key.
The key can spend the business balance. Use it only from your server. If a key is exposed, write to PayMore to revoke it.
curl "https://api.paymore.io/v1/balance" \
-H "X-API-Key: pm_live_xxx"Response
{
"balance": 1500,
"currency": "USD"
}Base URL
Paths below are relative to this base unless a full URL is shown.
https://api.paymore.io/v1
curl "https://api.paymore.io/v1"Response
{
"name": "PayMore API",
"version": "v1",
"status": "operational",
"base_url": "https://api.paymore.io/v1",
"documentation": "https://paymore.io/developers",
"endpoints": {
"public": ["GET /plans"],
"account": ["GET /balance", "GET /account", "GET /transactions"],
"kyc": ["POST /kyc/submit", "GET /kyc/{external_user_id}", "GET /end-users"],
"cards": [
"POST /cards/issue",
"GET /cards",
"GET /cards/{card_id}",
"POST /cards/{card_id}/fund",
"POST /cards/{card_id}/unload",
"POST /cards/{card_id}/freeze",
"POST /cards/{card_id}/unfreeze"
]
}
}Errors
An error is a JSON body with an error string. Some errors add fields such as required_fee or limit_per_minute.
- 400Invalid request: missing fields, invalid JSON, or an invalid amount.
- 401Key missing, not starting with pm_live_, unknown, or revoked.
- 402Business balance does not cover the amount or fee.
- 403Business account is not active, KYC is not approved, or the card is not in the required state.
- 404Route, end user, or card was not found. An unknown route also returns available_endpoints.
- 409The card state does not allow freeze or unfreeze.
- 429Rate limit exceeded. Wait 60 seconds.
- 500Server error. The body is Internal server error.
curl "https://api.paymore.io/v1/balance"Response
{
"error": "Missing or invalid API key. Use header X-API-Key or Authorization: Bearer pm_live_..."
}Rate limits
Authenticated requests are counted per business over a rolling 60 seconds:
| Plan | Requests per minute |
|---|---|
| Startup | 60 |
| Enterprise | 300 |
| Premium | 300 |
Over the limit, the API returns 429 with Retry-After: 60. The body includes limit_per_minute.
curl "https://api.paymore.io/v1/balance" \
-H "X-API-Key: pm_live_xxx"Response
{
"error": "Rate limit exceeded. Retry after 60 seconds.",
"limit_per_minute": 60
}Pagination
List routes (transactions, end users, cards) take limit from 1 to 100 (default 50) and offset from 0 to 100000 (default 0).
curl "https://api.paymore.io/v1/transactions?limit=50&offset=0" \
-H "X-API-Key: pm_live_xxx"Response
{
"transactions": [
{
"id": "c7a1e9d2-5b3f-4c8e-a6d1-0f2b4e8c9a71",
"business_id": "3f1c2b7a-8d4e-4a61-9b0f-2e6d8c5a1f34",
"type": "card_funding",
"amount": -102,
"description": "Card funding",
"reference_id": null,
"created_at": "2026-10-02T14:05:11.208Z"
}
],
"total": 1,
"limit": 50,
"offset": 0
}Get balance
Balance of the business account linked to the key, in USD. Fees and card funding are paid from this balance.
Parameters
This route has no parameters.
curl "https://api.paymore.io/v1/balance" \
-H "X-API-Key: pm_live_xxx"Response
{
"balance": 1500,
"currency": "USD"
}Get account
The business account linked to the key.
Parameters
This route has no parameters.
curl "https://api.paymore.io/v1/account" \
-H "X-API-Key: pm_live_xxx"Response
{
"account": {
"id": "3f1c2b7a-8d4e-4a61-9b0f-2e6d8c5a1f34",
"company_name": "Example Ltd",
"company_email": "[email protected]",
"plan": "startup",
"status": "active",
"business_balance": 1500,
"created_at": "2026-09-14T10:22:31.512Z"
}
}List transactions
Business ledger, newest first. Debits are negative. Filter with type: deposit, fee, card_issuance, card_funding, kyc_fee, subscription, withdrawal, or refund. Page with limit 1–100 (default 50) and offset 0–100000 (default 0).
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| type | query | Optional | string | deposit, fee, card_issuance, card_funding, kyc_fee, subscription, withdrawal, or refund. |
| limit | query | Optional | integer | Page size from 1 to 100. Default 50. |
| offset | query | Optional | integer | Rows to skip, from 0 to 100000. Default 0. |
curl "https://api.paymore.io/v1/transactions" \
-H "X-API-Key: pm_live_xxx"Response
{
"transactions": [
{
"id": "c7a1e9d2-5b3f-4c8e-a6d1-0f2b4e8c9a71",
"business_id": "3f1c2b7a-8d4e-4a61-9b0f-2e6d8c5a1f34",
"type": "card_funding",
"amount": -102,
"description": "Card funding",
"reference_id": null,
"created_at": "2026-10-02T14:05:11.208Z"
}
],
"total": 1,
"limit": 50,
"offset": 0
}Submit KYC
Creates an end user, or resubmits an existing one, for review. Required: external_user_id, first_name, last_name, email, phone, country, address, id_number. Optional: dob (YYYY-MM-DD), passport_number, document_type (passport, national_id, or driving_license), document_front_base64, document_back_base64, selfie_base64. If your plan has a KYC fee, it is charged from the business balance on each submission.
If the same ID or passport number already exists under your account, the response may include has_duplicate_warnings: true.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| external_user_id | body | Required | string | Your id for this person. |
| first_name | body | Required | string | Given name. |
| last_name | body | Required | string | Family name. |
| body | Required | string | Email address. | |
| phone | body | Required | string | Phone number. |
| country | body | Required | string | Country code, such as AE. |
| address | body | Required | string | Street address. |
| id_number | body | Required | string | National or identity number. |
| dob | body | Optional | string | Date of birth, YYYY-MM-DD. |
| passport_number | body | Optional | string | Passport number. |
| document_type | body | Optional | string | passport, national_id, or driving_license. |
| document_front_base64 | body | Optional | string | Front of the document, base64. |
| document_back_base64 | body | Optional | string | Back of the document, base64. |
| selfie_base64 | body | Optional | string | Selfie image, base64. |
curl -X POST "https://api.paymore.io/v1/kyc/submit" \
-H "X-API-Key: pm_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "external_user_id": "user_123", "first_name": "Amina", "last_name": "Hassan", "email": "[email protected]", "phone": "+971500000000", "country": "AE", "address": "Example tower", "id_number": "784-1990-0000000-0", "dob": "1990-01-15", "document_type": "passport"}'Response
{
"success": true,
"end_user_id": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123",
"kyc_status": "pending"
}Get KYC status
Status for one end user. kyc_status is none, pending, approved, or rejected.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| external_user_id | path | Required | string | The id you sent when the end user was created. |
curl "https://api.paymore.io/v1/kyc/user_123" \
-H "X-API-Key: pm_live_xxx"Response
{
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123",
"first_name": "Amina",
"last_name": "Hassan",
"email": "[email protected]",
"phone": "+971500000000",
"kyc_status": "approved",
"kyc_submitted_at": "2026-10-01T09:12:44.103Z",
"kyc_reviewed_at": "2026-10-01T15:30:02.871Z"
}
}List end users
End users under your account, newest first. Filter with kyc_status. Same limit and offset bounds as the transaction list.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| kyc_status | query | Optional | string | none, pending, approved, or rejected. |
| limit | query | Optional | integer | Page size from 1 to 100. Default 50. |
| offset | query | Optional | integer | Rows to skip, from 0 to 100000. Default 0. |
curl "https://api.paymore.io/v1/end-users" \
-H "X-API-Key: pm_live_xxx"Response
{
"end_users": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"external_user_id": "user_123",
"first_name": "Amina",
"last_name": "Hassan",
"email": "[email protected]",
"phone": "+971500000000",
"kyc_status": "approved",
"kyc_submitted_at": "2026-10-01T09:12:44.103Z",
"kyc_reviewed_at": "2026-10-01T15:30:02.871Z",
"created_at": "2026-10-01T09:12:44.103Z"
}
],
"total": 1,
"limit": 50,
"offset": 0
}Request a card
Requests a card for an end user whose KYC status is approved. external_user_id is required. card_type_id is optional. The request starts as pending until PayMore activates it. If your plan has an issuance fee, it is charged when the request is created.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| external_user_id | body | Required | string | End user whose KYC status is approved. |
| card_type_id | body | Optional | string | Optional card type id. |
curl -X POST "https://api.paymore.io/v1/cards/issue" \
-H "X-API-Key: pm_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "external_user_id": "user_123"}'Response
{
"success": true,
"card_request_id": "9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d",
"status": "pending",
"message": "Card request submitted. Our admin team will activate it and fill in card details. Check status via GET /cards/{card_id}."
}List cards
Cards on your account, newest first. Status is pending, approved, reviewing, active, rejected, cancelled, frozen, or disabled. Filter with status. This list does not return a card number or CVV.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| status | query | Optional | string | pending, approved, reviewing, active, rejected, cancelled, frozen, or disabled. |
| limit | query | Optional | integer | Page size from 1 to 100. Default 50. |
| offset | query | Optional | integer | Rows to skip, from 0 to 100000. Default 0. |
curl "https://api.paymore.io/v1/cards" \
-H "X-API-Key: pm_live_xxx"Response
{
"cards": [
{
"id": "9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d",
"end_user_id": "550e8400-e29b-41d4-a716-446655440000",
"card_type_id": null,
"status": "active",
"card_balance": 100,
"daily_limit": null,
"created_at": "2026-10-02T11:00:00.000Z",
"updated_at": "2026-10-02T14:05:11.208Z",
"end_user": {
"external_user_id": "user_123",
"first_name": "Amina",
"last_name": "Hassan"
}
}
],
"total": 1,
"limit": 50,
"offset": 0
}Get card
One card. card_id is a UUID. Only while status is active, the response includes the last four digits as card_last4 and the expiry as card_expiry. The full card number and CVV are never returned.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| card_id | path | Required | uuid | Card id returned by issue, list, or get. |
curl "https://api.paymore.io/v1/cards/9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d" \
-H "X-API-Key: pm_live_xxx"Response
{
"card": {
"id": "9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d",
"end_user_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "active",
"card_balance": 100,
"daily_limit": null,
"created_at": "2026-10-02T11:00:00.000Z",
"updated_at": "2026-10-02T14:05:11.208Z",
"end_user": {
"external_user_id": "user_123",
"first_name": "Amina",
"last_name": "Hassan"
},
"card_last4": "4242",
"card_expiry": "10/29"
}
}Fund card
Loads a USD amount onto an active card. amount is a positive number, rounded to cents, with a maximum of 10000 per request. The business balance is charged the amount plus your plan’s funding fee (the greater of the percentage and the minimum).
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| card_id | path | Required | uuid | Card id returned by issue, list, or get. |
| amount | body | Required | number | Positive USD amount, rounded to cents, maximum 10000. |
curl -X POST "https://api.paymore.io/v1/cards/9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d/fund" \
-H "X-API-Key: pm_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "amount": 100}'Response
{
"success": true,
"funded_amount": 100,
"fee": 2,
"new_card_balance": 100
}Unload card
Moves an amount from an active card back to the business balance. This route does not add a fee. The amount cannot exceed the card balance.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| card_id | path | Required | uuid | Card id returned by issue, list, or get. |
| amount | body | Required | number | Positive USD amount. It cannot exceed the card balance. This route adds no fee. |
curl -X POST "https://api.paymore.io/v1/cards/9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d/unload" \
-H "X-API-Key: pm_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "amount": 50}'Response
{
"success": true,
"unloaded_amount": 50,
"new_card_balance": 50
}Freeze card
Freezes an active card. No request body. A frozen card cannot be funded or unloaded until it is unfrozen.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| card_id | path | Required | uuid | Card id returned by issue, list, or get. |
curl -X POST "https://api.paymore.io/v1/cards/9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d/freeze" \
-H "X-API-Key: pm_live_xxx"Response
{
"success": true,
"card_id": "9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d",
"status": "frozen"
}Unfreeze card
Sets a frozen card back to active. No request body.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
| card_id | path | Required | uuid | Card id returned by issue, list, or get. |
curl -X POST "https://api.paymore.io/v1/cards/9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d/unfreeze" \
-H "X-API-Key: pm_live_xxx"Response
{
"success": true,
"card_id": "9b2f6c1e-4a7d-4e2b-8c3f-1d5e7a9b0c2d",
"status": "active"
}List plans
Returns USD fee schedules for the startup, enterprise, and premium plans. No key is required. The sample shows the startup shape. Call the endpoint for the current figures of all three plans.
GET https://api.paymore.io/plans returns the same body.
Parameters
This route has no parameters.
curl "https://api.paymore.io/v1/plans"Response
{
"plans": [
{
"plan": "startup",
"monthly_fee": 500,
"card_issuance_fee": 10,
"card_funding_fee_pct": 2,
"card_funding_fee_min": 0.5,
"monthly_maintenance_fee": 1,
"decline_fee": 0.4,
"crossborder_fee_pct": 2.5,
"crossborder_fee_min": 0.5,
"wallet_tokenization_fee": 1,
"wallet_deposit_fee_pct": 3,
"wallet_deposit_fee_min": 2,
"wallet_withdrawal_fee": 5,
"kyc_verification_fee": 1,
"chargeback_fee": 30,
"prepay_discount_6m": 0,
"prepay_discount_1y": 0
}
],
"currency": "USD"
}Coming soon
There is no international-transfer API.
Webhooks
PayMore does not send webhooks, and there is no signature scheme for an incoming request.
SDK
There is no SDK. The samples use curl, fetch, and Python’s standard urllib.