Dropshipping API
Integrate your store or ERP system with Tormino via our REST API. Place orders automatically, sync stock in real-time, and manage your wallet balance.
Table of contents
Authentication
All API requests require an API key (Bearer token). You receive this after your dropshipping application is approved. Add the key to every request header:
# Header format - Orders & Stock API Authorization: Bearer YOUR_API_KEY Content-Type: application/json # Header format - Wallet API (Shopwaive) X-Shopwaive-Access-Token: YOUR_SHOPWAIVE_API_KEY X-Shopwaive-Platform: shopify Content-Type: application/json
https://api.tormino.com/dropship/v1Wallet API:
https://app.shopwaive.com/api
Placing orders
Submit a new order from your system directly to our warehouse. The order is only created if wallet balance and stock are sufficient.
Request
| Parameter | Type | Required | Description |
|---|---|---|---|
| reference | string | Yes | Your internal order reference |
| shipping.name | string | Yes | End-customer full name |
| shipping.address1 | string | Yes | Street address |
| shipping.address2 | string | No | Additional address line |
| shipping.city | string | Yes | City |
| shipping.zip | string | Yes | Postal code |
| shipping.country | string | Yes | ISO 3166-1 alpha-2 (NL, BE, DE, FR) |
| shipping.phone | string | No | End-customer phone |
| shipping.email | string | No | End-customer email |
| items[].ean | string | Yes | Product EAN code |
| items[].sku | string | No | Product SKU (fallback if EAN missing) |
| items[].quantity | integer | Yes | Quantity to order |
// POST /orders { "reference": "ORD-2024-12345", "shipping": { "name": "Jan Jansen", "address1": "Kerkstraat 1", "address2": "", "city": "Amsterdam", "zip": "1011AB", "country": "NL", "phone": "+31612345678", "email": "jan@example.com" }, "items": [ { "ean": "8711234567890", "quantity": 2 } ] }
Response 200 OK
{
"order_id": "TORM-500123",
"status": "confirmed",
"wallet_balance_after": 425.50,
"currency": "EUR",
"estimated_ship_date": "2026-07-17"
}
Response 402 Payment Required
{
"error": "insufficient_wallet_balance",
"message": "Insufficient balance. Current: EUR 25.00. Required: EUR 74.50.",
"wallet_balance": 25.00,
"amount_required": 74.50,
"top_up_url": "https://tormino.nl/pages/b2b-dashboard#wallet"
}
Response 409 Conflict
{
"error": "insufficient_stock",
"message": "Item 8711234567890 has insufficient stock.",
"item_ean": "8711234567890",
"requested": 2,
"available": 1
}
Idempotency-Key header to prevent duplicate orders on retries. Same key = no duplicate order created.Stock synchronization
Check real-time availability of items before listing them in your store. Available as single or batch request.
Single item
{
"ean": "8711234567890",
"sku": "TORM-12345",
"available": true,
"quantity": 47,
"lead_time_days": 1
}
Batch (max 100 per request)
// Request { "eans": ["8711234567890", "8711234567891"] } // Response { "items": [ { "ean": "8711234567890", "available": true, "quantity": 47 }, { "ean": "8711234567891", "available": false, "quantity": 0 } ] }
Wallet management
Check your current balance and transaction history, or top up your wallet via iDeal.
Balance & transactions
# Headers X-Shopwaive-Access-Token: YOUR_SHOPWAIVE_API_KEY X-Shopwaive-Platform: shopify Content-Type: application/json # Response { "balance": 425.50, "activity": [ { "id": "action_739281", "type": "deposit", "amount": 500.00, "note": "Top-up via iDeal", "date": "2026-07-15T14:00:00Z", "status": "active" }, { "id": "action_739282", "type": "withdrawal", "amount": -74.50, "note": "Order TORM-500123", "date": "2026-07-16T10:30:00Z", "status": "active" } ] }
?activity=true for transaction history, ?orders=true for linked Shopify orders.
Top up
// Programmatore top-up (via Shopwaive API) PUT /customer X-Shopwaive-Access-Token: YOUR_SHOPWAIVE_API_KEY X-Shopwaive-Platform: shopify { "email": "partner@example.com", "amount": 500.00 }
Order overview
View your recent orders with fulfillment status and tracking number.
{
"orders": [
{
"order_id": "TORM-500123",
"reference": "ORD-2024-12345",
"status": "fulfilled",
"tracking_number": "3S1234567890",
"tracking_carrier": "PostNL",
"total": 74.50,
"created_at": "2026-07-16T10:30:00Z",
"shipped_at": "2026-07-17T09:15:00Z"
}
]
}
status (confirmed, shipped, cancelled), limit (max 50), offset for pagination.Webhooks
We send notifications to your configured webhook URL on order status changes. All webhooks are signed with HMAC-SHA256.
| Event | Trigger | Payload |
|---|---|---|
| order.confirmed | Order created + wallet charged | order_id, amount, wallet_balance_after |
| order.shipped | Fulfillment created in Shopify | order_id, tracking_number, tracking_carrier |
| order.cancelled | Order cancelled | order_id, reason, refund_amount |
| wallet.low_balance | Balance drops below threshold | balance, threshold, top_up_url |
Webhook verification
// Verify HMAC-SHA256 signature X-Tormino-Signature: sha256=hex_signature // Pseudocode expected = HMAC_SHA256(webhook_secret, raw_body) if expected == received_signature: process_webhook(payload) else: reject()
Error handling
The API uses standard HTTP status codes. Error responses contain a machine-readable error code and a description.
| Code | Error | Description |
|---|---|---|
| 401 | unauthorized | Missing or invalid API key |
| 402 | insufficient_wallet_balance | Wallet balance too low for order |
| 404 | product_not_found | EAN/SKU not found in catalog |
| 409 | insufficient_stock | Requested quantity exceeds available stock |
| 422 | validation_error | Missing or invalid request fields |
| 429 | rate_limit_exceeded | Too many requests (max 100/min) |
| 500 | internal_error | Server error - retry with backoff |
Code examples
Ready-to-use examples for placing an order in the most common programming languages.
$payload = [ 'reference' => 'ORD-2024-12345', 'shipping' => [ 'name' => 'Jan Jansen', 'address1' => 'Kerkstraat 1', 'city' => 'Amsterdam', 'zip' => '1011AB', 'country' => 'NL', ], 'items' => [ ['ean' => '8711234567890', 'quantity' => 2], ], ]; $ch = curl_init('https://api.tormino.com/dropship/v1/orders'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json', 'Idempotency-Key: ' . uniqid(), ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($httpCode === 200) { $result = json_decode($response, true); echo "Order confirmed: " . $result['order_id']; } elseif ($httpCode === 402) { echo "Insufficient wallet balance"; } curl_close($ch);
import requests import uuid payload = { "reference": "ORD-2024-12345", "shipping": { "name": "Jan Jansen", "address1": "Kerkstraat 1", "city": "Amsterdam", "zip": "1011AB", "country": "NL", }, "items": [ {"ean": "8711234567890", "quantity": 2}, ], } headers = { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", "Idempotency-Key": str(uuid.uuid4()), } response = requests.post( "https://api.tormino.com/dropship/v1/orders", json=payload, headers=headers, ) if response.status_code == 200: data = response.json() print(f"Order confirmed: {data['order_id']}") elif response.status_code == 402: print("Insufficient wallet balance")
const response = await fetch('https://api.tormino.com/dropship/v1/orders', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', 'Idempotency-Key': crypto.randomUUID(), }, body: JSON.stringify({ reference: 'ORD-2024-12345', shipping: { name: 'Jan Jansen', address1: 'Kerkstraat 1', city: 'Amsterdam', zip: '1011AB', country: 'NL', }, items: [ { ean: '8711234567890', quantity: 2 }, ], }), }); const data = await response.json(); if (response.ok) { console.log(`Order confirmed: ${data.order_id}`); } else if (response.status === 402) { console.log('Insufficient wallet balance'); }
Rate limits & best practices
Maximum 100 requests per minute per API key. Use batch endpoints for stock checks to save requests.
| Limit | Value |
|---|---|
| Requests per minute | 100 per API key |
| Requests per hour | 1000 per API key |
| Batch stock check | Max 100 EANs per request |
| Orders per request | 1 (one order per API call) |
| Rate limit headers | X-RateLimit-Remaining, X-RateLimit-Reset |
Idempotency-Key on order requests to safely retry on network errors.