API Conventions
API Conventions
This page covers the consistent patterns used across the Brilo API — base URL, how to send requests, what responses look like, how errors are structured, and how pagination works.
Base URL
All API requests go to:
https://api.brilo.tech
All endpoints are prefixed with /api/. For example:
https://api.brilo.tech/api/customers/
https://api.brilo.tech/api/subscriptions/
https://api.brilo.tech/api/credits/
Request Format
Headers
Every request requires:
X-API-KEY: your-api-key
Content-Type: application/json
Request Body
All POST and PATCH request bodies should be JSON:
curl -X POST https://api.brilo.tech/api/customers/ \
-H "X-API-KEY: your-api-key" \
-H "Content-Type: application/json" \
-d '{"customer_id": "cust_123", "email": "[email protected]"}'Response Format
All responses are JSON. Successful responses return the resource object directly — there is no outer wrapper.
{
"customer_id": "cust_123",
"email": "[email protected]",
"customer_name": "Acme Corp",
"total_amount_due": 0.0,
"subscriptions": [],
"invoices": []
}HTTP Status Codes
| Code | Meaning |
|---|---|
200 OK | Request succeeded. Response contains the resource. |
201 Created | Resource was created. Response contains the new resource. |
204 No Content | Request succeeded with no response body (e.g. deletes). |
400 Bad Request | Invalid request. Check the error detail for what's wrong. |
401 Unauthorized | Missing or invalid API key. |
404 Not Found | The resource doesn't exist. |
409 Conflict | Request conflicts with existing state (e.g. duplicate ID). |
422 Unprocessable Entity | Request is well-formed but fails validation. |
429 Too Many Requests | Rate limit exceeded. |
500 Internal Server Error | Something went wrong on Brilo's end. |
Error Responses
Errors return a JSON body with detail about what went wrong:
{
"detail": "Customer with id 'cust_123' already exists."
}For validation errors with multiple fields, errors may be keyed by field:
{
"email": ["This field is required."],
"customer_id": ["This field may not be blank."]
}Always check the detail or field-level messages to understand what to fix before retrying.
Monetary Amounts
All monetary values in the API are represented as decimal numbers in the major currency unit — not cents. 29.00 means $29.00 USD, not $0.29.
{
"amount": 99.00,
"currency": {
"code": "USD",
"name": "US Dollar",
"symbol": "$"
}
}When specifying amounts in request bodies, use the same decimal format: "recurring_fee": 29.00.
Dates and Timestamps
All dates and timestamps use ISO 8601 format in UTC:
- Date-only fields:
"2024-05-01" - Date-time fields:
"2024-05-01T10:00:00Z"
When sending dates in request bodies, use these formats. Timestamps in responses are always UTC — convert to local time in your application as needed.
Pagination
List endpoints return paginated results. The response includes the results array and pagination metadata:
{
"count": 143,
"next": "https://api.brilo.tech/api/customers/?page=2",
"previous": null,
"results": [
{ "customer_id": "cust_001", ... },
{ "customer_id": "cust_002", ... }
]
}| Field | Description |
|---|---|
count | Total number of records across all pages |
next | URL for the next page, or null if on the last page |
previous | URL for the previous page, or null if on the first page |
results | Array of records for the current page |
Default page size is 50. Pass ?page=N to navigate:
curl "https://api.brilo.tech/api/customers/?page=3" \
-H "X-API-KEY: your-api-key"Rate Limits
The API enforces rate limits to protect stability. If you exceed the limit, you'll receive a 429 Too Many Requests response.
The response includes a Retry-After header indicating how many seconds to wait before retrying:
HTTP/1.1 429 Too Many Requests
Retry-After: 10
Best practices:
- Add exponential backoff with jitter to your retry logic
- Don't fire large batches of events synchronously — queue and send at a steady rate
- Use the Verify Events Received endpoint to confirm delivery rather than re-sending blindly
Idempotency
For event tracking, Brilo uses the idempotency_id field to deduplicate requests. If you send the same event twice with the same idempotency_id, Brilo will process it only once.
This means you can safely retry failed event tracking requests without worrying about double-counting usage.
{
"event_name": "api_call_made",
"customer_id": "cust_123",
"idempotency_id": "evt_abc123unique",
"time_created": "2024-05-01T10:00:00Z"
}Use a UUID or a deterministic hash as your idempotency_id. See Events & Metering for more detail.
Next Steps
Updated 4 months ago

