Authentication, rate limits, and first API call
Reading time: 10 minutes
Integrate with Atlas programmatically using the REST API. This guide covers authentication, base URL, rate limits, request/response format, error handling, pagination, and webhooks.
All API requests use the following base URL:
https://api.atlas-accounting.com/api/v1
For a local or self-hosted instance, the base URL is your instance host with the same prefix — e.g. http://localhost:8000/api/v1.
The API follows REST conventions with JSON request and response bodies.
Atlas uses JWT (JSON Web Token) authentication with refresh tokens.
Field naming: the API uses camelCase for all request and response fields (e.g.
accessToken,fullName).
POST /auth/login
Content-Type: application/json
{
"email": "your@email.com",
"password": "your-password"
}
Response:
{
"user": {
"id": "uuid",
"email": "your@email.com",
"firstName": "Your",
"lastName": "Name",
"fullName": "Your Name",
"isActive": true,
"isEmailVerified": true,
"lastLoginAt": "2026-01-15T10:30:00Z",
"createdAt": "2026-01-01T09:00:00Z"
},
"organizations": [
{
"id": "uuid",
"name": "Your Organization",
"subscriptionTier": "starter"
}
],
"tokens": {
"accessToken": "eyJhbG...",
"refreshToken": "eyJhbG...",
"tokenType": "bearer",
"expiresIn": 3600,
"expiresAt": "2026-01-15T11:30:00Z"
}
}
Include the access token in the Authorization header:
Authorization: Bearer eyJhbG...
When the access token expires (after 1 hour):
POST /auth/refresh
Content-Type: application/json
{
"refreshToken": "eyJhbG..."
}
Atlas applies rate limiting to protect the platform — most notably on authentication endpoints such as POST /auth/login. When you exceed a limit, the API returns 429 Too Many Requests; back off and retry after a short delay.
Build clients to handle 429 gracefully (exponential backoff). Limits are subject to change and are not exposed as response headers.
All requests with a body must use:
Content-Type: application/json
Most resource endpoints operate within a single company. Pass the company as a company_id query parameter (required on list endpoints), for example GET /api/v1/invoices/?company_id=....
{
"id": "uuid",
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-01-15T10:30:00Z",
...
}
List endpoints return a paged envelope:
{
"items": [...],
"total": 150,
"limit": 100,
"offset": 0,
"hasMore": true
}
Most errors follow RFC 7807 (application/problem+json):
{
"type": "https://atlas.elegsys.com/errors/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "Admin or owner role required",
"instance": "/api/v1/webhook-subscriptions/event-types"
}
Validation errors (422) return a detail array, one entry per invalid field:
{
"detail": [
{
"loc": ["body", "amount"],
"msg": "Input should be greater than 0",
"type": "greater_than"
}
]
}
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 204 | No Content (successful deletion) |
| 400 | Bad Request — invalid input |
| 401 | Unauthorized — invalid or expired token |
| 403 | Forbidden — insufficient permissions |
| 404 | Not Found |
| 409 | Conflict — duplicate or state conflict |
| 422 | Validation Error — check the detail array |
| 429 | Rate Limited — slow down |
| 500 | Internal Server Error |
List endpoints use offset-based pagination:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 100 | Items per page (maximum varies by endpoint, e.g. 500) |
offset | integer | 0 | Number of items to skip |
The response envelope includes total, limit, offset, and hasMore so you can page through results. Most endpoints also accept resource-specific filters (e.g. status, customer_id, start_date/end_date).
GET /api/v1/invoices/?company_id=YOUR_COMPANY_ID&limit=25&offset=50
Let's fetch the current user's profile:
curl -X GET https://api.atlas-accounting.com/api/v1/auth/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response:
{
"user": {
"id": "uuid",
"email": "your@email.com",
"firstName": "Your",
"lastName": "Name",
"fullName": "Your Name",
"isActive": true,
"isEmailVerified": true
},
"role": "accountant",
"organization": {
"id": "uuid",
"name": "Your Organization",
"subscriptionTier": "starter"
},
"hasPortalAccess": true,
"resolvedPermissions": ["view_reports", "manage_invoices", "..."],
"companyAccess": [],
"departmentAccess": [],
"locationAccess": []
}
The role is one of owner, admin, accountant, bookkeeper, viewer, or employee, and resolvedPermissions lists the effective permission keys for the current user.
| Endpoint | Method | Description |
|---|---|---|
/auth/me | GET | Current user profile |
/companies/ | GET, POST | List and create companies |
/invoices/ | GET, POST | List and create invoices |
/bills/ | GET, POST | List and create bills |
/journal-entries/ | GET, POST | List and create journal entries |
/customers/ | GET, POST | List and create customers |
/vendors/ | GET, POST | List and create vendors |
/accounts/ | GET, POST | Chart of accounts |
/reports/profit-loss | GET | Profit & Loss report |
/reports/balance-sheet | GET | Balance Sheet report |
Migrating from QuickBooks? The API also exposes import endpoints under
/import/quickbooks/...(customers, vendors, invoices, bills).
Receive real-time notifications when events occur in Atlas.
Manage webhooks in the app under Settings > Webhooks (Admin or Owner role required), or via the API at /webhook-subscriptions. To create one:
GET /webhook-subscriptions/event-types for the live list)Delivery history is available at GET /webhook-subscriptions/{id}/deliveries.
| Event | Triggered When |
|---|---|
invoice.created | A new invoice is created |
invoice.sent | An invoice is sent to a customer |
invoice.approved | An invoice is approved |
invoice.paid | An invoice is fully paid |
invoice.overdue | An invoice becomes overdue |
invoice.voided | An invoice is voided |
bill.created | A new bill is created |
bill.approved | A bill is approved |
bill.paid | A bill is paid |
bill.voided | A bill is voided |
payment.received | A customer payment is recorded |
payment.made | A vendor payment is recorded |
journal_entry.posted | A journal entry is posted |
journal_entry.voided | A journal entry is voided |
period.closed | An accounting period is closed |
period.reopened | An accounting period is reopened |
{
"event": "invoice.paid",
"timestamp": "2026-01-15T10:30:00Z",
"data": {
"id": "uuid",
"invoiceNumber": "INV-001",
"amount": 1500.0,
"currency": "USD",
"customerId": "uuid"
}
}
Each webhook delivery includes these headers:
| Header | Purpose |
|---|---|
X-Webhook-Signature | HMAC-SHA256 of the payload, signed with your secret |
X-Webhook-Id | Unique delivery ID |
X-Webhook-Timestamp | When the event was sent |
Verify a delivery by computing the HMAC-SHA256 of the raw request body using your webhook secret and comparing it to X-Webhook-Signature.
Official client libraries are planned but not yet published. In the meantime, the API is plain REST/JSON — use any HTTP client (requests, httpx, fetch, axios). The interactive OpenAPI documentation is served at /docs (Swagger UI) on your Atlas instance, with the full machine-readable spec at /openapi.json.
/docs on your Atlas instance