/sales/invoices
Path: /sales/invoices
Namespace: sales
Resource: invoices
Overview
Sales invoices use the same JSON resource shape and relationships as Admin Invoices. For GET /sales/invoices.json, the server only returns invoices that match the sales view of the tenant (current domain, seller/supplier parties, and the seller agent tied to the signed-in user). If an invoice you expect is missing from this list, compare seller_id, supplier_id, and seller_agent_id on the record against your session context, or open it under /admin/invoices if your app has access.
Relationships
See Admin Invoices for fields and associations. Use the routes in this page for all sales JSON calls.
Seller, supplier, and seller agent (API behavior)
GET /sales/invoices.json: Results are already filtered for the sales workspace; optional Ransack params such asq[seller_id_eq]=must still be consistent with that view or the row will not appear.POST /sales/invoices.json: You can sendseller_id(and other allowed invoice fields) in the JSON body when creating or updating an unconfirmed invoice; omitseller_idonly if your integration relies on server-side defaults for the current host.- Example: Minimal create:javascript
const invoice = await fetch('/sales/invoices.json', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ invoice: { invoice_type: 'invoice', buyer_id: 2, date: '2026-03-15' } }) }).then(r => r.json());
Supplier
Supplier party fields behave like admin; see Admin Invoices.
Key Features
- Filtered index:
GET /sales/invoices.jsonreturns the sales-oriented subset for the current session. - Same JSON resource as admin for show/create/update/delete where your credentials allow.
- Nested lines: Use
POST /sales/invoices/:id/invoice_lines.json(and related line routes), not a nested payload on the invoice create, unless your deployment documents otherwise.
Available Operations
List Invoices (GET)
Endpoint: GET /sales/invoices.json
Query Parameters:
q[field_predicate]=value- Ransack query filters for advanced filteringscope=name- Apply a named list scope (e.g.active,unpaid,due,leads,orders; see Scopes below)page=N- Page number for paginationper_page=N- Items per page (default: 25)
Request Examples:
curl -X GET "https://your-company.erpax.com/sales/invoices.json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"curl -X GET "https://your-company.erpax.com/sales/invoices.json?scope=unpaid" \
-H "Accept: application/json"JavaScript Example:
const response = await fetch('/sales/invoices.json', {
credentials: 'include',
headers: { 'Accept': 'application/json' }
});
const data = await response.json();Response (200 OK):
{
"invoices": [
{
"id": 1,
"invoice_type": "invoice",
"number": "INV-2026-001",
"date": "2026-03-15",
"seller_id": 1,
"buyer_id": 2,
"total_amount_cents": 100000,
"confirmed": true
}
],
"meta": {
"current_page": 1,
"per_page": 25,
"total_pages": 5,
"total_count": 123
}
}Show Invoice (GET /:id)
Endpoint: GET /sales/invoices/:id.json
Request Example:
curl -X GET "https://your-company.erpax.com/sales/invoices/123.json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (200 OK):
{
"invoice": {
"id": 123,
"invoice_type": "invoice",
"number": "INV-2026-001",
"date": "2026-03-15",
"seller_id": 1,
"buyer_id": 2,
"total_amount_cents": 100000,
"confirmed": true
}
}Create Invoice (POST)
Endpoint: POST /sales/invoices.json
Request Example:
curl -X POST "https://your-company.erpax.com/sales/invoices.json" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"invoice": {
"invoice_type": "invoice",
"buyer_id": 2,
"date": "2026-03-15",
"currency_code": "USD"
}
}'Notes
seller_id: Include when you need a specific seller address on the created invoice so it appears underGET /sales/invoices.jsonfor your sales session.- Line items: Use
POST /sales/invoices/:invoice_id/invoice_lines.json(see Sales invoice lines). Do not rely on embedding lines in the invoice create body unless your server accepts that shape.
JavaScript Example:
const response = await fetch('/sales/invoices.json', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
invoice: {
invoice_type: 'invoice',
buyer_id: 2,
date: '2026-03-15',
currency_code: 'USD'
}
})
});
const invoice = await response.json();Response (201 Created):
{
"invoice": {
"id": 123,
"invoice_type": "invoice",
"seller_id": 1,
"buyer_id": 2,
"date": "2026-03-15",
"currency_code": "USD",
"total_amount_cents": 100000,
"confirmed": false,
"created_at": "2026-03-15T14:30:00Z"
}
}Update Invoice (PATCH /:id)
Endpoint: PATCH /sales/invoices/:id.json
Request Example:
curl -X PATCH "https://your-company.erpax.com/sales/invoices/123.json" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"invoice": {
"confirmed": true
}
}'Response (200 OK):
{
"invoice": {
"id": 123,
"confirmed": true,
"updated_at": "2026-03-15T15:00:00Z"
}
}Delete Invoice (DELETE /:id)
Endpoint: DELETE /sales/invoices/:id.json
Request Example:
curl -X DELETE "https://your-company.erpax.com/sales/invoices/123.json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (204 No Content):
(empty response)Member Actions
Custom actions available on individual invoices via API:
Renew Invoice
Endpoint: POST /sales/invoices/:id/renew
Description: Renew a recurring invoice (subscription or lease).
Request Example:
curl -X POST "https://your-company.erpax.com/sales/invoices/123/renew" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (200 OK):
{
"invoice": {
"id": 123,
"next_billing_date": "2026-04-15",
"updated_at": "2026-03-15T15:00:00Z"
}
}Email Invoice
Endpoint: GET /sales/invoices/:id/email
Description: Send the invoice via email to the buyer.
Request Example:
curl -X GET "https://your-company.erpax.com/sales/invoices/123/email" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (200 OK):
{
"message": "Email sent successfully"
}Print Invoice
Endpoint: GET /sales/invoices/:id/print
Description: Generate and return a printable version of the invoice.
Request Example:
curl -X GET "https://your-company.erpax.com/sales/invoices/123/print" \
-H "Accept: application/pdf" \
-H "Cookie: session_cookie"Response: Returns PDF or HTML printable version of the invoice.
Duplicate Invoice
Endpoint: POST /sales/invoices/:id/duplicate
Description: Create a duplicate copy of the invoice.
Request Example:
curl -X POST "https://your-company.erpax.com/sales/invoices/123/duplicate" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (201 Created):
{
"invoice": {
"id": 124,
"invoice_type": "invoice",
"number": null,
"date": "2026-03-15",
"created_at": "2026-03-15T15:00:00Z"
}
}Scopes
Pass a scope as a query parameter, for example GET /sales/invoices.json?scope=unpaid.
Available scope values on this route include active (default), pending, renewable, leads, orders, invoices, credits, paid, unpaid, and due. Admin Invoices documents additional scopes (accounting, aging, cancelled, etc.) available only under /admin/invoices.
Filters
Use Ransack-style query params q[...] on GET /sales/invoices.json the same way as on GET /admin/invoices.json (numbers, parties, dates, amounts, etc.). Which PATCH / POST attributes succeed depends on your session; treat 422 / 403 responses as the source of truth for allowed fields.
Business Rules
GET /sales/invoices.jsonreturns only invoices visible in the sales workspace for the current user and domain.- Writes (
POST,PATCH,DELETE) follow the same rules as other namespaces for confirmed documents and payments; unauthorized actions return an error response. - For full capability and extra scopes, use Admin Invoices routes where your app has access.
Related Resources
- Admin Invoices - Complete invoice documentation with all features
- Sales Dashboard - Sales namespace overview
- Sales Addresses - Address management in sales namespace
- Sales Items - Item management in sales namespace