Quick start
Create your first shipment in three lines. Replace sk_live_... with your API key (find it in your dashboard under Settings → API).
curl https://api.lightspeedlgc.com/v1/shipments \
-H "Authorization: Bearer sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"from": { "name": "North & Pine", "address": "412 Alder St, Sacramento, CA" },
"to": { "name": "Casey Park", "address": "1820 Maple Ave, Sacramento, CA" },
"package": { "weight_oz": 24, "dims": "10x8x4" },
"service": "same_day"
}'
Successful requests return a 201 Created with the new shipment object:
{
"id": "shp_01HX9KJM3VQR8P2FZTBN7C4WSY",
"status": "queued",
"courier_eta": null,
"service": "same_day",
"created_at": "2026-04-21T18:42:15Z"
}
Authentication
All requests must include a bearer token in the Authorization header. Tokens come in two flavors:
sk_test_...— sandbox keys. No real shipments dispatched. Free to use.sk_live_...— production keys. Real packages, real money.
Never expose live keys in browser code. Use restricted keys (read-only or scoped) where possible.
Base URL
All endpoints sit under a single base URL. The API is versioned via path prefix.
https://api.lightspeedlgc.com/v1
Shipments
The core resource. Every package moving through the network is a shipment.
Shipment object
| Field | Type | Description |
|---|---|---|
| id | string | Unique identifier, prefixed shp_ |
| status | enum | queued, dispatched, in_transit, delivered, exception, cancelled |
| service | enum | same_day, next_day, standard |
| from | object | Pickup address & contact |
| to | object | Delivery address & contact |
| package | object | weight_oz, dims, optional fragile |
| tracking_url | string | Customer-facing tracking page |
| courier_eta | timestamp | ISO 8601, null until dispatched |
| created_at | timestamp | When the shipment was created |
Couriers
Read-only data about the drivers in our network. Useful for capacity planning or surfacing courier identity in your tracking pages.
Webhooks
Subscribe to delivery events instead of polling. We POST a JSON payload to your URL, sign it with HMAC-SHA256, and retry with exponential backoff on non-2xx responses.
Event types
| Event | When it fires |
|---|---|
| shipment.created | A shipment is created via API or dashboard |
| shipment.dispatched | Assigned to a courier |
| shipment.in_transit | Courier picked up the package |
| shipment.out_for_delivery | Courier is on the final leg |
| shipment.delivered | Proof-of-delivery captured |
| shipment.exception | Address issue, refused, damaged, etc. |
| shipment.cancelled | Cancelled before dispatch |
Example payload
{
"event": "shipment.delivered",
"id": "evt_01HX9KKZ4M5N6Q7R8S9T0U1V2W",
"created": 1745244135,
"data": {
"shipment_id": "shp_01HX9KJM3VQR8P2FZTBN7C4WSY",
"delivered_at": "2026-04-21T20:14:55Z",
"courier": { "id": "crr_5821", "name": "M. Tate" },
"proof_of_delivery": "https://cdn.lightspeedlgc.com/pod/shp_01HX9KJM3.jpg"
}
}
Errors
We use conventional HTTP status codes. Error responses always include a JSON body with error.code and error.message.
| Code | Status | Meaning |
|---|---|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource created |
| 400 | Bad Request | Invalid parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | Authenticated but not allowed |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Duplicate or state conflict |
| 429 | Too Many Requests | Rate limited — back off |
| 5xx | Server Error | Our problem. Safe to retry. |
Rate limits
Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix timestamp). Limits scale with your plan:
| Plan | Requests / hour | Concurrent webhooks |
|---|---|---|
| Sandbox | 500 | 2 |
| Starter | 1,000 | 4 |
| Growth | 5,000 | 16 |
| Scale | 50,000 | Unlimited |