Merchant & Withdrawals
Process withdrawal requests and manage payment methods
Process withdrawal requests, manage payment methods, and handle external payouts.
Withdrawal Process
- User initiates withdrawal via Wallet API (Keys are locked)
- Merchant service processes payment through payment processor
- Transaction is marked as completed or failed
- Wallet service is notified of the result
Overview
The Merchant API provides:
- Withdrawal request management
- Payment processing integration
- Withdrawal status tracking
- Payment method configuration
- Admin withdrawal management
Base Path: /v1/withdrawals
Keys are Always Integers
Important: Keys are always whole numbers (integers). The amount field in withdrawal requests represents the number of Keys (e.g., 75, not 75.50). The USD value is calculated on the backend using the exchange rate.
Withdrawal Requests
Create Withdrawal Request
Create a new withdrawal request. This should be called after initiating a withdrawal via the Wallet API.
POST /v1/withdrawalsX-API-Key: your-api-key
Authorization: Bearer your-jwt-token
Content-Type: application/json{
"transactionId": "TXN-1697891234-GHI90123",
"amount": 75,
"paymentMethod": "bank_transfer",
"paymentDetails": {
"accountNumber": "1234567890",
"routingNumber": "987654321",
"accountName": "John Doe",
"bankName": "Example Bank"
},
"metadata": {
"userId": "user_456"
}
}Try it out:
# Development
curl -X POST "https://api-gateway.dev.1houseglobalservices.com/v1/withdrawals" \
-H "X-API-Key: your-development-api-key" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{
"transactionId": "TXN-1697891234-GHI90123",
"amount": 75,
"paymentMethod": "bank_transfer",
"paymentDetails": {
"accountNumber": "1234567890",
"routingNumber": "987654321"
}
}'
# Production
curl -X POST "https://api-gateway.prod.1houseglobalservices.com/v1/withdrawals" \
-H "X-API-Key: your-production-api-key" \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-d '{
"transactionId": "TXN-1697891234-GHI90123",
"amount": 75,
"paymentMethod": "bank_transfer",
"paymentDetails": {
"accountNumber": "1234567890",
"routingNumber": "987654321"
}
}'// Development
const DEV_API_URL = 'https://api-gateway.dev.1houseglobalservices.com';
const DEV_API_KEY = 'your-development-api-key';
// Production
const PROD_API_URL = 'https://api-gateway.prod.1houseglobalservices.com';
const PROD_API_KEY = 'your-production-api-key';
// Use appropriate environment
const apiUrl = process.env.NODE_ENV === 'production' ? PROD_API_URL : DEV_API_URL;
const apiKey = process.env.NODE_ENV === 'production' ? PROD_API_KEY : DEV_API_KEY;
const response = await fetch(`${apiUrl}/v1/withdrawals`, {
method: 'POST',
headers: {
'X-API-Key': apiKey,
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
transactionId: 'TXN-1697891234-GHI90123',
amount: 75,
paymentMethod: 'bank_transfer',
paymentDetails: {
accountNumber: '1234567890',
routingNumber: '987654321'
}
})
});
const data = await response.json();import requests
import os
# Development
DEV_API_URL = 'https://api-gateway.dev.1houseglobalservices.com'
DEV_API_KEY = 'your-development-api-key'
# Production
PROD_API_URL = 'https://api-gateway.prod.1houseglobalservices.com'
PROD_API_KEY = 'your-production-api-key'
# Use appropriate environment
api_url = PROD_API_URL if os.getenv('ENVIRONMENT') == 'production' else DEV_API_URL
api_key = PROD_API_KEY if os.getenv('ENVIRONMENT') == 'production' else DEV_API_KEY
response = requests.post(
f'{api_url}/v1/withdrawals',
headers={
'X-API-Key': api_key,
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
},
json={
'transactionId': 'TXN-1697891234-GHI90123',
'amount': 75,
'paymentMethod': 'bank_transfer',
'paymentDetails': {
'accountNumber': '1234567890',
'routingNumber': '987654321'
}
}
)
data = response.json(){
"success": true,
"status": 201,
"message": "Withdrawal request created successfully",
"data": {
"_id": "withdrawal_123",
"requestId": "WDR-1697891234-ABC12345",
"userId": "user_456",
"transactionId": "TXN-1697891234-GHI90123",
"amount": 75.00,
"currency": "Keys",
"status": "pending",
"paymentMethod": "bank_transfer",
"paymentDetails": {
"accountNumber": "1234567890",
"routingNumber": "987654321"
},
"createdAt": "2025-10-21T12:00:00.000Z"
},
"meta": {
"timestamp": "2025-10-21T12:00:00.000Z",
"version": "v1"
}
}Get User's Withdrawals
Retrieve withdrawal requests for the authenticated user.
GET /v1/withdrawals| Parameter | Type | Description | Default |
|---|---|---|---|
| page | number | Page number | 1 |
| limit | number | Results per page | 50 |
| status | string | Filter by status | all |
| startDate | string | Start date (ISO 8601) | none |
| endDate | string | End date (ISO 8601) | none |
{
"success": true,
"status": 200,
"message": "Withdrawals retrieved successfully",
"data": [
{
"requestId": "WDR-1697891234-ABC12345",
"amount": 75,
"status": "completed",
"paymentMethod": "bank_transfer",
"merchantTransactionId": "MERCHANT-1697891234-XYZ789",
"processedAt": "2025-10-21T13:00:00.000Z",
"createdAt": "2025-10-21T12:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 5,
"pages": 1
}
}Get Withdrawal by ID
Retrieve a specific withdrawal request.
GET /v1/withdrawals/:requestId{
"success": true,
"status": 200,
"data": {
"_id": "withdrawal_123",
"requestId": "WDR-1697891234-ABC12345",
"userId": {
"_id": "user_456",
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe"
},
"transactionId": "TXN-1697891234-GHI90123",
"amount": 75,
"currency": "Keys",
"status": "completed",
"paymentMethod": "bank_transfer",
"paymentDetails": {
"accountNumber": "1234567890",
"routingNumber": "987654321",
"accountName": "John Doe",
"bankName": "Example Bank"
},
"merchantTransactionId": "MERCHANT-1697891234-XYZ789",
"processedAt": "2025-10-21T13:00:00.000Z",
"processedBy": "system",
"createdAt": "2025-10-21T12:00:00.000Z",
"updatedAt": "2025-10-21T13:00:00.000Z"
}
}Process Withdrawal (Admin/System)
Process a pending withdrawal request through the payment processor.
POST /v1/withdrawals/:requestId/process{
"success": true,
"status": 200,
"message": "Withdrawal processed successfully",
"data": {
"requestId": "WDR-1697891234-ABC12345",
"status": "completed",
"merchantTransactionId": "MERCHANT-1697891234-XYZ789",
"processedAt": "2025-10-21T13:00:00.000Z",
"processedBy": "admin@example.com"
}
}Cancel Withdrawal
Cancel a pending withdrawal request (refunds Keys to wallet).
POST /v1/withdrawals/:requestId/cancel{
"reason": "User requested cancellation"
}{
"success": true,
"status": 200,
"message": "Withdrawal cancelled successfully",
"data": {
"requestId": "WDR-1697891234-ABC12345",
"status": "cancelled",
"errorMessage": "User requested cancellation"
}
}Admin Endpoints
Get All Withdrawals (Admin Only)
Retrieve all withdrawal requests in the system.
GET /v1/withdrawals/admin/all| Parameter | Type | Description | Default |
|---|---|---|---|
| page | number | Page number | 1 |
| limit | number | Results per page | 100 |
| status | string | Filter by status | all |
| userId | string | Filter by user ID | all |
| paymentMethod | string | Filter by payment method | all |
| startDate | string | Start date (ISO 8601) | none |
| endDate | string | End date (ISO 8601) | none |
Get Pending Withdrawals (Admin Only)
Retrieve all pending withdrawal requests.
GET /v1/withdrawals/admin/pending{
"success": true,
"status": 200,
"data": [
{
"requestId": "WDR-1697891234-ABC12345",
"userId": {
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe"
},
"amount": 75,
"paymentMethod": "bank_transfer",
"status": "pending",
"createdAt": "2025-10-21T12:00:00.000Z"
}
]
}Payment Methods
Withdrawal Status
| Status | Description |
|---|---|
| pending | Withdrawal request created, awaiting processing |
| processing | Payment is being processed by payment processor |
| completed | Payment successfully processed and sent |
| failed | Payment processing failed |
| cancelled | Withdrawal was cancelled (Keys refunded) |
Withdrawal Request Object
| Field | Type | Description |
|---|---|---|
| requestId | string | Unique withdrawal request identifier |
| userId | string/Object | User who requested withdrawal |
| transactionId | string | Associated wallet transaction ID |
| amount | integer | Withdrawal amount in Keys (number of Keys, always whole number) |
| currency | string | Currency code (always "Keys") |
| status | string | Withdrawal status |
| paymentMethod | string | Payment method type |
| paymentDetails | object | Payment method specific details |
| merchantTransactionId | string | Payment processor transaction ID |
| processedAt | datetime | When payment was processed |
| processedBy | string | Who processed the payment |
| errorMessage | string | Error message (if failed) |
| errorCode | string | Error code (if failed) |
| metadata | object | Additional metadata |
| notes | string | Admin notes |
| createdAt | datetime | Request creation date |
| updatedAt | datetime | Last update date |
Withdrawal Flow
1. User initiates withdrawal via Wallet API
POST /v1/wallets/withdraw
- Keys are locked (deducted from balance)
- Transaction created with status "pending"
2. User creates withdrawal request
POST /v1/withdrawals
- Withdrawal request created with status "pending"
- Links to wallet transaction
3. Admin/System processes withdrawal
POST /v1/withdrawals/:requestId/process
- Payment processor API called
- Merchant transaction ID generated
- Wallet service notified to complete transaction
4. Wallet service completes transaction
- Transaction status updated to "completed"
- Keys remain deducted (already sent)
OR
3. Withdrawal fails or is cancelled
POST /v1/withdrawals/:requestId/cancel
- Wallet service notified to refund
- Keys refunded to wallet
- Transaction status updated to "cancelled"Best Practices
1. Validate Payment Details
const validateBankDetails = (details) => {
if (!details.accountNumber || !details.routingNumber) {
throw new Error('Account number and routing number required');
}
// Additional validation...
};2. Handle Processing Errors
try {
await processWithdrawal(requestId);
} catch (error) {
// Log error
// Notify user
// Cancel withdrawal if needed
await cancelWithdrawal(requestId, error.message);
}3. Monitor Pending Withdrawals
// Admin dashboard should regularly check for pending withdrawals
const pending = await getPendingWithdrawals();
pending.forEach(withdrawal => {
// Process or alert
});4. Secure Payment Details
// Never log full payment details
const sanitized = {
...paymentDetails,
accountNumber: `****${accountNumber.slice(-4)}`
};Error Handling
Insufficient Balance
{
"success": false,
"status": 400,
"message": "Insufficient balance"
}Invalid Payment Method
{
"success": false,
"status": 400,
"message": "Invalid payment method",
"errors": [
{
"field": "paymentMethod",
"message": "Payment method must be one of: bank_transfer, paypal, stripe, crypto, other"
}
]
}Processing Failure
{
"success": false,
"status": 500,
"message": "Payment processing failed",
"error": "Payment processor timeout"
}Related Documentation
- Wallet Service - Wallet management and transactions
- Authentication - Get your tokens
- Platform Types - Data models and types