API Documentation
Complete REST API reference with authentication, endpoints, and code examples
Authentication Required
All API requests require authentication. Include your API key in the request header as shown below. You can generate API keys from your Account Settings.
Authentication
Authenticate API requests by including your API key in the Authorization header. All requests must be made over HTTPS.
# Include the API key in every requestcurl -X GET https://api.umbraerp.com/v1/invoices \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json"If authentication fails, the API returns a 401 Unauthorized response:
{ "error": { "code": "UNAUTHORIZED", "message": "Invalid or expired API key", "status": 401 }}Base URL
All API endpoints are relative to the following base URL:
https://api.umbraerp.com/v1Endpoints Overview
The API is organized around REST principles. Below is a summary of the main resource endpoints:
| Method | Endpoint | Description |
|---|---|---|
GET | /invoices | List all invoices |
POST | /invoices | Create a new invoice |
GET | /customers | List all customers |
POST | /customers | Create a new customer |
GET | /products | List all products |
POST | /products | Create a new product |
GET | /employees | List all employees |
GET | /reports/profit-loss | Generate profit & loss report |
GET | /webhooks | List webhook subscriptions |
List Invoices
Retrieve a paginated list of all invoices in your account. Supports filtering, sorting, and pagination through query parameters.
curl -X GET "https://api.umbraerp.com/v1/invoices?page=1&limit=20&status=unpaid&sort=due_date:asc" \ -H "Authorization: Bearer YOUR_API_KEY"Successful response:
{ "data": [ { "id": "inv_abc123", "number": "INV-01001", "customer": { "id": "cust_xyz789", "name": "Acme Corp" }, "total": 1500.00, "currency": "USD", "status": "unpaid", "due_date": "2026-04-15", "created_at": "2026-03-01T10:30:00Z" } ], "pagination": { "page": 1, "limit": 20, "total": 1, "total_pages": 1 }}Create an Invoice
Create a new invoice by sending a POST request with the required fields in the request body:
curl -X POST https://api.umbraerp.com/v1/invoices \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "customer_id": "cust_xyz789", "items": [ { "description": "Web Development Services", "quantity": 40, "unit_price": 75.00 }, { "description": "Hosting (Monthly)", "quantity": 1, "unit_price": 49.99 } ], "due_date": "2026-04-15", "currency": "USD", "notes": "Payment due within 30 days" }'Successful creation returns the invoice with a 201 status:
{ "data": { "id": "inv_def456", "number": "INV-01002", "customer_id": "cust_xyz789", "items": [ { "description": "Web Development Services", "quantity": 40, "unit_price": 75.00, "total": 3000.00 }, { "description": "Hosting (Monthly)", "quantity": 1, "unit_price": 49.99, "total": 49.99 } ], "subtotal": 3049.99, "tax": 0, "total": 3049.99, "currency": "USD", "status": "draft", "due_date": "2026-04-15", "created_at": "2026-03-04T12:00:00Z" }}Error Handling
The API uses standard HTTP status codes to indicate success or failure. Error responses include a structured JSON body with details:
{ "error": { "code": "VALIDATION_ERROR", "message": "The request body contains invalid fields", "status": 422, "details": [ { "field": "customer_id", "message": "Customer ID is required" } ] }}Common Status Codes
| Code | Meaning |
|---|---|
| 200 | Request succeeded |
| 201 | Resource created successfully |
| 400 | Bad request (malformed syntax) |
| 401 | Unauthorized (invalid API key) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Resource not found |
| 422 | Validation error |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Rate Limiting
API requests are rate limited based on your plan tier. Rate limit information is included in the response headers:
X-RateLimit-Limit: 1000X-RateLimit-Remaining: 999X-RateLimit-Reset: 1705312800Retry-After: 60Handling Rate Limits
Implement exponential backoff in your client code to gracefully handle rate limit responses. Check the Retry-After header to determine how long to wait before retrying the request.
SDK Examples
Use the official SDK for a simpler integration experience:
import { UmbraClient } from '@umbra-erp/sdk'; const client = new UmbraClient({ apiKey: process.env.UMBRA_API_KEY,}); // List invoicesconst invoices = await client.invoices.list({ page: 1, limit: 20, status: 'unpaid',}); // Create an invoiceconst newInvoice = await client.invoices.create({ customer_id: 'cust_xyz789', items: [ { description: 'Consulting', quantity: 10, unit_price: 150 }, ], due_date: '2026-04-15',}); // List customersconst customers = await client.customers.list({ limit: 50 }); // Create a productconst product = await client.products.create({ name: 'Widget Pro', sku: 'WDG-PRO-001', price: 29.99, stock: 500,}); console.log('Unpaid invoices:', invoices.data.length);console.log('New invoice:', newInvoice.data.number);from umbra_erp import UmbraClient client = UmbraClient(api_key="YOUR_API_KEY") # List invoicesinvoices = client.invoices.list(page=1, limit=20, status="unpaid") # Create an invoicenew_invoice = client.invoices.create( customer_id="cust_xyz789", items=[ {"description": "Consulting", "quantity": 10, "unit_price": 150}, ], due_date="2026-04-15",) # List customerscustomers = client.customers.list(limit=50) # Create a productproduct = client.products.create( name="Widget Pro", sku="WDG-PRO-001", price=29.99, stock=500,) print(f"Unpaid invoices: {invoices.pagination.total}")print(f"New invoice: {new_invoice.data.number}")