Shippea Partner API Documentation
Full REST API for SaaS partners and custom integrations: bearer-token authentication, wallet-based shipment payments, service lookup, tracking, label retrieval, cancellation, and webhook configuration.
Overview
Shippea Partner API
Full REST API for SaaS partners and custom integrations. Bearer-token authentication via client credentials, wallet-based shipment payments, and complete shipment lifecycle management — from service lookup to tracking and cancellation.
If you are building a Shopify app, use the Shopify Integration API v1 instead — it uses app-key authentication and a Shopify-native data model.
Authentication
Bearer token via client credentials
Content Type
application/json
Production
https://app.shippea.io/api/v2/partner
Sandbox
https://sandbox.shippea.io/api/v2/partner
Authentication
/api/v2/partner/auth/token
Use your client_id and client_secret to obtain a Bearer token. Include this token in all subsequent requests via the Authorization header. Tokens do not expire automatically — re-authenticate if you receive a 401 response.
Request
{
"client_id": "your_client_id",
"client_secret": "your_client_secret"
}Response (200)
{
"success": true,
"token_type": "Bearer",
"access_token": "1|...",
"message": "Access token generated successfully."
}cURL Example
curl --request POST '{BASE_URL}/auth/token' \
--header 'Content-Type: application/json' \
--data '{
"client_id": "your_client_id",
"client_secret": "your_client_secret"
}'Master Data
/api/v2/partner/regions
Returns all active regions available for service coverage. Use the region id when querying services.
Request
GET {BASE_URL}/regionsResponse (200)
{
"success": true,
"data": [
{"id": 1, "name": "Panamá", "iso_code": "PA-8"}
]
}cURL Example
curl --request GET '{BASE_URL}/regions' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'Services & Prices
/api/v2/partner/services
Returns available services and prices for a given region. Filter by weight to see only services that accept the parcel.
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
region_id | integer | REQUIRED | Region ID from the List Regions endpoint. |
origin_region_id | integer | REQUIRED | Sender's origin region ID from the List Regions endpoint. Regional couriers that do not cover this origin are excluded. |
weight | float | OPTIONAL | Weight in pounds. When provided, only services whose weight range covers this value are returned. |
sender_lat | float | OPTIONAL | Latitude of sender's pickup address. Required for ASAP/dynamic courier pricing. |
sender_long | float | OPTIONAL | Longitude of sender's pickup address. Required for ASAP/dynamic courier pricing. |
receiver_lat | float | OPTIONAL | Latitude of receiver's delivery address. Required for ASAP/dynamic courier pricing. |
receiver_long | float | OPTIONAL | Longitude of receiver's delivery address. Required for ASAP/dynamic courier pricing. |
Request
GET {BASE_URL}/services?region_id=1&origin_region_id=2&weight=2.5Response (200)
{
"success": true,
"data": [
{
"id": 12,
"rate_name": "Door-to-Door",
"rate_type": "Door-to-Door",
"min_weight": 0.0,
"max_weight": 5.0,
"price": 4.99,
"return_charge": 0.0,
"weight_unit": "lb",
"courier": {
"id": 3,
"name": "Shippea Express",
"logo_url": "https://..."
},
"agency": {
"id": 2,
"name": "Agency Name",
"region_id": 1
}
}
]
}cURL Example
curl --request GET '{BASE_URL}/services?region_id=1&origin_region_id=2&weight=2.5' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'Customers
/api/v2/partner/customers
Creates a customer account for shipment ownership. If the email already exists, returns the existing customer information — no duplicate is created.
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
first_name | string | REQUIRED | Customer first name. |
last_name | string | REQUIRED | Customer last name. |
email | string | REQUIRED | Email address. Used as unique identifier — returns existing record if already registered. |
phone | string | REQUIRED | International format phone number. |
password | string | OPTIONAL | Password for direct portal login. If omitted, the customer cannot log in directly. |
Example request body
{
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+50760000000",
"password": "optionalStrongPassword"
}Response (201)
{
"success": true,
"message": "Customer account created successfully.",
"data": {
"customer_uuid": "...",
"email": "john@example.com"
}
}cURL Example
curl --request POST '{BASE_URL}/customers' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+50760000000",
"password": "optionalStrongPassword"
}'Shipments
Shipment Lifecycle
Shippea supports listing, creation, payment, tracking, label retrieval, and cancellation. In the standard flow, shipment creation debits the wallet immediately and queues label generation asynchronously.
/api/v2/partner/shipments
Returns a paginated list of all shipments for the authenticated partner account. Results are sorted newest first.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
status | string | OPTIONAL | Filter by shipment status, for example: label_created, in_transit, delivered, cancelled. |
order_number | string | OPTIONAL | Filter by your internal order reference number. |
from_date | date | OPTIONAL | Earliest creation date to include. Format: Y-m-d. |
to_date | date | OPTIONAL | Latest creation date to include. Format: Y-m-d. |
per_page | integer | OPTIONAL | Results per page. Default: 20. Maximum: 100. |
Request
GET {BASE_URL}/shipments?status=label_created&per_page=20Response (200)
{
"success": true,
"data": [
{
"shipment_id": 991,
"tracking_number": "4001234",
"order_number": "ORDER-1001",
"status": "label_created",
"is_paid": true,
"total_price": 4.99,
"currency": "USD",
"label_url": "https://...",
"created_at": "2026-06-12 10:00:00"
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"total": 145,
"last_page": 8
}
}cURL Example
curl --request GET '{BASE_URL}/shipments?per_page=20' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'/api/v2/partner/shipments
Creates a shipment, debits the wallet automatically, and queues async label generation. Total weight and final price are calculated server-side. Accepts either service_id or service_name.
label_created status with is_paid: true. The label is generated asynchronously — poll GET /shipments/{tracking}/label until it is ready.order_number twice, the original shipment is returned and no duplicate is created.Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
service_id | integer | OPTIONAL | ID of the service from List Services. Provide either this or service_name. |
service_name | string | OPTIONAL | Exact service name. Alternative to service_id. |
order_number | string | OPTIONAL | Your internal order reference, stored against the shipment. |
customer | object | REQUIRED | Customer info: name, email, phone. |
sender_details | object | REQUIRED | Pickup/sender info. See Sender Object below. |
receiver_details | object | REQUIRED | Delivery/receiver info. |
items_information | array | REQUIRED | Array of item objects. See Item Object below. |
Sender Object
| Field | Type | Required | Description |
|---|---|---|---|
name | string | REQUIRED | Sender full name or business name. |
address | string | REQUIRED | Full street address. |
city | string | REQUIRED | City name. |
country | string | REQUIRED | Country name. |
province_code | string | REQUIRED | ISO province code. Used to resolve region. |
zip | string | REQUIRED | Postal code. |
phone | string | REQUIRED | Contact phone number. |
latitude | float | OPTIONAL | GPS coordinates for pickup mapping. Lat. |
longitude | float | OPTIONAL | GPS coordinates for pickup mapping. Long. |
Item Object
| Field | Type | Required | Description |
|---|---|---|---|
title | string | REQUIRED | Item name / product title. |
sku | string | OPTIONAL | Stock-keeping unit identifier. |
quantity | integer | REQUIRED | Number of units. |
weight | float | REQUIRED | Weight per unit in pounds. |
length | float | OPTIONAL | Package dimensions in inches. Length. |
width | float | OPTIONAL | Package dimensions in inches. Width. |
height | float | OPTIONAL | Package dimensions in inches. Height. |
package_type | string | OPTIONAL | Packaging type. |
declared_value | float | OPTIONAL | Declared value for insurance purposes. |
Example request body
{
"order_number": "ORDER-1001",
"service_name": "Door-to-Door",
"customer": {
"name": "John Doe",
"email": "john@example.com",
"phone": "+50760000000"
},
"sender_details": {
"name": "My Store",
"email": "store@example.com",
"address": "Sender Street 45",
"city": "Panamá",
"country": "Panama",
"province_code": "PA-8",
"zip": "0801",
"phone": "+50761110000",
"latitude": 8.9824,
"longitude": -79.5199
},
"receiver_details": {
"name": "John Doe",
"email": "john@example.com",
"address": "Street 123",
"city": "Panamá",
"country": "Panama",
"province_code": "PA-8",
"zip": "0801",
"phone": "+50760000000",
"latitude": 8.9943,
"longitude": -79.5188
},
"items_information": [
{
"title": "Shoes",
"sku": "SHOE-001",
"quantity": 1,
"weight": 1.2,
"length": 12,
"width": 8,
"height": 5,
"package_type": "Box",
"declared_value": 35
}
]
}Response (201)
{
"success": true,
"message": "Shipment created and payment processed. Label generation has been queued.",
"data": {
"shipment_id": 991,
"tracking_number": "4001234",
"status": "label_created",
"is_paid": true,
"payment_method": "shippea_wallet",
"total_price": 4.99,
"currency": "USD",
"wallet_balance": 195.01,
"service": {
"id": 12,
"name": "Door-to-Door",
"type": "Door-to-Door"
},
"calculation": {
"total_items": 1,
"total_weight": 1.2,
"total_declared_value": 35,
"base_price": 4.99,
"return_fee": 0,
"final_price": 4.99
},
"items": [
{
"id": 1,
"title": "Shoes",
"sku": "SHOE-001",
"quantity": 1,
"weight": 1.2
}
]
}
}cURL Example
curl --request POST '{BASE_URL}/shipments' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"order_number": "ORDER-1001",
"service_name": "Door-to-Door",
"sender_details": {
"name": "My Store",
"address": "Sender Street 45",
"city": "Panamá",
"country": "Panama",
"province_code": "PA-8",
"latitude": 8.9824,
"longitude": -79.5199
},
"receiver_details": {
"address": "Street 123",
"city": "Panamá",
"country": "Panama",
"province_code": "PA-8",
"latitude": 8.9943,
"longitude": -79.5188
},
"items_information": [{"title":"Shoes","quantity":1,"weight":1.2}]
}'/api/v2/partner/shipments/{trackingNumber}/pay
Debits the wallet and queues async label generation for a shipment currently in PENDING_PAYMENT status. Only applicable to shipments that were not auto-paid at creation.
In the standard flow, payment is auto-debited at creation. This endpoint is only needed for shipments that are explicitly in PENDING_PAYMENT status.
Request
POST {BASE_URL}/shipments/4001234/payResponse (200)
{
"success": true,
"message": "Payment successful. Label generation has been queued.",
"data": {
"tracking_number": "4001234",
"status": "label_created",
"transaction_id": "TXN-...",
"amount_charged": 4.99,
"currency": "USD"
}
}cURL Example
curl --request POST '{BASE_URL}/shipments/4001234/pay' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'/api/v2/partner/shipments/{trackingNumber}
Fetch shipment status and full details using the tracking number returned on creation.
Request
GET {BASE_URL}/shipments/4001234Response (200)
{
"success": true,
"data": {
"tracking_number": "4001234",
"order_number": "ORDER-1001",
"status": "in_transit",
"is_paid": true
}
}cURL Example
curl --request GET '{BASE_URL}/shipments/4001234' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'/api/v2/partner/shipments/{trackingNumber}/label
Returns the label URL for a shipment. Label generation is asynchronous — poll this endpoint after creation until a URL is returned.
If the shipment is still in PENDING_PAYMENT status, a 402 response is returned indicating payment is required first.
Request
GET {BASE_URL}/shipments/4001234/labelResponse (200)
{
"success": true,
"data": {
"tracking_number": "4001234",
"label_url": "https://.../label.pdf",
"combined_url": "https://.../combined.pdf"
}
}cURL Example
curl --request GET '{BASE_URL}/shipments/4001234/label' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'/api/v2/partner/shipments/{trackingNumber}
Cancels a shipment when its current status allows cancellation. Returns an error if the shipment is already dispatched or delivered.
Request
DELETE {BASE_URL}/shipments/4001234Response (200)
{
"success": true,
"message": "Shipment cancelled successfully."
}cURL Example
curl --request DELETE '{BASE_URL}/shipments/4001234' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'Account & Wallet
/api/v2/partner/account
Returns the authenticated partner account profile, wallet summary, and API client details.
Request
GET {BASE_URL}/accountResponse (200)
{
"success": true,
"data": {
"account": {
"name": "My Company",
"email": "partner@example.com",
"phone": "+50760000000",
"status": "active"
},
"wallet": {
"balance": 195.01,
"currency": "USD",
"is_active": true
},
"api_client": {
"name": "My Integration",
"client_id": "clnt_abc123",
"webhook_url": "https://myapp.com/webhooks",
"last_used_at": "2026-06-12 10:00:00"
}
}
}cURL Example
curl --request GET '{BASE_URL}/account' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'Wallet
/api/v2/partner/wallet
Returns the current wallet balance, currency, and the last 20 transactions.
Request
GET {BASE_URL}/walletResponse (200)
{
"success": true,
"data": {
"balance": 195.01,
"currency": "USD",
"is_active": true,
"transactions": [
{
"type": "debit",
"amount": 4.99,
"balance": 195.01,
"reason": "Shipment payment - 4001234",
"reference": "SHIPMENT-4001234",
"date": "2026-06-12 10:00:00"
}
]
}
}cURL Example
curl --request GET '{BASE_URL}/wallet' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'Webhook
Webhook Configuration
Register a webhook URL for shipment event notifications. Verify inbound payloads by computing HMAC-SHA256(webhook_secret, raw_body) and comparing it with the X-Shippea-Signature header.
/api/v2/partner/webhook
Returns the webhook URL and secret currently registered for this API client.
Request
GET {BASE_URL}/webhookResponse (200)
{
"success": true,
"data": {
"webhook_url": "https://myapp.com/webhooks",
"webhook_secret": "shp_secret_abc..."
}
}/api/v2/partner/webhook
Registers or updates the webhook URL. A webhook_secret is auto-generated on first registration — store it securely to verify incoming payloads.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
webhook_url | string | REQUIRED | Full HTTPS URL of your endpoint to receive webhook event notifications. |
Example request body
{
"webhook_url": "https://myapp.com/webhooks/shippea"
}Response (200)
{
"success": true,
"message": "Webhook URL registered successfully.",
"data": {
"webhook_url": "https://myapp.com/webhooks/shippea",
"webhook_secret": "shp_secret_abc..."
}
}HMAC-SHA256(webhook_secret, raw_body) and comparing to the X-Shippea-Signature header./api/v2/partner/webhook
Removes the registered webhook URL. No further events will be dispatched to the old URL.
Request
DELETE {BASE_URL}/webhookResponse (200)
{
"success": true,
"message": "Webhook URL removed successfully."
}Authentication
/api/v2/partner/auth/logout
Revokes the current access token. Subsequent requests with this token return 401.
Only the token used for this request is revoked. Other active tokens for the same client are unaffected.
Request
POST {BASE_URL}/auth/logoutResponse (200)
{
"success": true,
"message": "Token revoked successfully."
}cURL Example
curl --request POST '{BASE_URL}/auth/logout' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Accept: application/json'Reference
Regions Reference
Panama region IDs and ISO codes to use with the region_id and origin_region_id query parameters on the /services endpoint, and the province_code fields in shipment creation. Use the /regions endpoint to retrieve live IDs.
GET /regions endpoint — IDs may differ between production and sandbox.| Region ID | Province Name | ISO Province Code | Usage |
|---|---|---|---|
1 | Bocas del Toro | PA-1 | region_id=1, province_code="PA-1" |
2 | Coclé | PA-2 | region_id=2, province_code="PA-2" |
3 | Colón | PA-3 | region_id=3, province_code="PA-3" |
4 | Chiriquí | PA-4 | region_id=4, province_code="PA-4" |
5 | Darién | PA-5 | region_id=5, province_code="PA-5" |
6 | Herrera | PA-6 | region_id=6, province_code="PA-6" |
7 | Los Santos | PA-7 | region_id=7, province_code="PA-7" |
8 | Panamá | PA-8 | region_id=8, province_code="PA-8" |
9 | Veraguas | PA-9 | region_id=9, province_code="PA-9" |
10 | Kuna Yala (Guna Yala) | PA-KY | region_id=10, province_code="PA-KY" |
11 | Panamá Oeste | PA-10 | region_id=11, province_code="PA-10" |
Reference
Error Codes
All errors return success: false and a human-readable message. The HTTP status code indicates the error category.
| HTTP | Error Code | Description |
|---|---|---|
422 | VALIDATION_ERROR | Missing or invalid fields. |
401 | UNAUTHORIZED | Invalid or expired Bearer token. |
403 | AUTH_INACTIVE_ACCOUNT | Account or wallet is inactive. |
422 | SERVICE_NOT_FOUND | The specified service name or ID does not match any active service. |
400 | INSUFFICIENT_WALLET_BALANCE | Wallet balance is below the service cost. |
404 | SHIPMENT_NOT_FOUND | No shipment matches the tracking number. |
400 | CANNOT_CANCEL | Shipment is past the cancellable state — already dispatched or delivered. |
404 | LABEL_NOT_READY | Label has not been generated yet. Retry after a few seconds. |
402 | PAYMENT_REQUIRED | Shipment is awaiting payment before the label can be issued. |
Resources
Postman Collection
Download the Postman collection to get all v2 endpoints pre-configured with automated token-save test scripts.
📮Partner API – Postman CollectionAfter importing, set thebase_url variable and fill in client_id and client_secret. The Auth token request auto-saves the token to a collection variable.-5.png)