# Carrier Portal API Documentation **Version**: 1.0 **Base URL**: `http://localhost:4000/api/v1` **Last Updated**: 2025-12-04 ## Table of Contents 1. [Overview](#overview) 2. [Authentication](#authentication) 3. [API Endpoints](#api-endpoints) - [Carrier Authentication](#carrier-authentication) - [Carrier Dashboard](#carrier-dashboard) - [Booking Management](#booking-management) - [Document Management](#document-management) 4. [Data Models](#data-models) 5. [Error Handling](#error-handling) 6. [Examples](#examples) --- ## Overview The Carrier Portal API provides endpoints for transportation carriers (transporteurs) to: - Authenticate and manage their accounts - View dashboard statistics - Manage booking requests from clients - Accept or reject booking requests - Download shipment documents - Track their performance metrics All endpoints require JWT authentication except for the public authentication endpoints. --- ## Authentication ### Authentication Header All protected endpoints require a Bearer token in the Authorization header: ``` Authorization: Bearer ``` ### Token Management - **Access Token**: Valid for 15 minutes - **Refresh Token**: Valid for 7 days - **Auto-Login Token**: Valid for 1 hour (for magic link authentication) --- ## API Endpoints ### Carrier Authentication #### 1. Login **Endpoint**: `POST /carrier-auth/login` **Description**: Authenticate a carrier with email and password. **Request Body**: ```json { "email": "carrier@example.com", "password": "SecurePassword123!" } ``` **Response** (200 OK): ```json { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "carrier": { "id": "carrier-uuid", "companyName": "Transport Express", "email": "carrier@example.com" } } ``` **Errors**: - `401 Unauthorized`: Invalid credentials - `401 Unauthorized`: Account is inactive - `400 Bad Request`: Validation error --- #### 2. Get Current Carrier Profile **Endpoint**: `GET /carrier-auth/me` **Description**: Retrieve the authenticated carrier's profile information. **Headers**: ``` Authorization: Bearer ``` **Response** (200 OK): ```json { "id": "carrier-uuid", "userId": "user-uuid", "companyName": "Transport Express", "email": "carrier@example.com", "role": "CARRIER", "organizationId": "org-uuid", "phone": "+33612345678", "website": "https://transport-express.com", "city": "Paris", "country": "France", "isVerified": true, "isActive": true, "totalBookingsAccepted": 45, "totalBookingsRejected": 5, "acceptanceRate": 90.0, "totalRevenueUsd": 125000, "totalRevenueEur": 112500, "preferredCurrency": "EUR", "lastLoginAt": "2025-12-04T10:30:00Z" } ``` **Errors**: - `401 Unauthorized`: Invalid or expired token --- #### 3. Change Password **Endpoint**: `PATCH /carrier-auth/change-password` **Description**: Change the carrier's password. **Headers**: ``` Authorization: Bearer ``` **Request Body**: ```json { "oldPassword": "OldPassword123!", "newPassword": "NewPassword123!" } ``` **Response** (200 OK): ```json { "message": "Password changed successfully" } ``` **Errors**: - `401 Unauthorized`: Invalid old password - `400 Bad Request`: Password validation failed --- #### 4. Request Password Reset **Endpoint**: `POST /carrier-auth/request-password-reset` **Description**: Request a password reset (generates temporary password). **Request Body**: ```json { "email": "carrier@example.com" } ``` **Response** (200 OK): ```json { "message": "If this email exists, a password reset will be sent" } ``` **Note**: For security, the response is the same whether the email exists or not. --- #### 5. Verify Auto-Login Token **Endpoint**: `POST /carrier-auth/verify-auto-login` **Description**: Verify an auto-login token from email magic link. **Request Body**: ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` **Response** (200 OK): ```json { "userId": "user-uuid", "carrierId": "carrier-uuid" } ``` **Errors**: - `401 Unauthorized`: Invalid or expired token --- ### Carrier Dashboard #### 6. Get Dashboard Statistics **Endpoint**: `GET /carrier-dashboard/stats` **Description**: Retrieve carrier dashboard statistics including bookings count, revenue, and recent activities. **Headers**: ``` Authorization: Bearer ``` **Response** (200 OK): ```json { "totalBookings": 50, "pendingBookings": 5, "acceptedBookings": 42, "rejectedBookings": 3, "acceptanceRate": 93.3, "totalRevenue": { "usd": 125000, "eur": 112500 }, "recentActivities": [ { "id": "activity-uuid", "type": "BOOKING_ACCEPTED", "description": "Booking #12345 accepted", "createdAt": "2025-12-04T09:15:00Z", "bookingId": "booking-uuid" }, { "id": "activity-uuid-2", "type": "DOCUMENT_DOWNLOADED", "description": "Downloaded invoice.pdf", "createdAt": "2025-12-04T08:30:00Z", "bookingId": "booking-uuid-2" } ] } ``` **Errors**: - `401 Unauthorized`: Invalid or expired token - `404 Not Found`: Carrier not found --- #### 7. Get Carrier Bookings (Paginated) **Endpoint**: `GET /carrier-dashboard/bookings` **Description**: Retrieve a paginated list of bookings for the carrier. **Headers**: ``` Authorization: Bearer ``` **Query Parameters**: - `page` (number, optional): Page number (default: 1) - `limit` (number, optional): Items per page (default: 10) - `status` (string, optional): Filter by status (PENDING, ACCEPTED, REJECTED) **Example Request**: ``` GET /carrier-dashboard/bookings?page=1&limit=10&status=PENDING ``` **Response** (200 OK): ```json { "data": [ { "id": "booking-uuid", "origin": "Rotterdam", "destination": "New York", "status": "PENDING", "priceUsd": 1500, "priceEur": 1350, "primaryCurrency": "USD", "requestedAt": "2025-12-04T08:00:00Z", "carrierViewedAt": null, "documentsCount": 3, "volumeCBM": 25.5, "weightKG": 12000, "palletCount": 10, "transitDays": 15, "containerType": "40HC" } ], "total": 50, "page": 1, "limit": 10 } ``` **Errors**: - `401 Unauthorized`: Invalid or expired token - `404 Not Found`: Carrier not found --- #### 8. Get Booking Details **Endpoint**: `GET /carrier-dashboard/bookings/:id` **Description**: Retrieve detailed information about a specific booking. **Headers**: ``` Authorization: Bearer ``` **Path Parameters**: - `id` (string, required): Booking ID **Response** (200 OK): ```json { "id": "booking-uuid", "carrierName": "Transport Express", "carrierEmail": "carrier@example.com", "origin": "Rotterdam", "destination": "New York", "volumeCBM": 25.5, "weightKG": 12000, "palletCount": 10, "priceUSD": 1500, "priceEUR": 1350, "primaryCurrency": "USD", "transitDays": 15, "containerType": "40HC", "status": "PENDING", "documents": [ { "id": "doc-uuid", "fileName": "invoice.pdf", "type": "INVOICE", "url": "https://storage.example.com/doc.pdf", "uploadedAt": "2025-12-03T10:00:00Z" } ], "confirmationToken": "token-123", "requestedAt": "2025-12-04T08:00:00Z", "respondedAt": null, "notes": "Urgent shipment", "rejectionReason": null, "carrierViewedAt": "2025-12-04T10:15:00Z", "carrierAcceptedAt": null, "carrierRejectedAt": null, "carrierRejectionReason": null, "carrierNotes": null, "createdAt": "2025-12-04T08:00:00Z", "updatedAt": "2025-12-04T10:15:00Z" } ``` **Errors**: - `401 Unauthorized`: Invalid or expired token - `403 Forbidden`: Access denied to this booking - `404 Not Found`: Booking not found --- ### Booking Management #### 9. Accept Booking **Endpoint**: `POST /carrier-dashboard/bookings/:id/accept` **Description**: Accept a booking request. **Headers**: ``` Authorization: Bearer ``` **Path Parameters**: - `id` (string, required): Booking ID **Request Body**: ```json { "notes": "Ready to proceed. Pickup scheduled for Dec 5th." } ``` **Response** (200 OK): ```json { "message": "Booking accepted successfully" } ``` **Errors**: - `401 Unauthorized`: Invalid or expired token - `403 Forbidden`: Access denied to this booking - `404 Not Found`: Booking not found - `400 Bad Request`: Booking cannot be accepted (wrong status) --- #### 10. Reject Booking **Endpoint**: `POST /carrier-dashboard/bookings/:id/reject` **Description**: Reject a booking request with a reason. **Headers**: ``` Authorization: Bearer ``` **Path Parameters**: - `id` (string, required): Booking ID **Request Body**: ```json { "reason": "CAPACITY_NOT_AVAILABLE", "notes": "Sorry, we don't have capacity for this shipment at the moment." } ``` **Response** (200 OK): ```json { "message": "Booking rejected successfully" } ``` **Errors**: - `401 Unauthorized`: Invalid or expired token - `403 Forbidden`: Access denied to this booking - `404 Not Found`: Booking not found - `400 Bad Request`: Rejection reason required - `400 Bad Request`: Booking cannot be rejected (wrong status) --- ### Document Management #### 11. Download Document **Endpoint**: `GET /carrier-dashboard/bookings/:bookingId/documents/:documentId/download` **Description**: Download a document associated with a booking. **Headers**: ``` Authorization: Bearer ``` **Path Parameters**: - `bookingId` (string, required): Booking ID - `documentId` (string, required): Document ID **Response** (200 OK): ```json { "document": { "id": "doc-uuid", "fileName": "invoice.pdf", "type": "INVOICE", "url": "https://storage.example.com/doc.pdf", "size": 245678, "mimeType": "application/pdf", "uploadedAt": "2025-12-03T10:00:00Z" } } ``` **Errors**: - `401 Unauthorized`: Invalid or expired token - `403 Forbidden`: Access denied to this document - `404 Not Found`: Document or booking not found --- ## Data Models ### Carrier Profile ```typescript interface CarrierProfile { id: string; userId: string; organizationId: string; companyName: string; email: string; phone?: string; website?: string; city?: string; country?: string; isVerified: boolean; isActive: boolean; totalBookingsAccepted: number; totalBookingsRejected: number; acceptanceRate: number; totalRevenueUsd: number; totalRevenueEur: number; preferredCurrency: 'USD' | 'EUR'; lastLoginAt?: Date; } ``` ### Booking ```typescript interface Booking { id: string; carrierId: string; carrierName: string; carrierEmail: string; origin: string; destination: string; volumeCBM: number; weightKG: number; palletCount: number; priceUSD: number; priceEUR: number; primaryCurrency: 'USD' | 'EUR'; transitDays: number; containerType: string; status: 'PENDING' | 'ACCEPTED' | 'REJECTED' | 'CANCELLED'; documents: Document[]; confirmationToken: string; requestedAt: Date; respondedAt?: Date; notes?: string; rejectionReason?: string; carrierViewedAt?: Date; carrierAcceptedAt?: Date; carrierRejectedAt?: Date; carrierRejectionReason?: string; carrierNotes?: string; createdAt: Date; updatedAt: Date; } ``` ### Document ```typescript interface Document { id: string; fileName: string; type: 'INVOICE' | 'PACKING_LIST' | 'CERTIFICATE' | 'OTHER'; url: string; size?: number; mimeType?: string; uploadedAt: Date; } ``` ### Activity ```typescript interface CarrierActivity { id: string; carrierId: string; bookingId?: string; activityType: 'BOOKING_ACCEPTED' | 'BOOKING_REJECTED' | 'DOCUMENT_DOWNLOADED' | 'PROFILE_UPDATED'; description: string; metadata?: Record; createdAt: Date; } ``` --- ## Error Handling ### Error Response Format All error responses follow this structure: ```json { "statusCode": 400, "message": "Validation failed", "error": "Bad Request", "timestamp": "2025-12-04T10:30:00Z", "path": "/api/v1/carrier-auth/login" } ``` ### Common HTTP Status Codes - `200 OK`: Request successful - `201 Created`: Resource created successfully - `400 Bad Request`: Validation error or invalid request - `401 Unauthorized`: Authentication required or invalid credentials - `403 Forbidden`: Insufficient permissions - `404 Not Found`: Resource not found - `500 Internal Server Error`: Server error --- ## Examples ### Complete Authentication Flow ```bash # 1. Login curl -X POST http://localhost:4000/api/v1/carrier-auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "carrier@example.com", "password": "SecurePassword123!" }' # Response: # { # "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", # "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", # "carrier": { "id": "carrier-uuid", ... } # } # 2. Get Dashboard Stats curl -X GET http://localhost:4000/api/v1/carrier-dashboard/stats \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." # 3. Get Pending Bookings curl -X GET "http://localhost:4000/api/v1/carrier-dashboard/bookings?status=PENDING&page=1&limit=10" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." # 4. Accept a Booking curl -X POST http://localhost:4000/api/v1/carrier-dashboard/bookings/booking-uuid/accept \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "notes": "Ready to proceed with shipment" }' ``` ### Using Auto-Login Token ```bash # Verify auto-login token from email magic link curl -X POST http://localhost:4000/api/v1/carrier-auth/verify-auto-login \ -H "Content-Type: application/json" \ -d '{ "token": "auto-login-token-from-email" }' ``` --- ## Rate Limiting All API endpoints are rate-limited to prevent abuse: - **Authentication endpoints**: 5 requests per minute per IP - **Dashboard/Booking endpoints**: 30 requests per minute per user - **Global limit**: 100 requests per minute per user Rate limit headers are included in all responses: ``` X-RateLimit-Limit: 30 X-RateLimit-Remaining: 29 X-RateLimit-Reset: 60 ``` --- ## Security ### Best Practices 1. **Always use HTTPS** in production 2. **Store tokens securely** (e.g., httpOnly cookies, secure storage) 3. **Implement token refresh** before access token expires 4. **Validate all input** on client side before sending to API 5. **Handle errors gracefully** without exposing sensitive information 6. **Log out properly** by clearing all stored tokens ### CORS Configuration The API allows requests from: - `http://localhost:3000` (development) - `https://your-production-domain.com` (production) --- ## Changelog ### Version 1.0 (2025-12-04) - Initial release - Authentication endpoints - Dashboard endpoints - Booking management - Document management - Complete carrier portal workflow --- ## Support For API support or questions: - **Email**: support@xpeditis.com - **Documentation**: https://docs.xpeditis.com - **Status Page**: https://status.xpeditis.com --- **Document created**: 2025-12-04 **Author**: Xpeditis Development Team **Version**: 1.0