API Reference
The public developer API is a shipment-focused, server-to-server surface. It deliberately excludes ShipPack's internal mobile, driver, wallet, admin, payment-provider, assignment, and pricing fields.
The OpenAPI 3.1 contract covers application-key credentials, shipment catalogs, shipments, sandbox simulation, and the signed outbound shipment webhook schema.
Base URL
Use the same base URL for sandbox and production. The application key prefix selects the environment.
https://dev.api.theshippack.com/api/v1/developerHow paths are shown
Endpoint lists below are gateway-relative and retain the /developer prefix to match the OpenAPI and Postman contracts. When a client is configured with the full developer base URL above, do not append /developer a second time.
| Environment | Key prefix | Purpose |
|---|---|---|
| Sandbox | sk_test_ | Simulated shipments and sandbox lifecycle webhooks |
| Production | sk_live_ | Approved operational shipments and production webhooks |
Authentication
Dashboard authentication
Account, application, key, and webhook management routes require a normal Sanctum user token and the developer app header.
Authorization: Bearer USER_ACCESS_TOKEN
X-App-Type: developerServer-to-server authentication
Catalog and shipment routes require an application secret key.
Authorization: Bearer sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxCredential properties
Secrets are shown once and stored as SHA-256 hashes with their prefix, environment, expiry, and revocation state. The limit is 120 requests per minute per credential.
OpenAPI Contract
The machine-readable source of truth is maintained at:
openapi/shippack-developer-api.jsonThe server-to-server contract contains these operations:
GET /developer/credentials
GET /developer/package-sizes
GET /developer/delivery-types
GET /developer/delivery-options
GET /developer/shipments
POST /developer/shipments
GET /developer/shipments/{shipmentId}
POST /developer/shipments/{shipmentId}/cancel
POST /developer/shipments/{shipmentId}/simulateContract boundary
Registration, dashboard, application and key management, webhook configuration, and production review are intentionally documented outside the secret-key SDK contract.
Dashboard Endpoints
All routes in this section require the user token and X-App-Type: developer.
Developer account
GET /developer/account
POST /developer/accountThe developer_accounts row is normally provisioned during verification. POST remains idempotent for compatibility and recovery and does not create a second account.
Applications and production access
GET /developer/applications
POST /developer/applications
GET /developer/applications/{applicationId}
PATCH /developer/applications/{applicationId}
DELETE /developer/applications/{applicationId}
POST /developer/applications/{applicationId}/production-accessProduction-access request
{
"reason": "We will create deliveries for paid ecommerce orders from our backend checkout workflow."
}API keys
GET /developer/applications/{applicationId}/api-keys
POST /developer/applications/{applicationId}/api-keys
DELETE /developer/applications/{applicationId}/api-keys/{apiKeyId}Create-key request
{
"name": "Backend sandbox key",
"environment": "sandbox",
"expiresAt": null
}Production Access Review
Developers submit the production-access request from their application. The following review endpoints are operator-only and cannot be called with developer credentials.
GET /admin/developer-applications?productionStatus=pending&perPage=20
PATCH /admin/developer-applications/{applicationId}/production-accessApproval body
{
"decision": "approved",
"note": "Business and integration use case verified."
}- decision is approved or rejected.
- Production keys require an approved application.
- Rejecting production access revokes active live keys.
Credential and Catalog Endpoints
GET /developer/credentials
GET /developer/package-sizes
GET /developer/delivery-types
GET /developer/delivery-options?origins=LAT,LNG&destinations=LAT,LNG- credentials returns the authenticated application and environment context.
- package-sizes provides valid packageSizeId values.
- delivery-types provides valid deliveryTypeId values.
- delivery-options evaluates options for the supplied origin and destination coordinates.
Shipment Endpoints
GET /developer/shipments?perPage=20
POST /developer/shipments
GET /developer/shipments/{shipmentId}
POST /developer/shipments/{shipmentId}/cancel
POST /developer/shipments/{shipmentId}/simulateApplication isolation
Every shipment is mapped to its creating application. One application cannot list or retrieve another application's shipments. Production callers also cannot choose an internal ShipPack user ID, and caller-supplied prices are discarded.
Create a Shipment
POST /developer/shipmentsRequest body
{
"pickup": "Lekki Phase 1, Lagos, Nigeria",
"pickupLat": 6.4488,
"pickupLng": 3.472,
"pickupCountry": "NG",
"dropoffCountry": "NG",
"destinationDetails": {
"dropoff": "Wuse 2, Abuja, Nigeria",
"dropoffLat": 9.0765,
"dropoffLng": 7.4983,
"recipient": {
"name": "Adebayo Test",
"phoneNumber": "+2348012345678"
}
},
"shipmentMode": "LAND",
"shipperMode": "AUTO",
"packageSizeId": "PACKAGE_SIZE_ID",
"deliveryTypeId": "DELIVERY_TYPE_ID",
"packageDescription": "Documents and clothes",
"attachments": [],
"submit": false
}- Set submit to false to save without payment submission.
- The production MVP accepts paymentMethod: wallet when submit is true.
- Sandbox references begin with SPTEST and tracking IDs begin with TRKTEST.
Sandbox Simulation
The simulate operation is sandbox-only and must follow the public lifecycle order.
POST /developer/shipments/{shipmentId}/simulateRequest body
{
"status": "ASSIGNED"
}Valid sequence
PENDING → ASSIGNED → PICKED_UP → IN_TRANSIT → OUT_FOR_DELIVERY → DELIVEREDAny non-terminal status may transition to FAILED.
Webhook Management
Webhook configuration belongs to an application and uses dashboard authentication.
GET /developer/applications/{applicationId}/webhooks
POST /developer/applications/{applicationId}/webhooks
PATCH /developer/applications/{applicationId}/webhooks/{webhookId}
DELETE /developer/applications/{applicationId}/webhooks/{webhookId}
POST /developer/applications/{applicationId}/webhooks/{webhookId}/rotate-secret
POST /developer/applications/{applicationId}/webhooks/{webhookId}/test
GET /developer/applications/{applicationId}/webhooks/{webhookId}/deliveries
POST /developer/applications/{applicationId}/webhooks/{webhookId}/deliveries/{deliveryId}/retryCreate-webhook request
{
"environment": "sandbox",
"url": "https://example.com/webhooks/shippack",
"description": "Shipment lifecycle handler",
"events": [
"shipment.created",
"shipment.assigned",
"shipment.picked_up",
"shipment.in_transit",
"shipment.out_for_delivery",
"shipment.delivered",
"shipment.cancelled",
"shipment.failed"
]
}HTTPS and DNS validation
Webhook URLs cannot target localhost, private, reserved, or locally resolving addresses. DNS is checked again immediately before every delivery.
Webhook Payload and Signature
Example payload
{
"id": "45be8cee-4382-4bad-9336-bca329ed0c77",
"type": "shipment.delivered",
"createdAt": "2026-08-17T11:30:00Z",
"data": {
"id": "developer-shipment-id",
"reference": "SP123456789",
"trackingId": "TRACK123",
"status": "DELIVERED"
}
}Delivery headers
X-ShipPack-Event: shipment.delivered
X-ShipPack-Delivery: DELIVERY_UUID
X-ShipPack-Timestamp: 1786966200
X-ShipPack-Signature: sha256=HEX_HMACThe signed value is TIMESTAMP.RAW_REQUEST_BODY.
Node.js verification
import crypto from "node:crypto";
const signed = timestamp + "." + rawBody;
const expected = "sha256=" + crypto
.createHmac("sha256", webhookSecret)
.update(signed)
.digest("hex");
const valid = crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(receivedSignature)
);- Reject timestamps outside a five-minute tolerance.
- Return an HTTP 2xx response quickly, then process asynchronously.
- Deduplicate with payload id or X-ShipPack-Delivery.
- High-frequency location events are not forwarded in the MVP.
Webhook Delivery Retries
A delivery is marked failed after five unsuccessful attempts.
| Attempt | Delay |
|---|---|
| Initial attempt | Immediately |
| Retry 1 | 30 seconds |
| Retry 2 | 2 minutes |
| Retry 3 | 10 minutes |
| Retry 4 | 30 minutes |
Delivery logs expose status, the HTTP response, a truncated response body, and the last error. A non-delivered attempt can be retried manually.
Production Webhook Flow
- shipment-service publishes a shipment lifecycle event.
- notification-service performs normal notification work and forwards the protected shipment envelope.
- user-service resolves the operational shipment mapping to its developer application.
- The internal status is normalized into the public developer event name.
- One idempotent delivery record is created per matching endpoint and event ID.
- The user-service queue signs and delivers each callback.
Location-event boundary
High-frequency location events are deliberately not forwarded to developer webhooks in the MVP.
Pagination and Rate Limits
- Use perPage on shipment collection requests; the documented example is perPage=20.
- Each application credential is limited to 120 requests per minute.
- The TypeScript SDK performs bounded retries only for eligible GET requests.