Merchant API Documentation
Direct API integration for deposits, withdrawals, and real-time callbacks.
https://api.veltorapay.comAll endpoints use the
/dealer/{dealerName} prefix where {dealerName} is your assigned merchant identifier.
Authentication
All API requests require header-based authentication using your API key and secret.
| Header | Required | Description |
|---|---|---|
| X-API-Key | Required | Your API key. Can also contain key:secret combined format. |
| X-API-Secret | Optional | Your API secret. If omitted, include it in X-API-Key as key:secret. |
| Content-Type | Required | application/json |
X-API-Key: your-api-key
X-API-Secret: your-api-secret
Content-Type: application/json
Create Deposit
POST/dealer/{dealerName}/create-deposit
Creates a new deposit request and returns the assigned bank account details for the customer to transfer funds to.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| amount | decimal | Required | Deposit amount in TRY (0.01 – 10,000,000) |
| senderName | string | Optional | Sender's full name. Alias: userName |
| clientToken | string | Optional | Your unique transaction reference. Alias: transactionId |
| userId | string | Optional | Customer user identifier (max 120 chars) |
POST /dealer/yourmerchant/create-deposit
Content-Type: application/json
X-API-Key: your-api-key
X-API-Secret: your-api-secret
{
"amount": 1000.00,
"senderName": "Ahmet Yilmaz",
"clientToken": "TXN-20260331-001",
"userId": "user-12345"
}
Response — 200 OK
{
"success": true,
"token": "c3d4e5f6-7890-abcd-ef12-345678901234",
"amount": 1000.00,
"senderName": "Ahmet Yilmaz",
"source": "Source-1",
"assignedTo": {
"walletId": "EXT-WALLET-001",
"accountHolder": "VeltoraPay A.S.",
"bank": "Ziraat Bankasi",
"iban": "TR12 0001 0012 3456 7890 1234 56"
},
"createdAt": "2026-03-31T10:00:00Z"
}
token value — you'll need it to check deposit status and match callbacks.
Check Deposit
POST/dealer/{dealerName}/check-deposit
Check the status of a deposit request by its token.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| token | string | Required | The deposit token returned from create-deposit |
{
"token": "c3d4e5f6-...",
"clientToken": "TXN-20260331-001",
"amount": 1000.00,
"senderName": "Ahmet Yilmaz",
"status": "Matched",
"iban": "TR12 0001 0012 3456 7890 1234 56",
"accountHolder": "VeltoraPay A.S.",
"bank": "Ziraat Bankasi",
"source": "Source-1",
"matchedAt": "2026-03-31T10:05:30Z",
"createdAt": "2026-03-31T10:00:00Z",
"updatedAt": "2026-03-31T10:05:30Z"
}
Create Withdraw
POST/dealer/{dealerName}/create-withdraw
Creates a new withdrawal request. The system selects the optimal source and processes the payment to the customer's bank account.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| amount | decimal | Required | Withdraw amount in TRY (0.01 – 10,000,000) |
| recipientName | string | Required | Recipient's full name |
| recipientIban | string | Required | Recipient's IBAN |
| recipientBank | string | Optional | Recipient's bank name |
| clientToken | string | Optional | Your unique transaction reference |
| userId | string | Optional | Customer user identifier (max 120 chars) |
POST /dealer/yourmerchant/create-withdraw
Content-Type: application/json
X-API-Key: your-api-key
X-API-Secret: your-api-secret
{
"amount": 500.00,
"recipientName": "Mehmet Demir",
"recipientIban": "TR76 0006 2000 1234 5678 9012 34",
"recipientBank": "Garanti BBVA",
"clientToken": "WD-20260331-001"
}
Response — 200 OK
{
"success": true,
"token": "a1b2c3d4-5678-...",
"amount": 500.00,
"recipientName": "Mehmet Demir",
"recipientIban": "TR76 0006 2000 1234 5678 9012 34",
"source": "Pool",
"status": "Pending",
"createdAt": "2026-03-31T11:00:00Z"
}
Failed status and a rejection callback will be sent automatically.
Check Withdraw
POST/dealer/{dealerName}/check-withdraw
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| token | string | Required | The withdraw token returned from create-withdraw |
{
"token": "a1b2c3d4-...",
"clientToken": "WD-20260331-001",
"amount": 500.00,
"recipientName": "Mehmet Demir",
"recipientIban": "TR76 0006 2000 1234 5678 9012 34",
"recipientBank": "Garanti BBVA",
"status": "Succeeded",
"externalStatus": "Succeeded",
"source": "Pool",
"createdAt": "2026-03-31T11:00:00Z",
"updatedAt": "2026-03-31T11:02:30Z"
}
List Deposits
GET/dealer/{dealerName}/deposits
Paginated list of your deposit requests.
Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| status | string | — | Filter by status: Pending, Matched, Rejected, Timeout, ManualApproved |
| fromDate | date | — | Start date (YYYY-MM-DD) |
| toDate | date | — | End date (YYYY-MM-DD) |
| page | int | 1 | Page number |
| pageSize | int | 50 | Items per page (max 200) |
List Withdraws
GET/dealer/{dealerName}/withdraws
Paginated list of your withdraw requests. Same query parameters as List Deposits.
Deposit Callbacks
VeltoraPay sends HTTP POST callbacks to your configured Deposit Callback URL when a deposit status changes.
Callback PayloadPOST {your_deposit_callback_url}
Content-Type: application/json
{
"event": "deposit.status_changed",
"token": "c3d4e5f6-...",
"clientToken": "TXN-20260331-001",
"status": "matched",
"amount": 1000.00,
"senderName": "Ahmet Yilmaz",
"customerName": "Ahmet Yilmaz",
"iban": "TR12 0001 0012 3456 7890 1234 56",
"accountHolder": "VeltoraPay A.S.",
"bank": "Ziraat Bankasi",
"source": "Source-1",
"matchedAt": "2026-03-31T10:05:30Z",
"timestamp": "2026-03-31T10:05:30Z"
}
Callback Status Values
| Status | Meaning |
|---|---|
| matched | Deposit matched or manually approved — funds received |
| cancelled | Deposit was rejected |
| timeout | Deposit timed out — no matching transfer detected |
Retry Policy
If your callback URL returns a non-2xx response, VeltoraPay retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 15 minutes |
| 5 | 30 minutes |
| 6 | 60 minutes |
{{placeholder}} tokens. Contact your account manager for setup.
Withdraw Callbacks
VeltoraPay sends HTTP POST callbacks to your configured Withdraw Callback URL when a withdrawal status changes.
Callback PayloadPOST {your_withdraw_callback_url}
Content-Type: application/json
{
"event": "withdraw.status_changed",
"token": "a1b2c3d4-...",
"clientToken": "WD-20260331-001",
"status": "Completed",
"externalStatus": "Succeeded",
"amount": 500.00,
"recipientName": "Mehmet Demir",
"recipientIban": "TR76 0006 2000 1234 5678 9012 34",
"recipientBank": "Garanti BBVA",
"source": "Pool",
"timestamp": "2026-03-31T11:02:30Z"
}
Callback Status Values
| Status | Meaning |
|---|---|
| Completed | Withdrawal succeeded — funds sent |
| Rejected | Withdrawal failed or rejected |
| Timeout | Withdrawal timed out |
Status Reference
Deposit Statuses
| Status | Value | Description |
|---|---|---|
| Pending | 0 | Waiting for bank transfer |
| Matched | 1 | Auto-matched with bank transaction |
| Rejected | 2 | Rejected by admin or system |
| Timeout | 3 | Expired — no match found |
| ManualApproved | 4 | Manually approved by operator |
Withdraw Statuses
| Status | Value | Description |
|---|---|---|
| Pending | 0 | Queued for processing |
| InProgress | 1 | Being processed by payment source |
| Succeeded | 2 | Funds sent to recipient |
| Failed | 3 | Rejected or insufficient balance |
| Timeout | 4 | Processing timed out |
Error Codes
| HTTP | Code | Description |
|---|---|---|
| 400 | invalid_body | Request body is invalid or missing |
| 400 | missing_field | A required field is missing |
| 400 | invalid_amount | Amount is not a valid number |
| 400 | amount_below_minimum | Amount is below minimum threshold |
| 400 | amount_above_maximum | Amount exceeds maximum threshold |
| 400 | iban_required | Recipient IBAN is missing (withdraw) |
| 401 | unauthorized | Invalid or missing API key/secret |
| 403 | ip_not_whitelisted | Request IP is not in whitelist |
| 403 | user_banned | The userId is banned |
| 404 | not_found | Token or resource not found |
| 409 | duplicate_token | clientToken already exists with active status |
| 409 | no_eligible_account | No suitable bank account available |
| 429 | rate_limited | Too many requests |
| 503 | no_available_source | No payment source available |
Rate Limiting
API requests are rate-limited to 120 requests per 60 seconds per IP address. Exceeding this limit returns 429 Too Many Requests.
Security Best Practices
- IP Whitelisting: Configure your server IPs in the merchant panel. Only accept VeltoraPay callbacks from our server IP.
- Token Verification: Always cross-check
tokenandclientTokenin callbacks against your records. - Status Verification: After receiving a callback, call
check-depositorcheck-withdrawto confirm the status independently. - HTTPS Only: All callback URLs must use HTTPS.
- Idempotency: Design your callback handler to be idempotent — you may receive the same callback multiple times.