Lugg Partner API
Introduction
The Lugg API is built on HTTP. Our API is RESTful. It has predictable resource URLs. It returns HTTP response codes to indicate errors. It also accepts and returns JSON in the HTTP body. You can use your favorite HTTP/REST library for your programming language to use Lugg's API.
Media types
IMPORTANT: All API requests must include the following Accept header to specify the API version:
Accept: application/vnd.lugg+json; version=2
This custom media type directs your requests to the proper API version. Requests without this header may fail or return unexpected results.
Authentication
You must send an OAuth2 access token in an Authorization header with each request.
Creating a client
To obtain OAuth credentials, please contact your Lugg partner representative or reach out to our partnerships team. We'll provide you with a Client ID and Client Secret for your organization. Keep these credentials secure as they'll be required for all API requests.
Generating a token
Lugg uses the client_credentials flow to create access tokens for applications that
you have created for your organization. Once obtained you'll use this access token to make
requests on behalf of your organization.
Partner access tokens currently do not expire automatically. Reuse the token until it is revoked, and create a new token if you revoke or rotate credentials.
curl -X POST 'https://api.lugg.com/oauth/token' \
-H 'Accept: application/vnd.lugg+json; version=2' \
-d '{ \
"grant_type": "client_credentials", \
"client_id": <client_id>, \
"client_secret": <client_secret>, \
"scope": "public org" \
}'
Making authenticated requests
To authenticate subsequent API requests, you must provide both the Accept header and a valid bearer token:
curl -X GET 'https://api.lugg.com/bookings' \
-H 'Accept: application/vnd.lugg+json; version=2' \
-H 'Authorization: Bearer <bearer_token>'
Scopes
OAuth tokens require specific scopes to access API resources. When requesting a token, include the scope parameter with space-separated scope values.
Available Scopes
| Scope | Description | Use Case |
|---|---|---|
public |
Base access scope | Included by default in all tokens |
org |
Full organization access | Read and write permissions for all resources |
org:read |
Read-only organization access | List and view resources only |
org:write |
Write-only organization access | Create, update, and delete resources only |
Scope Examples
| Access Level | Scope Value | Use Case |
|---|---|---|
| Full access | "scope": "public org" |
Recommended for most integrations |
| Read-only | "scope": "public org:read" |
Reporting and monitoring |
| Write-only | "scope": "public org:write" |
Booking creation only |
| Explicit read+write | "scope": "public org:read org:write" |
Equivalent to org |
Note: The org scope is a parent scope that grants both read and write access. For granular control, use org:read or org:write individually. Endpoints accept either the parent org scope or the appropriate granular scope (org:read for GET requests, org:write for POST/PATCH/DELETE requests).
Sandbox Environment
The Lugg API provides a sandbox environment for testing and development purposes at https://api-sandbox.lugg.com.
Key Characteristics
- Separate credentials: The sandbox requires its own OAuth client ID and secret. Contact your Lugg partner representative to obtain sandbox credentials.
- Safe testing: Sandbox data is isolated from production. No real workers are dispatched, and no real charges are processed.
- Non-functional features: Share URLs, tracking links, and customer-facing interfaces generated in sandbox are for testing purposes only and will not function for end users.
When to Use Sandbox
Use the sandbox environment to:
- Test your integration during development
- Validate API requests and responses
- Test error handling and edge cases
- Demonstrate your integration to stakeholders
Always test thoroughly in sandbox before deploying to production.
Automatic Booking Simulation
To test a complete booking lifecycle, add test_specifications.mode: auto to a POST /bookings request:
{
"test_specifications": {
"mode": "auto"
}
}
The request must include a valid arrival window. The simulation starts immediately and does not wait for the requested arrival-window time.
Automatic simulation:
- Assigns a synthetic crew
- Progresses every route stop through arrival and completion
- Attaches a representative completion photo to each completed stop
- Calculates the final fare and creates normal sandbox billing records
- Sends the existing booking webhooks
The booking response has the same shape as a normal booking response. Use booking webhooks or GET /bookings/{id} to observe its progress.
test_specifications is only accepted in the sandbox. Production requests that include it return a 422 response.
Errors
Lugg uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, a arrival window is no longer available, etc.). Codes in the 5xx range indicate an error with Lugg's servers.
HTTP Status codes
| Code | Title | Description |
|---|---|---|
| 200 | OK | The request was successful. |
| 400 | Bad request | Bad request. |
| 404 | Not found | Some resource does not exist. |
| 401 | Unauthorized | Your access token is missing or invalid. |
| 429 | Too Many Requests | The rate limit was exceeded. |
| 5xx | Internal Server Error | An error occurred with our API. |
Error types
| Type | Description |
|---|---|
| api_error | Internal API error. |
| validation_error | Your parameters were not valid. |
| authentication_error | You are not authorized. |
| invalid_request_error | The parameters were valid but the request could not be completed. |
| rate_limit_error | The request has been rate limited. |
Rate-limited responses use type: rate_limit_error and typically include code: rate_limit_exceeded.
Example error response.
{
"type": "invalid_request_error",
"message": "Arrival window no longer available.",
"param": "arrival_window_id",
"code": null
}
Rate Limiting
To keep the API stable, requests are rate limited at the organization level.
Current default:
- 300 requests per 60 seconds across your organization's API usage.
If you exceed this limit, you'll receive 429 Too Many Requests. Continued excessive traffic may result in temporary blocking.
Rate limit headers
| Header | Description |
|---|---|
Retry-After |
Seconds to wait before retrying. |
RateLimit-Limit |
Maximum requests allowed in the current window. |
RateLimit-Remaining |
Requests remaining in the current window. |
RateLimit-Reset |
Unix timestamp when the current window resets. |
Integration guidance
- Prefer webhook/event-driven flows over polling when possible.
- Keep request patterns efficient and avoid broad scans for single-entity lookups.
- Control concurrency centrally if multiple workers/services call the API.
- Honor
Retry-Afterand back off on429responses.
Limits may change over time. Build clients to handle 429 responses gracefully.
Pagination
The Lugg API uses cursor-based pagination for list endpoints. This provides consistent results even as data changes.
Request Parameters
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Number of results per page (1-100, default: 20) |
| after | string | Cursor for forward pagination (returns next page) |
| before | string | Cursor for backward pagination (returns previous page) |
Note: You cannot use both after and before in the same request.
Response Format
All paginated endpoints return a consistent structure with:
data: Array of requested resourcesnext: Complete URL for the next page (null if no more pages)previous: Complete URL for the previous page (null if at the beginning)
Example
Request:
GET https://api.lugg.com/bookings?limit=10
Response:
{
"data": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"hid": "ABC123",
"state": "created"
// ... other booking fields
}
],
"next": "https://api.lugg.com/bookings?limit=10&after=eyJpZCI6IjA5ODc2NTQzMjEiLCJjcmVhdGVkX2F0IjoiMjAyNC0wMS0wMlQxMjowMDowMFoifQ==",
"previous": null
}
- First page: Omit both
afterandbeforeparameters - Next page: Use the complete URL provided in the
nextfield - Previous page: Use the complete URL provided in the
previousfield - Last page: When
nextis null
The pagination URLs include all necessary parameters. Simply follow these URLs directly without modification.