API Documentation

Accept and send payments programmatically

Secure Fast Developer Friendly

🚀 Getting Started

1
Request an API Key

Create a key request from the merchant dashboard and wait for admin approval. The API Secret is shown only once when created or regenerated, so store it securely.

2
Set Permissions

Choose which endpoints your API key can access. Minimum one permission required.

3
Configure IP Whitelist

Optionally restrict the API key to your server's public outbound IP address. Do not enter a customer, browser, or CDN address.

4
Go Live

Test PayIn and Payout status updates with small amounts, then scale up. Always use HTTPS.

🌍 IP Whitelist

IP whitelisting is optional. If no IP address is configured, valid API credentials may be used from any IP. When one or more addresses are configured, requests from every other IP are rejected with AUTH_005.

Whitelist the public outbound IP address of the server that sends requests to OESPay. Do not use the customer's IP, browser IP, domain IP, or a CDN/proxy IP.

To check a Linux server's public IPv4 address:

curl -4 -s https://api.ipify.org
Dual-stack servers: A server may send requests over IPv4 or IPv6. Use a stable outbound address, configure your HTTP client to use the whitelisted IPv4 address, or whitelist every legitimate outbound address used by your server.

Multiple server IP addresses may be added to the same API key. Each API key has its own independent whitelist.

🔐 Authentication

Both X-API-Key and X-API-Secret are REQUIRED for all protected API endpoints. Provider and merchant webhook callbacks use their own verification rules.

Required Headers:

X-API-Key: oes_your_api_key_here
X-API-Secret: sk_your_secret_here
Important: Never expose your API credentials in client-side code. Always use server-side requests.

🔑 Permissions

Each API key can have one or more permissions. The all permission grants full access.

PermissionDescriptionEndpoints
payinCreate and manage payment invoices/create-invoice, /check-status, /merchant/payins
payoutCreate and manage payout requests/payout/create, /merchant/payouts
balanceCheck balance and statistics/merchant/balance, /merchant/stats
allFull access to all endpointsAll endpoints

🌐 Base URL

https://cashwanna.com/api

All endpoints are relative to this base URL.

📝 Create Invoice

POST /create-invoice Requires: payin

📤 Request

Required Headers:

Content-Type: application/json
X-API-Key: oes_your_api_key_here
X-API-Secret: sk_your_secret_here
{
    "amount": 100.00,
    "pay_way": "cashapp",
    "customer_email": "customer@example.com",
    "customer_name": "John Doe",
    "redirect_url": "https://merchant.example/payment/return"
}
ParameterTypeRequiredDescription
amountnumeric✅ YesNormally Min: 1, Max: 10000. eCashApp, Apple Pay and Google Pay accept only the exact preset amounts listed below.
pay_waystring✅ Yescashapp, ecashapp, applepay, googlepay, chime, btcpay, paypal, venmo
customer_emailstring❌ NoValid customer email, maximum 255 characters
customer_namestring❌ NoCustomer name, maximum 255 characters
redirect_urlURL❌ NoHTTPS return URL after checkout, maximum 2048 characters
Restricted invoice amounts: For ecashapp, applepay, and googlepay, the amount must exactly match one of: 9.99, 14.99, 17.99, 19.99, 24.99, 29.99, 30.99, 39.99, 49.99, 59.99, 99.99, 124.99, 129.99, 149.99, or 199.99 USD. Other amounts return PAYIN_007 with HTTP 422.

Fee and net values vary according to the authenticated merchant's effective rate.

✅ Response (Auto Wallet)

{
    "success": true,
    "data": {
        "order_id": 123,
        "order_no": "API_1788264000_abc123",
        "amount": "99.99",
        "fee": "14.80",
        "net": "85.19",
        "pay_way": "applepay",
        "payment_url": "https://provider.example/checkout/xxx",
        "expires_at": "2026-09-01T12:00:00Z",
        "status": "processing"
    }
}

✅ Response (Manual Wallet)

{
    "success": true,
    "data": {
        "order_id": 124,
        "order_no": "API_1788264000_def456",
        "amount": "100.00",
        "fee": "10.30",
        "net": "89.70",
        "pay_way": "chime",
        "manual_code": "W6X-F1",
        "wallet_address": "$ExampleTag",
        "checkout_url": "https://cashwanna.com/checkout/124",
        "expires_at": "2026-09-01T20:00:00Z",
        "status": "pending_manual"
    }
}

🔍 Check Order Status

GET /check-status/{order_id} Requires: payin

✅ Response

{
    "success": true,
    "data": {
        "order_id": 123,
        "order_no": "API_1788264000_abc123",
        "amount": "99.99",
        "real_amount": "99.99",
        "fee": "14.80",
        "net": "85.19",
        "pay_way": "applepay",
        "payment_url": "https://provider.example/checkout/xxx",
        "manual_code": null,
        "status": "success",
        "created_at": "2026-09-01T10:00:00Z",
        "success_time": "2026-09-01T10:05:00Z",
        "expires_at": "2026-09-01T12:00:00Z"
    }
}

📊 Status Values

pending processing success failed pending_manual expired cancelled disputed

💰 Get Balance

GET /merchant/balance Requires: balance

✅ Response

{
    "success": true,
    "data": {
        "balance": "1500.00",
        "bonus_balance": "50.00",
        "currency": "USD"
    }
}

📋 Get PayIns

GET /merchant/payins Requires: payin

Query Parameters:

?limit=20&status=success&pay_way=cashapp

limit accepts 1–100 and defaults to 20. Results are returned newest first.

✅ Response

{
    "success": true,
    "data": {
        "total": 45,
        "payins": [
            {
                "id": 123,
                "order_no": "API_1706000000_abc123",
                "merchant_order_no": "MCH_1706000000_xyz789",
                "pay_way": "cashapp",
                "amount": "100.00",
                "real_amount": "100.00",
                "fee": "11.00",
                "net": "89.00",
                "status": "success",
                "cashier_url": "https://provider.example/checkout/xxx",
                "created_at": "2026-01-15 10:00:00",
                "success_time": "2026-01-15 10:05:00",
                "expire_time": "2026-01-15 12:00:00"
            }
        ]
    }
}

📋 Get Payouts

GET /merchant/payouts Requires: payout

Query Parameters:

?limit=20&status=approved&pay_way=chime_payout

limit accepts 1–100 and defaults to 20. Results are returned newest first.

✅ Response

{
    "success": true,
    "data": {
        "total": 12,
        "payouts": [
            {
                "id": 456,
                "payout_id": 456,
                "transaction_id": "POU-123456",
                "amount": "50.00",
                "fee": "3.50",
                "total_deducted": "53.50",
                "pay_way": "chime_payout",
                "recipient": "$ExampleTag",
                "status": "approved",
                "rejection_reason": null,
                "invoice_number": "INV-20260906-000456",
                "completion_image": "payouts/completed/example.jpg",
                "created_at": "2026-09-06 12:49:35",
                "approved_at": "2026-09-06 12:52:00",
                "completed_at": "2026-09-06 12:52:00"
            }
        ]
    }
}

📊 Payout Status Values

pending processing approved rejected cancelled failed
Merchant webhooks are enabled. Use this endpoint as a polling fallback and match the returned payout_id or transaction_id. Do not create a second payout while checking an existing request.

📊 Get Stats

GET /merchant/stats Requires: balance

✅ Response

{
    "success": true,
    "data": {
        "balance": "1500.00",
        "bonus_balance": "50.00",
        "payin": {
            "total_count": 45,
            "total_amount": "5000.00",
            "total_success": "4500.00",
            "total_pending": "500.00",
            "total_failed": "0.00"
        },
        "payout": {
            "total_count": 12,
            "total_amount": "1200.00",
            "total_approved": "1100.00",
            "total_pending": "100.00",
            "total_failed": "0.00"
        }
    }
}

👤 Get Profile

GET /merchant/profile Requires: all

✅ Response

{
    "success": true,
    "data": {
        "id": 12,
        "name": "Example Merchant",
        "email": "merchant@example.com",
        "status": "active"
    }
}

📤 Create Payout (API)

POST /payout/create Requires: payout
The Idempotency-Key header is required and must not exceed 100 characters. Reuse the same key only when retrying the exact same payout request; use a new key for every new payout.

📤 Headers

Content-Type: application/json
X-API-Key: oes_your_api_key
X-API-Secret: sk_your_secret
Idempotency-Key: unique_request_id_123

📤 Request Body

{
    "amount": 50.00,
    "pay_way": "paypal_payout",
    "account_info": "merchant@example.com"
}
ParameterTypeRequiredDescription
amountnumeric✅ YesMin: 10, Max: 5000
pay_waystring✅ Yescashapp_payout, paypal_payout, ach_payout, card_payout, chime_payout
account_infostring✅ YesEmail, tag, or handle

✅ Response (201 Created)

{
    "success": true,
    "data": {
        "order_id": 456,
        "transaction_id": "POU-20260901-A1B2C3D4E5F6-1788264000",
        "amount": "50.00",
        "fee": "3.50",
        "total_deducted": "53.50",
        "pay_way": "paypal_payout",
        "recipient": "merchant@example.com",
        "status": "pending",
        "created_at": "2026-09-01 10:00:00"
    }
}

🔄 Merchant Webhooks

Outgoing merchant webhooks are enabled for API-created PayIns and Payouts. OESPay sends an asynchronous signed callback whenever the resource status or supported result details change.

⚙️ Setup

Open Merchant Dashboard → API Keys, configure an HTTPS webhook URL, enable delivery, and securely copy the separately generated webhook signing secret.

The webhook secret is different from the X-API-Secret used to call protected API endpoints. Never expose either secret in client-side code.

Webhook delivery applies only to PayIns and Payouts linked to the API key on which the webhook is enabled.

📤 Request Headers

Content-Type: application/json
X-OESPay-Event-Id: 85d5cb6f-93a9-48d4-a2a7-20a9b271111e
X-OESPay-Timestamp: 1788264000
X-OESPay-Signature: sha256=generated_hmac_signature

📥 PayIn Status Event

{
    "event_id": "550e8400-e29b-41d4-a716-446655440000",
    "event": "payin.status.updated",
    "created_at": "2026-09-07T16:57:02+00:00",
    "data": {
        "local_order_no": "MCH_1788800033_example",
        "order_id": "API_1788800033_example",
        "transaction_id": 37050,
        "status": "failed",
        "amount": "20.00",
        "real_amount": null,
        "fee": "3.10",
        "net": "16.90",
        "pay_way": "chime",
        "admin_notes": "Payment was not received from the provided account.",
        "success_time": null
    }
}

📤 Payout Status Event

{
    "event_id": "a3d38cb1-7a89-42dd-8fac-e2e017199edb",
    "event": "payout.status.updated",
    "created_at": "2026-09-07T17:02:00+00:00",
    "data": {
        "local_order_no": "POU-LOCAL-EXAMPLE",
        "payout_id": 456,
        "transaction_id": "POU-20260901-A1B2C3D4E5F6-1788264000",
        "amount": "50.00",
        "fee": "3.50",
        "total_deducted": "53.50",
        "pay_way": "paypal_payout",
        "recipient": "merchant@example.com",
        "status": "approved",
        "rejection_reason": null,
        "invoice_number": "INV-20260907-ABC123",
        "completion_image": "https://cashwanna.com/storage/payout-completions/example.jpg",
        "completed_at": "2026-09-07T17:01:30+00:00"
    }
}

Verification: Calculate HMAC-SHA256 over the exact raw HTTP request body using the separate webhook signing secret. Compare the hexadecimal result with X-OESPay-Signature using a timing-safe comparison. Accept the optional sha256= prefix.

Important: Read the raw body before decoding JSON. Do not re-encode, reformat, sort, or otherwise modify the JSON before calculating the signature.

Acknowledgement: Return any HTTP 2xx response after safely recording the event.

Duplicate protection: Store X-OESPay-Event-Id and ignore an event that has already been processed.

Retries: Delivery is asynchronous and failed deliveries are retried. Your endpoint should acknowledge quickly and process the event idempotently.

Fallback: If a callback is delayed, use GET /check-status/{order_id} for PayIns or GET /merchant/payouts for Payouts.

💳 Supported Wallets

PayIn

cashapp ecashapp applepay googlepay chime btcpay paypal venmo

Payout

cashapp_payout paypal_payout ach_payout card_payout chime_payout

⚠️ Error Codes

CodeHTTP StatusMessage
AUTH_001401API key required
AUTH_002401Invalid API credentials
AUTH_003401API key is inactive or expired
AUTH_004401Invalid API credentials
AUTH_005403Request IP is not allowed
AUTH_006403Permission denied for this endpoint
AUTH_007401API secret required
AUTH_008403Merchant account is inactive
AUTH_009403API permission configuration missing
AUTH_010401Merchant not authenticated
PAYIN_001422Payment method is unavailable
PAYIN_002422Calculated fee exceeds the invoice amount
PAYIN_003502Upstream payment provider could not create the invoice
PAYIN_004422Unsupported payment method
PAYIN_005404Order not found for the authenticated merchant
PAYIN_006503No active manual wallet is available
PAYIN_007422Invalid restricted amount; response includes allowed_amounts
PAYOUT_002500Temporary payout processing error. Please retry safely with the same Idempotency-Key.
PAYOUT_003400Payment method not available for payout
PAYOUT_004422Valid Idempotency-Key header is required
PAYOUT_005409Idempotency key was already used with different payout data
PAYOUT_006422Insufficient balance or merchant inactive
RATE_001429Rate limit exceeded (5000/min)
500500Internal server error

⏱️ Rate Limit

5000 requests per minute per API key.

If you exceed this limit, you will receive a 429 Too Many Requests response.

Rate Limit Headers:

X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4999
X-RateLimit-Reset: 1706000000

Need Help?

Contact our support team for integration assistance.

Get API Keys →