REST API · JSON · Bearer Auth

Shiplee
API Reference

Full logistics integration — authenticate, create orders, fetch rates, book, cancel and track shipments.https://apiv1.shiplee.app

Overview

The Shiplee API is a RESTful JSON interface for programmatic logistics management. All requests and responses use application/json unless noted.

Capabilities

All protected endpoints require Authorization: Bearer <token>. Tokens expire after 1 hour — re-authenticate via /login to refresh.

Authentication

Shiplee uses signed JWT tokens bound to your seller account. Every token encodes your user ID, email, and Shiplee ID.

Setup steps
  1. Register at app.shiplee.ai and generate an API key in API Settings.
  2. Whitelist your server IP address and request domain in API Settings.
  3. POST credentials to /login — receive a JWT valid for 1 hour.
  4. Pass Authorization: Bearer <token> on every subsequent request.

Both IP and domain must be whitelisted. Requests from unknown origins return 403 Forbidden.

Login

POST/login

Authenticates your credentials and returns a JWT token.

Request body
json
{
    "username": "you@example.com",
    "apikey":   "your-api-key"
}
Code examples
bash
curl -X POST https://apiv1.shiplee.app/login \
  -H "Content-Type: application/json" \
  -H "Origin: http://localhost" \
  -d '{"username":"you@example.com","apikey":"your-api-key"}'
powershell
$body    = @{ username = "you@example.com"; apikey = "your-api-key" } | ConvertTo-Json
$headers = @{ "Content-Type" = "application/json"; "Origin" = "http://localhost" }
Invoke-RestMethod -Uri "https://apiv1.shiplee.app/login" -Method Post -Body $body -Headers $headers
php
<?php
$ch = curl_init('https://apiv1.shiplee.app/login');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json','Origin: http://localhost'],
    CURLOPT_POSTFIELDS => json_encode(['username'=>'you@example.com','apikey'=>'your-api-key']),
]);
echo curl_exec($ch); curl_close($ch);
python
import requests
r = requests.post('https://apiv1.shiplee.app/login',
    json={'username': 'you@example.com', 'apikey': 'your-api-key'},
    headers={'Origin': 'http://localhost'})
token = r.json()['token']
javascript
const { token } = await fetch('https://apiv1.shiplee.app/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: 'you@example.com', apikey: 'your-api-key' })
}).then(r => r.json());
Response 200
json
{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": { "id": 62, "email": "you@example.com", "shiplee_id": "d10701280b9798033c6917e9415b03c3" }
}

Add Order

POST/order

Creates a new forward order. Returns a numeric order_id used across all shipping endpoints.

Request body
json
{
    "pincode": "560098", "city": "Bangalore", "state": "Karnataka",
    "name": "John Doe", "email": "customer@example.com", "mobileNumber": "9000000001",
    "addressLine1": "123 Sample Street, Apt 4B", "sameAddressCheckbox": 1,
    "orderID": "ORD-123456", "paymentType": "prepaid",
    "products": [{ "productName": "Sample Product", "quantity": 2, "productPrice": 500.00, "sku": "SKU123" }],
    "parcels": [{ "length": 10, "breadth": 10, "height": 10, "physicalWeight": 1.5 }]
}

Set sameAddressCheckbox to 0 and add billingPincode, billingName, etc. for separate billing addresses.

Response 201
json
{ "success": true, "message": "Order added successfully", "order_id": 484900 }

Reverse Order

POST/reverse_order

Creates a reverse pickup order for a customer return or exchange.

Critical: orderId must be the numeric integer from /order (e.g. 484900). The warehouseId must belong to your account.

Request body
json
{
    "orderId": 484900, "awbNumber": "XB1234567890", "reason": "Customer return — wrong size",
    "warehouseId": 2147483833, "paymentType": "prepaid", "insurance": false,
    "customer": { "name": "John Doe", "mobile": "9000000001", "address1": "123 Sample Street, Apt 4B",
        "pincode": "560098", "city": "Bangalore", "state": "Karnataka" },
    "products": [{ "productName": "Sample Product", "quantity": 1, "productPrice": 500.00, "sku": "SKU123" }],
    "parcel": { "length": 10, "breadth": 10, "height": 10, "physicalWeight": 1.5 }
}
Response 201
json
{ "success": true, "message": "Reverse order created successfully", "reverse_order_id": "RO-7A685" }

Get Rates

POST/rates

Returns available courier options with freight and COD charges for an existing order.

Request body
json
{ "orderId": 484900, "warehouseId": 2147483833, "shipmentType": "forward" }
Response 200
json
{
    "success": true, "message": "Rates fetched successfully",
    "data": { "carrier_info": [
        { "carrier_id": "delhivery_e_prepaid", "carrier_name": "Delhivery Express", "cost": 138, "freight_charges": 138, "cod_charges": 0, "tat": "2-3 days" },
        { "carrier_id": "delhivery_s_prepaid", "carrier_name": "Delhivery Surface",  "cost": 104, "freight_charges": 104, "cod_charges": 0, "tat": "4-6 days" }
    ]}
}

Create Shipment

POST/create_shipment

Books a forward shipment for an existing order. Deducts charges from your wallet and returns the AWB number.

Minimum wallet balance of ₹500 required. Duplicate bookings for the same orderId are rejected automatically.

Request body
json
{
    "orderId": 484900, "warehouseId": 2147483833, "action": "book_shipment",
    "carrierId": "delhivery_e_prepaid", "carrierName": "Delhivery Express", "shipmentType": "forward"
}
Response 201
json
{ "success": true, "message": "Shipment booked", "awb_number": "XB1234567890", "shipment_id": "SHPL-54321" }

Cancel Shipment

POST/cancel_shipment

Cancels one or more booked shipments by AWB. Calls the courier's own cancellation API, deletes the booking record, credits the full shipping charge back to your wallet, and either resets the order for re-booking or marks it permanently cancelled.

Only cancellable statuses: Orders must be in booked or manifested state. Already delivered, RTO, or new orders will be rejected. If any AWB in a batch fails the ownership or status check the entire request is rejected.

The cancel is atomic — if the courier API call succeeds but any DB step fails, the entire transaction is rolled back and the courier cancellation is logged for manual review.

Request body
json — single AWB
{
    "awb":    "XB1234567890",
    "action": "cancel"
}
json — bulk (up to 50)
{
    "awbs":   ["XB1234567890", "37574910074362"],
    "action": "delete"
}
Request fields
FieldTypeRequiredDescription
awbstringoptional*Single AWB to cancel. Alphanumeric + _-, max 50 chars.
awbsarrayoptional*Array of AWB strings. Max 50 per request.
actionstringoptionalcancel (default) or delete — see table below.

* Provide either awb or awbs — at least one is required.

Action types
actionOrder status after cancelCan re-book?Use case
cancelnew✅ YesWrong courier / address — want to re-book immediately
deletecancelled❌ NoOrder genuinely cancelled by customer
What happens internally
  1. JWT + IP whitelist verified
  2. Every AWB checked — must belong to your account and be in booked / manifested state
  3. Courier cancel API called (auto-detected: Delhivery → XpressBees → Amazon → SmartShip)
  4. Row deleted from orders table
  5. customer_info.status updated to new or cancelled
  6. Full shipping charge credited back to your wallet
  7. Entry added to RechargeLogs (Credit) and ShippingCharges (status = cancelled)
  8. Full audit trail written to CancelDeleteLogs
  9. Entire batch rolled back if any step fails
Code examples
bash
# Cancel single — reset to new (re-bookable)
curl -X POST https://apiv1.shiplee.app/cancel_shipment \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{"awb":"XB1234567890","action":"cancel"}'

# Delete bulk — permanently cancelled
curl -X POST https://apiv1.shiplee.app/cancel_shipment \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{"awbs":["XB1234567890","37574910074362"],"action":"delete"}'
php
<?php
// Cancel single AWB — reset to new so you can re-book
$ch = curl_init('https://apiv1.shiplee.app/cancel_shipment');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        'Authorization: Bearer YOUR_JWT_TOKEN',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'awb'    => 'XB1234567890',
        'action' => 'cancel',   // resets to 'new' — re-bookable
    ]),
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);

if ($res['success']) {
    echo "Cancelled. Refunded: " . $res['refunded_count'] . " shipment(s).";
    // Order is now 'new' — call /rates then /create_shipment to re-book
} else {
    echo "Error: " . $res['message'];
}
python
import requests

headers = {'Authorization': 'Bearer YOUR_JWT_TOKEN'}

# Cancel single — re-bookable
r = requests.post('https://apiv1.shiplee.app/cancel_shipment',
    json={'awb': 'XB1234567890', 'action': 'cancel'},
    headers=headers)
print(r.json())
# {'success': True, 'message': 'Shipment(s) cancelled and reset to new...', 'refunded_count': 1}

# Cancel bulk — permanently deleted
r2 = requests.post('https://apiv1.shiplee.app/cancel_shipment',
    json={'awbs': ['XB1234567890', '37574910074362'], 'action': 'delete'},
    headers=headers)
print(r2.json())
javascript
// Cancel and re-book flow
async function cancelAndRebook(awb, orderId, warehouseId) {
    // Step 1 — cancel
    const cancel = await fetch('https://apiv1.shiplee.app/cancel_shipment', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_JWT_TOKEN' },
        body: JSON.stringify({ awb, action: 'cancel' }),
    }).then(r => r.json());

    if (!cancel.success) throw new Error(cancel.message);

    // Step 2 — get new rates
    const rates = await fetch('https://apiv1.shiplee.app/rates', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_JWT_TOKEN' },
        body: JSON.stringify({ orderId, warehouseId, shipmentType: 'forward' }),
    }).then(r => r.json());

    const carrier = rates.data.carrier_info[0]; // pick cheapest

    // Step 3 — re-book with new carrier
    const booking = await fetch('https://apiv1.shiplee.app/create_shipment', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_JWT_TOKEN' },
        body: JSON.stringify({
            orderId, warehouseId, action: 'book_shipment',
            carrierId: carrier.carrier_id, carrierName: carrier.carrier_name,
            shipmentType: 'forward',
        }),
    }).then(r => r.json());

    return booking; // { success: true, awb_number: 'NEW_AWB', ... }
}
Success response 200
json
{
    "success":        true,
    "message":        "Shipment(s) cancelled and reset to new. You can re-book them.",
    "refunded_count": 1
}
Error responses 4xx
json
{ "success": false, "message": "Missing Authorization header" }
{ "success": false, "message": "Invalid JWT token" }
{ "success": false, "message": "User account not active" }
{ "success": false, "message": "The IP '1.2.3.4' is not whitelisted" }
{ "success": false, "message": "Provide \"awb\" (string) or \"awbs\" (array)" }
{ "success": false, "message": "Invalid action: must be \"cancel\" or \"delete\"" }
{ "success": false, "message": "Maximum 50 AWBs per request" }
{ "success": false, "message": "One or more AWBs not found, do not belong to your account, or are not in a cancellable state (must be booked/manifested)" }
{ "success": false, "message": "Delhivery cancel failed for AWB XB1234567890: ..." }
{ "success": false, "message": "Internal server error" }

Re-booking flow: After a successful action: "cancel", the order is back in new state. Call /rates with the same orderId + warehouseId, pick a carrier, then call /create_shipment to get a fresh AWB — no need to recreate the order.

Reverse Shipment

POST/reverse_create_shipment

Books a Delhivery pickup for an existing reverse order. Request body is application/x-www-form-urlencoded.

Request body
form-urlencoded
order_id=1042&warehouse_id=2147483833&carrierId=delhivery_e_prepaid&carrierName=Delhivery+Express
Response 200
json
{ "success": true, "message": "Reverse shipment booked", "awb_number": "1234567890123", "shipment_id": "UPLOAD_WBN_ABC" }

Track Shipment

GET/track?awb={awb_number}

Returns the full tracking timeline for a shipment by AWB number. Sellers can only query AWBs belonging to their own account.

Response 200
json
{
    "data": {
        "orderNumber": "122", "orderStatus": "Manifested", "orderStatusCode": "manifested",
        "trackingNumber": "80905112190", "carrierName": "Blue Dart- Apex",
        "paymentType": "cod", "orderValue": 1450, "weightGrams": 500,
        "trackingDetails": [
            { "scanStatus": "SHIPMENT DELIVERED", "scanLocation": "KATARGAM OFFICE", "scanDateTime": "2025-09-27 16:31:00", "message": "delivered" }
        ]
    }, "errorMessage": null
}

Generate Label

POST/label

Generates a shipping label PDF for one or more AWBs. Returns a binary PDF stream (application/pdf) ready for download or direct printing.

Security: Every AWB is verified against your seller account. If any AWB belongs to another seller the entire request is rejected with 403.

Response Content-Type is application/pdf on success and application/json on error — check the header before parsing.

Request body
json — single
{ "awb": "80905112190" }
json — bulk (up to 50)
{ "awbs": ["80905112190", "XB1234567890", "1234567890123"] }
Code examples
bash
curl -X POST https://apiv1.shiplee.app/label \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{"awb":"80905112190"}' --output label.pdf
php
<?php
$ch = curl_init('https://apiv1.shiplee.app/label');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,
    CURLOPT_HTTPHEADER=>['Content-Type: application/json','Authorization: Bearer YOUR_JWT_TOKEN'],
    CURLOPT_POSTFIELDS=>json_encode(['awb'=>'80905112190'])]);
$res = curl_exec($ch);
$ct  = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); curl_close($ch);
if (str_contains($ct,'application/pdf')) { file_put_contents('label.pdf',$res); echo "Saved."; }
else { echo json_decode($res,true)['message']; }
python
import requests
r = requests.post('https://apiv1.shiplee.app/label',
    json={'awb': '80905112190'},
    headers={'Authorization': 'Bearer YOUR_JWT_TOKEN'})
if r.headers.get('Content-Type','').startswith('application/pdf'):
    open('label.pdf','wb').write(r.content)
else: print(r.json()['message'])
javascript
const res = await fetch('https://apiv1.shiplee.app/label', {
    method:'POST', headers:{'Content-Type':'application/json','Authorization':'Bearer YOUR_JWT_TOKEN'},
    body: JSON.stringify({ awb: '80905112190' })
});
if (res.headers.get('Content-Type')?.includes('application/pdf')) {
    const a = Object.assign(document.createElement('a'),
        {href: URL.createObjectURL(await res.blob()), download:'label.pdf'});
    a.click();
}
Hide flags (from Label Settings)
SettingEffect when enabled
hide_cust_nameRemoves consignee name
hide_cust_mobileRemoves consignee phone
hide_wh_nameRemoves warehouse name
hide_wh_addressRemoves warehouse address
hide_wh_mobileRemoves warehouse phone
hide_productRemoves product list
hide_skuRemoves SKU from products
hide_quantityRemoves quantity from products
hide_order_amountHides ₹ amount (COD/PREPAID still shown)
Error responses 4xx / 5xx
json
{ "success": false, "message": "Forbidden: one or more AWBs do not belong to your account" }
{ "success": false, "message": "No valid orders found for the provided AWB(s)" }
{ "success": false, "message": "Maximum 50 AWBs per request" }

Warehouse Management

Warehouses are your pickup and return destinations. Register new locations or list existing ones.

POST/add_warehouse
json
{
    "nickname": "Main Warehouse", "mobileNumber": "9000000001",
    "address1": "123 Logistics Road", "pincode": "110076",
    "city": "New Delhi", "state": "Delhi", "addressType": "primary"
}
GET/get_warehouses

Returns all active warehouses for the authenticated seller.

json — 200
{
    "success": true, "message": "Warehouses retrieved successfully",
    "data": [{ "id": 2147483833, "nickname": "Main Warehouse", "address1": "123 Logistics Road",
               "pincode": "110076", "city": "New Delhi", "state": "Delhi", "addressType": "primary" }]
}

Support

Reach the Shiplee technical team through any of these channels:

ChannelContact
Emailsupport@shiplee.app
WhatsApp+91 86453 22815
Dashboardapp.shiplee.ai