Skip to content

API Reference

Complete REST API reference for PayIn multi-chain stablecoin payment infrastructure.

Base URL

Production:

https://app.payin.com/api/v1

Testnet:

https://testnet.payin.com/api/v1

Local Development:

http://localhost:3000/api/v1

Testnet First

We strongly recommend testing your integration on testnet before going to production. Testnet uses test tokens with no real value.

Authentication

All API requests require authentication using an API key in the request header:

http
X-API-Key: your-api-key-here

Generating API Keys

  1. Log in to PayIn Admin Dashboard
  2. Navigate to Settings → API Keys
  3. Click Create API Key
  4. Give it a descriptive name
  5. Copy the key (shown only once!)

API Key Permissions

RoleCreate OrdersCreate DepositsView DataManage Settings
Owner
Admin✅ (except ownership)
Member
Viewer

API Key Security

  • Never commit API keys to version control
  • Rotate keys regularly
  • Use different keys for testnet and production
  • See Security Guide for best practices

Request Format

Headers

All requests should include:

http
Content-Type: application/json
X-API-Key: your-api-key-here

Request Body

POST and PUT requests use JSON format:

json
{
  "orderReference": "ORDER-2025-001",
  "amount": "100.00",
  "currency": "USDT",
  "chainId": "ethereum-sepolia"
}

Response Format

Success Response

json
{
  "orderId": "ord_abc123def456",
  "orderReference": "ORDER-2025-001",
  "amount": "100.00",
  "currency": "USDT",
  "chainId": "ethereum-sepolia",
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
  "status": "pending",
  "createdAt": "2025-01-20T10:30:00Z",
  "expiresAt": "2025-01-20T10:40:00Z"
}

Error Response

json
{
  "error": "Invalid amount",
  "message": "Amount must be a positive number",
  "code": "INVALID_AMOUNT",
  "statusCode": 400
}

HTTP Status Codes

CodeDescriptionMeaning
200OKRequest succeeded
201CreatedResource created successfully
400Bad RequestInvalid request parameters
401UnauthorizedMissing or invalid API key
403ForbiddenAPI key lacks required permissions
404Not FoundResource doesn't exist
409ConflictResource already exists (duplicate)
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer error (contact support)

Rate Limiting

API requests are rate-limited to prevent abuse:

Default Limits:

  • 100 requests per minute per API key
  • 1000 requests per hour per API key
  • 10000 requests per day per API key

Response Headers:

http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642680000

When rate limited, you'll receive:

json
{
  "error": "Rate limit exceeded",
  "message": "Too many requests. Please try again in 60 seconds.",
  "code": "RATE_LIMIT_EXCEEDED",
  "statusCode": 429,
  "retryAfter": 60
}

Enterprise Plans

Need higher limits? Contact us for enterprise plans with custom rate limits.

Pagination

List endpoints support pagination:

Query Parameters:

GET /api/v1/orders?page=1&limit=20

Response:

json
{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 157,
    "totalPages": 8,
    "hasMore": true
  }
}

Pagination Parameters:

ParameterTypeDefaultMaxDescription
pageinteger1-Page number (1-indexed)
limitinteger20100Items per page

Filtering & Sorting

Many list endpoints support filtering and sorting:

Filtering:

GET /api/v1/orders?status=pending&currency=USDT

Sorting:

GET /api/v1/orders?sortBy=createdAt&sortOrder=desc

Common Filters:

EndpointSupported Filters
Ordersstatus, currency, chainId, orderReference
Depositsstatus, currency, depositReference
Transfersstatus, currency, chainId, txHash

Sort Options:

  • sortBy: Field to sort by (createdAt, amount, etc.)
  • sortOrder: asc or desc (default: desc)

Idempotency

POST requests that create resources support idempotency keys to prevent duplicate creation:

http
Idempotency-Key: unique-key-123

Behavior:

  • Same idempotency key within 24 hours returns the original response
  • Different request body with same key returns 409 Conflict
  • Keys expire after 24 hours

Example:

bash
curl -X POST https://testnet.payin.com/api/v1/orders \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -H "Idempotency-Key: order-2025-001-retry-1" \
  -d '{
    "orderReference": "ORDER-2025-001",
    "amount": "100.00",
    "currency": "USDT",
    "chainId": "ethereum-sepolia"
  }'

Webhooks

PayIn sends real-time event notifications via webhooks. See Webhooks Guide for details.

Event Types:

  • order.completed - Order payment received and confirmed
  • order.expired - Order expired without payment
  • deposit.pending - Deposit detected, awaiting confirmation
  • deposit.confirmed - Deposit confirmed

Webhook Configuration:

bash
POST /api/v1/webhooks/endpoints
{
  "url": "https://your-api.com/webhooks/payin",
  "events": ["order.completed", "deposit.confirmed"],
  "secret": "webhook_secret_key"
}

API Endpoints

📦 Orders API

Create and manage payment orders.

MethodEndpointDescription
POST/ordersCreate order
GET/orders/:idGet order details
GET/ordersList orders

💰 Deposits API

Manage user deposit addresses and deposits.

MethodEndpointDescription
POST/deposits/referencesBind deposit address
GET/deposits/references/:refGet deposit address
GET/deposits/referencesList deposit references
GET/depositsList deposits
DELETE/deposits/references/:refUnbind address

🔄 Transfers API

Query blockchain transactions.

MethodEndpointDescription
GET/transfersList transfers
GET/transfers/:idGet transfer details

📬 Webhooks API

Configure webhook endpoints.

MethodEndpointDescription
POST/webhooks/endpointsCreate endpoint
GET/webhooks/endpointsList endpoints
PUT/webhooks/endpoints/:idUpdate endpoint
DELETE/webhooks/endpoints/:idDelete endpoint
GET/webhooks/eventsList events

Create no-code payment links.

MethodEndpointDescription
POST/payment-linksCreate link
GET/payment-linksList links
GET/payment-links/:idGet link details
PUT/payment-links/:idUpdate link
DELETE/payment-links/:idDelete link

🏦 Address Pool API

Manage address pool (admin only).

MethodEndpointDescription
POST/address-pool/importImport addresses
GET/address-pool/statusGet pool status
GET/address-pool/addressesList addresses

⚙️ Configuration API

Manage organization settings (admin only).

MethodEndpointDescription
GET/configGet all config
GET/config/:keyGet config value
PUT/config/:keyUpdate config

🔐 Organizations & API Keys

Manage organizations and API keys (admin only).

MethodEndpointDescription
GET/organizationsList organizations
POST/organizations/:id/api-keysCreate API key
GET/organizations/:id/api-keysList API keys
DELETE/api-keys/:keyIdDelete API key

Error Handling

Common Error Codes

CodeHTTP StatusDescriptionSolution
INVALID_API_KEY401API key is missing or invalidCheck API key is correct
INSUFFICIENT_PERMISSIONS403API key lacks required permissionsUse key with appropriate role
RESOURCE_NOT_FOUND404Requested resource doesn't existVerify ID is correct
DUPLICATE_ORDER_REFERENCE409Order reference already existsUse unique order reference
NO_AVAILABLE_ADDRESSES503Address pool exhaustedImport more addresses
INVALID_AMOUNT400Amount is invalid or negativeProvide valid positive amount
INVALID_CHAIN400Chain ID not supportedUse supported chain ID
INVALID_CURRENCY400Currency not supported on chainUse valid currency for chain
ORDER_EXPIRED400Cannot pay expired orderCreate new order
ORDER_ALREADY_PAID400Order already completedCheck order status

Error Response Structure

typescript
{
  error: string;          // Short error message
  message: string;        // Detailed error description
  code: string;          // Error code for programmatic handling
  statusCode: number;    // HTTP status code
  details?: any;         // Additional error context (optional)
}

Example Error Handling

TypeScript:

typescript
try {
  const response = await fetch('https://testnet.payin.com/api/v1/orders', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.PAYIN_API_KEY!
    },
    body: JSON.stringify({
      orderReference: 'ORDER-2025-001',
      amount: '100.00',
      currency: 'USDT',
      chainId: 'ethereum-sepolia'
    })
  });

  if (!response.ok) {
    const error = await response.json();

    switch (error.code) {
      case 'DUPLICATE_ORDER_REFERENCE':
        console.log('Order already exists, fetching existing order');
        // Fetch existing order
        break;
      case 'NO_AVAILABLE_ADDRESSES':
        console.error('Address pool exhausted, alerting admin');
        // Send alert to admin
        break;
      default:
        console.error('API Error:', error.message);
        throw new Error(error.message);
    }
  }

  const order = await response.json();
  console.log('Order created:', order);
} catch (error) {
  console.error('Request failed:', error);
}

Python:

python
import requests

try:
    response = requests.post(
        'https://testnet.payin.com/api/v1/orders',
        headers={
            'Content-Type': 'application/json',
            'X-API-Key': os.getenv('PAYIN_API_KEY')
        },
        json={
            'orderReference': 'ORDER-2025-001',
            'amount': '100.00',
            'currency': 'USDT',
            'chainId': 'ethereum-sepolia'
        }
    )

    response.raise_for_status()
    order = response.json()
    print(f"Order created: {order['orderId']}")

except requests.exceptions.HTTPError as e:
    error = e.response.json()

    if error['code'] == 'DUPLICATE_ORDER_REFERENCE':
        print('Order already exists')
    elif error['code'] == 'NO_AVAILABLE_ADDRESSES':
        print('Address pool exhausted')
    else:
        print(f"API Error: {error['message']}")

Versioning

The PayIn API uses URL versioning:

https://testnet.payin.com/api/v1/...

Current Version: v1

Deprecation Policy:

  • New API versions announced 6 months in advance
  • Old versions supported for 12 months after deprecation
  • Breaking changes only in new major versions
  • Non-breaking changes added to current version

SDKs & Libraries

Official SDKs:

  • TypeScript/Node.js
  • Python
  • PHP

Community SDKs:

Testing

Test Mode

Use testnet for testing:

  • Base URL: https://testnet.payin.com/api/v1
  • Free test tokens
  • Same API as production
  • Safe to experiment

Test Cards & Addresses

Testnet Chains:

  • Ethereum Sepolia
  • Polygon Amoy
  • Tron Nile
  • Solana Devnet

Getting Test Tokens:

Example Test Flow

bash
# 1. Create order on testnet
curl -X POST https://testnet.payin.com/api/v1/orders \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-testnet-key" \
  -d '{
    "orderReference": "TEST-001",
    "amount": "10.00",
    "currency": "USDT",
    "chainId": "ethereum-sepolia"
  }'

# 2. Send test USDT to the payment address

# 3. Check order status
curl https://testnet.payin.com/api/v1/orders/ord_xxx \
  -H "X-API-Key: your-testnet-key"

# 4. Verify webhook received (if configured)

Support & Resources

Documentation

API Status

  • Status Page
  • Check current API availability
  • Subscribe to incident notifications

Getting Help

  • Email: support@payin.com
  • Documentation: Browse this site
  • API Issues: Include request ID from error response

Rate Limit Increases

For enterprise usage with higher rate limits:

Next Steps

Released under the MIT License.