Getting Started

Welcome to the Payment Processor API documentation. This API allows you to accept cryptocurrency payments and manage payouts programmatically.

Base URL

https://api.shadowpay.world

Quick Start

To get started, you'll need:

  1. An api_key for authentication
  2. A configured wallet chain for your chosen blockchain network

Example: Create Your First Payment

curl -X POST "https://api.shadowpay.world/post_create_order" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "order_id=ORDER_001" \
  -d "amount=100" \
  -d "symbol=USDC" \
  -d "chain=sepolia" \
  -d "base_currency=EUR" \
  -d "api_key=YOUR_API_KEY"

Response:

{
  "payment_url": "https://shadowpay.world/d4e5f6g7-h8i9-j0k1-l2m3-n4o5p6q7r8s9"
}

Authentication

All authenticated endpoints require your API key for authentication. The API key automatically identifies your merchant account.

  • api_key - Your secret API key (format: sk_live_xxx or sk_test_xxx)
Security Note: Never expose your API key in client-side code or public repositories. Your API key has full access to your merchant account.

Create Payment Order

POST /post_create_order

Creates a new cryptocurrency payment order and returns a payment URL for the customer.

Parameters

Parameter Type Required Description
order_id string ✓ Unique identifier for this order
amount string ✓ Payment amount in merchant's base currency (set during account creation, e.g., "100" for €100 or $100)
symbol string ✓ Currency symbol (e.g., "USDC", "USDT")
chain string ✓ Blockchain network (e.g., "ethereum", "sepolia", "base", "arbitrum")
base_currency string ✓ Base fiat currency for the amount (e.g., "EUR", "USD")
api_key string ✓ Your API key for authentication

Example Request

curl -X POST "https://api.shadowpay.world/post_create_order" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "order_id=ORDER_12345" \
  -d "amount=100.50" \
  -d "symbol=USDC" \
  -d "chain=ethereum" \
  -d "base_currency=EUR" \
  -d "api_key=sk_live_abc123xyz789"

Response

{
  "payment_url": "https://shadowpay.world/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Error Responses

  • 400 - Invalid amount format or cryptocurrency not available
  • 401 - Invalid authentication credentials
  • 404 - Cryptocurrency not found
  • 500 - No wallet chain configured or internal error

Get Payment Info

GET /get_payment_infos/{payment_id}

Retrieves detailed information about a payment, including current status, amounts, and transaction events.

Note: This endpoint does not require authentication and can be called by the payment page frontend.

Path Parameters

Parameter Type Description
payment_id UUID The unique payment identifier from the payment URL

Example Request

curl -X GET "https://api.shadowpay.world/get_payment_infos/a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Response

{
  "crypto_price": 0.92,
  "amount": 100.0,
  "confirmed_amount": 50.0,
  "received_amount": 80.0,
  "expires_at": "2025-10-24T10:45:00.000Z",
  "updated_at": "2025-10-24T10:35:00.000Z",
  "qrcode": "data:image/png;base64,iVBORw0KGgo...",
  "chain": "sepolia",
  "status": "partially_received",
  "payment_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "currency": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
  "symbol": "USDC",
  "base_currency": "EUR",
  "amount_base_currency": 92.0,
  "transaction_events": [
    {
      "tx_hash": "0xabc123...",
      "amount": 50.0,
      "status": "confirmed",
      "block_number": 12340,
      "created_at": "2025-10-24T10:31:00.000Z",
      "updated_at": "2025-10-24T10:33:00.000Z"
    },
    {
      "tx_hash": "0xdef456...",
      "amount": 30.0,
      "status": "seen",
      "block_number": 12341,
      "created_at": "2025-10-24T10:35:00.000Z",
      "updated_at": "2025-10-24T10:35:00.000Z"
    }
  ]
}
Note: The QR code is generated using the EIP-681 standard format for ERC-20 token transfers, making it compatible with MetaMask, Rabby, Trust Wallet, and other modern crypto wallets. First call to this endpoint automatically changes status from created to pending.

Payment Status Values

The status field in the response can have one of the following values:

Status Description
created Payment order created, not yet viewed by customer
pending Customer viewing payment page, waiting for payment
partially_received Some crypto received on blockchain, but not full amount
received Full crypto amount received on blockchain (unconfirmed)
partially_confirmed Some amount confirmed on blockchain
confirmed Payment fully confirmed on blockchain (final state)
expired Payment window expired (default: 15 minutes)
failed Payment failed or cancelled

Get Payout Info

GET /get_payout_infos/{payout_id}

Retrieves detailed information about a payout/withdrawal, including current status, amounts, and transaction events.

Note: This endpoint does not require authentication and can be called to check withdrawal status.

Path Parameters

Parameter Type Description
payout_id UUID The unique payout identifier returned from create withdrawal

Example Request

curl -X GET "https://api.shadowpay.world/get_payout_infos/b1c2d3e4-f5g6-7890-hijk-lm1234567890"

Response

{
  "crypto_price": 0.92,
  "amount": 50.0,
  "status": "confirmed",
  "chain": "sepolia",
  "destination_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "currency": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
  "symbol": "USDC",
  "base_currency": "EUR",
  "amount_base_currency": 46.0,
  "tx_hash": "0xabc123def456...",
  "created_at": "2025-10-24T11:00:00.000Z",
  "confirmed_at": "2025-10-24T11:05:00.000Z",
  "updated_at": "2025-10-24T11:05:00.000Z",
  "transaction_events": [
    {
      "tx_hash": "0xabc123def456...",
      "amount": 50.0,
      "status": "confirmed",
      "block_number": 12450,
      "created_at": "2025-10-24T11:02:00.000Z",
      "updated_at": "2025-10-24T11:05:00.000Z"
    }
  ]
}

Payout Status Values

The status field in the response can have one of the following values:

Status Description
pending Payout request created, waiting for processing
queued Payout queued for execution
sent Transaction sent to blockchain
confirmed Transaction confirmed on blockchain (final state)
failed Payout failed (check failure_reason field)
cancelled Payout cancelled

List Available Currencies

POST /post_currencies

Returns a list of available cryptocurrencies with their current exchange rates and network information.

Query Parameters

Parameter Type Required Description
api_key string ✓ Your API key for authentication

Example Request

curl -X POST "https://api.shadowpay.world/post_currencies?api_key=YOUR_API_KEY"

Response

[
  {
    "symbol": "USDC",
    "name": "USD Coin",
    "network": "ethereum",
    "rate": 1.00,
    "deposit_address": "0x1234567890abcdef1234567890abcdef12345678",
    "available": true
  },
  {
    "symbol": "USDC",
    "name": "USD Coin (Sepolia Testnet)",
    "network": "sepolia",
    "rate": 1.00,
    "deposit_address": "0x1234567890abcdef1234567890abcdef12345678",
    "available": true
  },
  {
    "symbol": "USDT",
    "name": "Tether",
    "network": "ethereum",
    "rate": 0.99,
    "deposit_address": "0x4567890123def4567890123def4567890123def",
    "available": true
  }
]
Note: The symbol field contains only the currency symbol (e.g., "USDC", "USDT") without the chain. Use the network field to identify which blockchain the currency is available on. The same currency can appear multiple times with different networks.

Create Withdrawal

POST /post_create_withdrawal

Creates a withdrawal request to send cryptocurrency from your merchant wallet to a specified address.

Idempotency: Duplicate withdrawal requests with the same order_id will return the existing payout if it's still active.

Parameters

Parameter Type Required Description
order_id string ✓ Unique identifier for this withdrawal order
amount string ✓ Withdrawal amount in merchant's base currency (set during account creation, e.g., "100" for €100 or $100)
address_to string ✓ Destination blockchain address
chain string ✓ Blockchain network (ethereum, sepolia, arbitrum, base)
symbol string ✓ Currency symbol (USDC, USDT)
base_currency string ✓ Base fiat currency for the amount (e.g., "EUR", "USD")
api_key string ✓ Your API key for authentication

Example Request

curl -X POST "https://api.shadowpay.world/post_create_withdrawal" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "order_id=WITHDRAWAL_001" \
  -d "amount=50" \
  -d "address_to=0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" \
  -d "chain=sepolia" \
  -d "symbol=USDC" \
  -d "base_currency=EUR" \
  -d "api_key=sk_live_abc123xyz789"

Response

{
  "payout_id": "b1c2d3e4-f5g6-7890-hijk-lm1234567890",
  "status": "pending",
  "payout_type": "withdrawal",
  "amount": 50.0,
  "symbol": "USDC",
  "chain": "sepolia",
  "source_wallet_address": "0x1234567890abcdef1234567890abcdef12345678",
  "destination_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "created_at": "2025-10-24T10:30:00.000Z"
}

Withdrawal Statuses

  • pending - Withdrawal request created, waiting for processing
  • queued - Withdrawal queued for execution
  • sent - Transaction sent to blockchain
  • confirmed - Transaction confirmed on blockchain
  • failed - Withdrawal failed
  • cancelled - Withdrawal cancelled

Webhooks

Webhooks allow you to receive real-time notifications when payment and payout events occur in your account. Instead of polling our API, webhooks push event data directly to your server.

Setup

To receive webhooks, you need to:

  1. Contact us to register your webhook endpoint URL
  2. We will generate a unique webhook_secret for your account
  3. Store this secret securely - you'll use it to verify webhook authenticity
Note: Webhook URL and secret are manually configured by our team. Contact support to set up or update your webhook endpoint.

Webhook Events

We currently send webhooks for the following events:

Event Type Description
payment.confirmed Payment has been fully confirmed on the blockchain
payout.confirmed Payout transaction successfully completed on the blockchain
payout.failed Payout transaction failed on the blockchain
Important: Webhooks are only sent for fully confirmed payments. Partial payments, expired payments, and failed payments do NOT trigger webhooks.

Webhook Payload Structure

Payment Webhook Example

{
  "event_type": "payment.confirmed",
  "event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "created_at": "2024-12-03T10:30:45.123456+00:00",
  "payment": {
    "id": "d4e5f6g7-h8i9-j0k1-l2m3-n4o5p6q7r8s9",
    "merchant_order_id": "ORDER_12345",
    "crypto_amount": "100000000",
    "amount_base": "100.00",
    "crypto_currency": "USDC",
    "base_currency": "EUR",
    "status": "confirmed",
    "created_at": "2024-12-03T10:15:30.000000+00:00",
    "crypto_amount_paid": "100000000",
    "amount_base_paid": "100.00"
  }
}

Payout Webhook Example

{
  "event_type": "payout.confirmed",
  "event_id": "b2c3d4e5-f6g7-8901-bcde-f12345678901",
  "created_at": "2024-12-03T11:45:20.123456+00:00",
  "metadata": {
    "tx_hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "block_number": 12345678,
    "confirmed_at": "2024-12-03T11:45:15.000000+00:00"
  },
  "payout": {
    "id": "e5f6g7h8-i9j0-k1l2-m3n4-o5p6q7r8s9t0",
    "merchant_reference_id": "PAYOUT_456",
    "payout_type": "withdrawal",
    "crypto_amount": "50000000",
    "crypto_currency": "USDC",
    "amount_base": "50.00",
    "base_currency": "EUR",
    "status": "confirmed",
    "created_at": "2024-12-03T11:30:15.000000+00:00",
    "destination_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
  }
}

Webhook Security

All webhook requests include cryptographic signatures to verify their authenticity. This prevents spoofing and ensures the request genuinely comes from Shadow Pay.

Signature Headers

Each webhook request includes two security headers:

  • X-Webhook-Timestamp - Unix timestamp when the webhook was sent
  • X-Webhook-Signature - HMAC-SHA256 signature of the payload

Signature Verification Process

To verify a webhook is authentic:

  1. Extract X-Webhook-Timestamp and X-Webhook-Signature from headers
  2. Reconstruct the signed message: {timestamp}.{json_payload}
  3. Compute HMAC-SHA256 using your webhook secret: HMAC-SHA256(message, webhook_secret)
  4. Compare the computed signature with the received signature using a timing-safe comparison
# Signature verification logic
message = f"{timestamp}.{json.dumps(payload, separators=(',', ':'), sort_keys=True)}"
expected_signature = hmac.new(webhook_secret, message.encode('utf-8'), hashlib.sha256).hexdigest()
is_valid = hmac.compare_digest(expected_signature, received_signature)

Retry Behavior

If your endpoint is unavailable or returns an error, we will automatically retry the webhook delivery:

  • Retry Schedule: 30s, 1m, 2m, 4m, 8m, 16m, 32m, 64m, 112.5m (total ~4 hours)
  • Maximum Attempts: 10 retries
  • Success Codes: 200-299 HTTP status codes
  • Permanent Failures: 400, 401, 403, 404, 410, 422 (no retries)
  • Transient Failures: 5xx errors, timeouts, connection errors (will retry)
Best Practice: Your webhook endpoint should respond quickly (within 5 seconds) and return a 200 status code. Process the webhook asynchronously if needed.

Idempotency

Each webhook has a unique event_id. We guarantee at-least-once delivery, so you may receive duplicate webhooks. Use the event_id to make your webhook handling idempotent and prevent duplicate processing.

Testing Webhooks

During development:

  • Use tools like ngrok to expose your local server
  • Implement signature verification before deploying to production
  • Contact support to trigger test webhook events

Error Handling

The API uses standard HTTP response codes to indicate success or failure.

HTTP Status Codes

Code Description
200 Success - Request completed successfully
400 Bad Request - Invalid parameters or request format
401 Unauthorized - Invalid or missing authentication credentials
404 Not Found - Payment, order, or cryptocurrency not found
500 Internal Server Error - Something went wrong on the server

Error Response Format

{
  "detail": "Invalid authentication credentials"
}

Common Error Examples

Authentication Error (401)

{
  "detail": "Invalid authentication credentials"
}

Payment Not Found (404)

{
  "detail": "Payment a1b2c3d4-e5f6-7890-abcd-ef1234567890 not found"
}

Invalid Amount (400)

{
  "detail": "Invalid amount format"
}