API Endpoints
Shipments
| Method |
Endpoint |
Description |
Auth Required |
| GET |
/api/v1/shipments |
List all shipments |
JWT |
| POST |
/api/v1/shipments |
Create shipment |
JWT |
| GET |
/api/v1/shipments/{id} |
Get shipment by ID |
JWT |
| PUT |
/api/v1/shipments/{id} |
Update shipment |
JWT |
| DELETE |
/api/v1/shipments/{id} |
Delete shipment |
JWT |
| GET |
/api/v1/shipments/{id}/packages |
Get shipment's packages |
JWT |
| POST |
/api/v1/shipments/{id}/packages |
Add package to shipment |
JWT |
| GET |
/api/v1/shipments/board |
Get shipments board (dashboard) |
JWT |
Create Shipment
POST /api/v1/shipments
Authorization: Bearer <token>
Content-Type: application/json
Request:
{
"sender_name": "Juan Pérez",
"sender_phone": "+34612345678",
"sender_address": "Calle Mayor 123, Madrid",
"recipient_name": "María García",
"recipient_phone": "+51123456789",
"recipient_address": "Av. Javier Prado 456, Lima",
"origin": "Madrid",
"destination": "Lima",
"description": "Ropa y regalos",
"weight": 15.5,
"price": 120.00,
"payment_status": "PENDING"
}
Response (201):
{
"id": "uuid",
"tracking_id": "TRK-A1B2C3D4",
"status": "RECEIVED",
"payment_status": "PENDING",
"tenant_id": "uuid",
"origin_company_id": "uuid",
...
}
Shipment Status Values
| Status |
Description |
RECEIVED |
Shipment received, awaiting processing |
PREPARING |
Packages being prepared |
IN_TRANSIT |
Packages assigned to bags/vuelos |
CONSOLIDATING |
Packages arriving at destination warehouse |
READY_FOR_PICKUP |
Ready for delivery |
DELIVERED |
Delivered to recipient |
RETURNED |
Returned to sender |
Packages
| Method |
Endpoint |
Description |
Auth Required |
| GET |
/api/v1/packages/{id} |
Get package by ID |
JWT |
| PUT |
/api/v1/packages/{id} |
Update package |
JWT |
| DELETE |
/api/v1/packages/{id} |
Delete package |
JWT |
| GET |
/api/v1/packages/{id}/events |
Get package events timeline |
JWT |
| POST |
/api/v1/packages/{id}/photo |
Upload package photo |
JWT |
Package Response
{
"id": "uuid",
"shipment_id": "uuid",
"qr_code": "PKG-839201",
"status": "ASSIGNED_TO_BAG",
"weight": 2.5,
"category": "general",
"bags": ["bag-uuid-1", "bag-uuid-2"],
"created_at": "2026-04-22T10:00:00Z"
}
Bags
| Method |
Endpoint |
Description |
Auth Required |
| GET |
/api/v1/bags |
List all bags |
JWT |
| POST |
/api/v1/bags |
Create bag |
JWT |
| GET |
/api/v1/bags/{id} |
Get bag by ID |
JWT |
| PUT |
/api/v1/bags/{id} |
Update bag |
JWT |
| DELETE |
/api/v1/bags/{id} |
Delete bag |
JWT |
| GET |
/api/v1/bags/{id}/packages |
Get bag's packages |
JWT |
| POST |
/api/v1/bags/{id}/packages/{package_id} |
Add package to bag |
JWT |
| DELETE |
/api/v1/bags/{id}/packages/{package_id} |
Remove package from bag |
JWT |
| POST |
/api/v1/bags/{id}/assign-courier |
Assign courier to bag |
JWT |
| PUT |
/api/v1/bags/{id}/seal |
Seal bag (close for additions) |
JWT |
| PUT |
/api/v1/bags/{id}/checkin |
Update with airline IATA code |
JWT |
Create Bag
POST /api/v1/bags
Authorization: Bearer <token>
Content-Type: application/json
Request:
{
"label": "BAG-MAD-001",
"origin": "MAD",
"destination": "LIM",
"warehouse_id": "uuid",
"courier_id": "uuid" // opcional, puede asignarse después
}
Response (201):
{
"id": "uuid",
"label": "BAG-MAD-001",
"status": "OPEN",
"courier_id": null,
"flight_id": null,
"airline_tag_code": null,
"total_packages": 0,
"total_weight_kg": 0,
"created_at": "2026-04-22T10:00:00Z"
}
Assign Courier to Bag
POST /api/v1/bags/{id}/assign-courier
Authorization: Bearer <token>
Content-Type: application/json
Request:
{
"courier_id": "uuid",
"flight_id": "uuid"
}
Response (200):
{
"id": "uuid",
"courier_id": "uuid",
"courier_name": "Juan Pérez",
"flight_id": "uuid",
"flight_number": "IB6251",
"status": "ASSIGNED"
}
Update Bag Check-in (Airline IATA Code)
PUT /api/v1/bags/{id}/checkin
Authorization: Bearer <token>
Content-Type: application/json
Request:
{
"airline_tag_code": "AMC1234567890",
"airline": "Iberia",
"flight_number": "IB6251"
}
Response (200):
{
"id": "uuid",
"status": "CHECKED_IN",
"airline_tag_code": "AMC1234567890",
"airline": "Iberia",
"flight_number": "IB6251"
}
Bag Status Values
| Status |
Description |
OPEN |
Bag is open, packages can be added |
SEALED |
Bag is sealed, no more packages |
CHECKED_IN |
Checked-in at airline, code assigned |
IN_TRANSIT |
On flight |
DELIVERED |
All packages delivered |
Couriers
| Method |
Endpoint |
Description |
Auth Required |
| GET |
/api/v1/couriers |
List all couriers |
JWT |
| POST |
/api/v1/couriers |
Create courier |
JWT |
| GET |
/api/v1/couriers/{id} |
Get courier by ID |
JWT |
| PUT |
/api/v1/couriers/{id} |
Update courier |
JWT |
| DELETE |
/api/v1/couriers/{id} |
Deactivate courier |
JWT |
| GET |
/api/v1/couriers/{id}/stats |
Get courier statistics |
JWT |
| GET |
/api/v1/couriers/{id}/bags |
Get courier's bags |
JWT |
| GET |
/api/v1/couriers/{id}/flights |
Get courier's flights |
JWT |
Create Courier
POST /api/v1/couriers
Authorization: Bearer <token>
Content-Type: application/json
Request:
{
"full_name": "Juan Pérez",
"passport_number": "AA1234567",
"nationality": "Peruana",
"phone": "+51123456789",
"email": "juan.perez@email.com",
"home_country": "PE",
"preferred_routes": ["MAD-LIM", "LIM-MAD"]
}
Response (201):
{
"id": "uuid",
"full_name": "Juan Pérez",
"passport_number": "AA1234567",
"nationality": "Peruana",
"phone": "+51123456789",
"email": "juan.perez@email.com",
"status": "ACTIVE",
"flights_completed": 0,
"packages_delivered": 0,
"rating": null,
"created_at": "2026-04-22T10:00:00Z"
}
Courier Stats
GET /api/v1/couriers/{id}/stats
Authorization: Bearer <token>
Response (200):
{
"courier_id": "uuid",
"flights_completed": 45,
"packages_delivered": 234,
"no_show_count": 2,
"rating": 4.8,
"causes": [
{"cause": "enfermedad", "count": 1},
{"cause": "emergencia", "count": 1}
]
}
Flights
| Method |
Endpoint |
Description |
Auth Required |
| GET |
/api/v1/flights |
List all flights |
JWT |
| POST |
/api/v1/flights |
Create flight |
JWT |
| GET |
/api/v1/flights/{id} |
Get flight by ID |
JWT |
| PUT |
/api/v1/flights/{id} |
Update flight |
JWT |
| DELETE |
/api/v1/flights/{id} |
Delete flight |
JWT |
| GET |
/api/v1/flights/search |
Search flights |
JWT |
| GET |
/api/v1/flights/{id}/status |
Get flight status |
JWT |
| POST |
/api/v1/flights/{id}/sync |
Sync flight data (AeroDataBox) |
JWT |
Create Flight
POST /api/v1/flights
Authorization: Bearer <token>
Content-Type: application/json
Request:
{
"flight_number": "IB6251",
"airline": "Iberia",
"departure_airport": "MAD",
"arrival_airport": "LIM",
"scheduled_departure": "2026-04-22T10:00:00Z",
"scheduled_arrival": "2026-04-22T19:30:00Z",
"courier_id": "uuid",
"max_weight_kg": 23
}
Response (201):
{
"id": "uuid",
"flight_number": "IB6251",
"airline": "Iberia",
"status": "SCHEDULED",
"departure_airport": "MAD",
"arrival_airport": "LIM",
"courier_id": "uuid",
"available_weight_kg": 23,
"bags_count": 0
}
Flight Status Values
| Status |
Description |
SCHEDULED |
Flight is scheduled |
BOARDING |
Boarding in progress |
DEPARTED |
Flight has departed |
ARRIVED |
Flight has arrived |
CANCELLED |
Flight was cancelled |
Scan Events
| Method |
Endpoint |
Description |
Auth Required |
| POST |
/api/v1/scan-event |
Register scan event |
JWT |
Register Scan Event
POST /api/v1/scan-event
Authorization: Bearer <token>
Content-Type: application/json
Request:
{
"qr_code": "PKG_839201",
"warehouse_id": "uuid",
"event_type": "PACKAGE_SCANNED",
"photo_url": "https://s3.../photo.jpg",
"evidence": {
"actor_id": "uuid",
"notes": "Paquete recibido en warehouse"
}
}
Response (200):
{
"event_id": "uuid",
"package_id": "uuid",
"event_type": "PACKAGE_SCANNED",
"timestamp": "2026-04-22T10:15:00Z",
"warehouse_current": "MAD-WH-01",
"next_actions": ["PRINT_LABEL", "ASSIGN_TO_BAG"]
}
Warehouse Events
| Method |
Endpoint |
Description |
Auth Required |
| POST |
/api/v1/warehouse/{id}/receive |
Receive package in warehouse |
JWT |
| POST |
/api/v1/warehouse/{id}/consolidate |
Trigger consolidation check |
JWT |
Receive Package (In-situ)
POST /api/v1/warehouse/{id}/receive
Authorization: Bearer <token>
Content-Type: application/json
Request:
{
"sender_name": "Juan Pérez",
"sender_phone": "+34612345678",
"recipient_name": "María García",
"recipient_phone": "+51123456789",
"description": "Electrónicos",
"weight": 1.5
}
Response (201):
{
"shipment_id": "uuid",
"tracking_id": "TRK-X1Y2Z3",
"package_id": "uuid",
"qr_code": "PKG-NEW001",
"status": "CREATED"
}
Tracking (Public)
| Method |
Endpoint |
Description |
Auth Required |
| GET |
/api/v1/track/{tracking_id} |
Track shipment (public) |
None (rate limited) |
Track Shipment
GET /api/v1/track/TRK-A1B2C3D4
Response (200):
{
"tracking_id": "TRK-A1B2C3D4",
"status": "IN_TRANSIT",
"origin": "Madrid (MAD)",
"destination": "Lima (LIM)",
"estimated_delivery": "2026-04-23",
"packages_count": 3,
"events": [
{
"timestamp": "2026-04-22T10:15:00Z",
"event_type": "PACKAGE_SCANNED",
"location": "MAD Warehouse",
"description": "Paquete escaneado"
},
{
"timestamp": "2026-04-22T14:00:00Z",
"event_type": "ASSIGNED_TO_BAG",
"location": "MAD Warehouse",
"description": "Paquete asignado a BAG-MAD-001"
},
{
"timestamp": "2026-04-22T16:00:00Z",
"event_type": "BAG_LOADED",
"location": "MAD Airport",
"description": "Maleta cargada al vuelo IB6251"
}
]
}
Response (404):
{
"error": "Tracking ID not found or expired",
"message": "Este tracking no existe o ha expirado"
}
Health Check
GET /
Response (200):
{
"status": "healthy",
"version": "1.0.0",
"timestamp": "2026-04-14T22:00:00.000000"
}