Invoices
AINative generates invoices for every billing period using its own invoicing system (not Stripe Invoicing). Invoices include line items, PDF download URLs, and payment history.
Base URL: https://api.ainative.studio
Invoice statuses
| Status | Description |
|---|---|
draft | Created but not yet sent. Can still be edited. |
sent | Finalized and delivered to the customer. Immutable. |
paid | Payment received. |
overdue | Due date passed without payment. |
void | Cancelled. Cannot be paid or un-voided. |
List Invoices (Billing Portal)
GET /api/v1/billing/invoices
Paginated list of invoices for the authenticated user from the billing portal. Amounts are returned in dollars (not cents).
Auth required.
Query parameters
| Param | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
page_size | integer | 20 | Invoices per page |
status | string | — | Filter by status (omit for all) |
curl "https://api.ainative.studio/api/v1/billing/invoices?page=1&page_size=10" \
-H "Authorization: Bearer <your_api_key>"
import httpx
resp = httpx.get(
"https://api.ainative.studio/api/v1/billing/invoices",
headers={"Authorization": "Bearer <your_api_key>"},
params={"page": 1, "page_size": 10},
)
data = resp.json()["data"]
for invoice in data["items"]:
print(invoice["number"], invoice["status"], invoice["amount"])
Response
{
"success": true,
"data": {
"items": [
{
"id": "invoice-uuid",
"number": "INV-2026-0042",
"amount": 49.00,
"amount_paid": 49.00,
"currency": "USD",
"status": "paid",
"period_start": "2026-04-01T00:00:00Z",
"period_end": "2026-04-30T23:59:59Z",
"due_date": "2026-05-05T00:00:00Z",
"paid_at": "2026-04-25T10:30:00Z",
"invoice_pdf": "https://storage.example.com/invoices/INV-2026-0042.pdf",
"line_items": [
{
"description": "Pro Plan - Monthly Subscription",
"amount": 4900,
"quantity": 1
}
],
"created_at": "2026-04-01T00:00:00Z"
}
],
"total": 3,
"page": 1,
"page_size": 10,
"has_more": false
}
}
Get Invoice
GET /api/v1/billing/invoices/{invoice_id}
Retrieve a single invoice by its Stripe invoice ID.
Auth required.
curl https://api.ainative.studio/api/v1/billing/invoices/in_xxx \
-H "Authorization: Bearer <your_api_key>"
Response
{
"success": true,
"data": {
"id": "in_xxx",
"amount": 49.00,
"currency": "USD",
"status": "paid",
"created_at": "2026-04-01T00:00:00Z",
"period_start": "2026-04-01T00:00:00Z",
"period_end": "2026-04-30T23:59:59Z",
"items": [...]
}
}
Download Invoice PDF
GET /api/v1/billing/invoices/{invoice_id}/download
Returns the PDF download URL for an invoice. No authentication required — the invoice UUID acts as an unguessable access token, allowing PDF links in emails to work without login.
Void and cancelled invoices return 404.
curl https://api.ainative.studio/api/v1/billing/invoices/invoice-uuid/download
Response
{
"success": true,
"data": {
"invoice_id": "invoice-uuid",
"invoice_number": "INV-2026-0042",
"pdf_url": "https://storage.example.com/invoices/INV-2026-0042.pdf",
"amount": 49.00,
"currency": "USD",
"status": "paid"
}
}
Email Invoice
POST /api/v1/billing/invoices/{invoice_id}/email
Send an invoice email to the authenticated user. Duplicate sends are prevented by checking invoice_email_log. Use resend-email with force_send=true to override.
Auth required.
curl -X POST https://api.ainative.studio/api/v1/billing/invoices/in_xxx/email \
-H "Authorization: Bearer <your_api_key>"
Resend Invoice Email
POST /api/v1/billing/invoices/{invoice_id}/resend-email
Resend an invoice email with duplicate detection. The email type (due_invoice or paid_invoice) is determined automatically from the invoice status.
Auth required.
Query parameters
| Param | Type | Default | Description |
|---|---|---|---|
force_send | boolean | false | Send even if already sent previously |
# Force resend even if email was already sent
curl -X POST \
"https://api.ainative.studio/api/v1/billing/invoices/in_xxx/resend-email?force_send=true" \
-H "Authorization: Bearer <your_api_key>"
Response (success)
{
"success": true,
"message": "Invoice email sent to user@example.com",
"invoice_id": "in_xxx",
"invoice_number": "INV-2026-0042",
"email_type": "paid_invoice",
"recipient": "user@example.com",
"log_id": "log-uuid",
"forced": false
}
Response (already sent, force_send not set)
{
"success": false,
"message": "Invoice email already sent. Use force_send=true to resend.",
"already_sent": true,
"previous_sends": [
{
"type": "paid_invoice",
"status": "sent",
"sent_at": "2026-04-25T11:00:00Z"
}
]
}
Bulk Download Invoices
POST /api/v1/billing/invoices/download-bulk
Get PDF download URLs for up to 50 invoices in a single request.
Auth required.
Request body
| Field | Type | Description |
|---|---|---|
invoice_ids | string[] | Stripe invoice IDs to download (max 50) |
curl -X POST https://api.ainative.studio/api/v1/billing/invoices/download-bulk \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"invoice_ids": ["in_aaa", "in_bbb", "in_ccc"]}'
Response
{
"success": true,
"data": {
"invoices": [
{
"invoice_id": "in_aaa",
"invoice_number": "INV-2026-0040",
"pdf_url": "https://storage.example.com/invoices/INV-2026-0040.pdf",
"amount": 49.00,
"currency": "USD",
"created_at": "2026-03-01T00:00:00Z"
}
],
"total_requested": 3,
"total_available": 1,
"failed": [
{"invoice_id": "in_bbb", "reason": "PDF not available"},
{"invoice_id": "in_ccc", "reason": "Invoice not found"}
]
}
}
Billing Information
GET /api/v1/billing
Returns a summary of the user's billing info: primary payment method, next billing date, and amount due. Card numbers are masked — only the last 4 digits are shown.
Auth required.
curl https://api.ainative.studio/api/v1/billing \
-H "Authorization: Bearer <your_api_key>"
Response (with active subscription)
{
"success": true,
"data": {
"payment_method": {
"type": "card",
"last4": "4242",
"exp_month": 12,
"exp_year": 2027,
"brand": "visa"
},
"next_billing_date": "2026-05-01T00:00:00Z",
"amount_due": 49.00,
"currency": "USD",
"billing_cycle": "monthly"
}
}
Response (no active subscription)
{
"success": true,
"data": {
"payment_method": null,
"next_billing_date": null,
"amount_due": 0.00,
"currency": "USD",
"billing_cycle": null
}
}
Payment Methods
List Payment Methods
GET /api/v1/billing/payment-methods
Returns all Stripe payment methods attached to the user's customer account.
Auth required.
curl https://api.ainative.studio/api/v1/billing/payment-methods \
-H "Authorization: Bearer <your_api_key>"
Response
{
"success": true,
"data": {
"payment_methods": [
{
"id": "pm_xxx",
"type": "card",
"card": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2027
}
}
]
}
}
Add Payment Method
POST /api/v1/billing/payment-methods
Attach a Stripe payment method to the user's customer account. The payment_method_id must be created by Stripe Elements on the frontend before calling this endpoint.
Auth required.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
payment_method_id | string | Yes | Stripe payment method ID (e.g. "pm_xxx") |
curl -X POST https://api.ainative.studio/api/v1/billing/payment-methods \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"payment_method_id": "pm_xxx"}'
Response 201 Created
{
"success": true,
"data": {
"id": "pm_xxx",
"type": "card",
"card": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2027
}
},
"message": "Payment method added successfully"
}
Returns 404 if the user has no Stripe customer (must subscribe to a plan first).
Admin: Invoice Management
The following endpoints are restricted to users with ADMIN or SUPERUSER roles.
Create Invoice
POST /api/v1/invoices
Create a new draft invoice with line items. Invoice number is auto-generated in INV-YYYY-NNNN format.
Admin only.
List All Invoices
GET /api/v1/invoices
Paginated list of all invoices with optional filters.
Admin only.
| Param | Description |
|---|---|
status | Filter by status |
user_id | Filter by customer user ID |
skip / limit | Pagination |
Get Invoice by ID
GET /api/v1/invoices/{invoice_id}
Users can view their own invoices. Admins can view any invoice.
Update Draft Invoice
PATCH /api/v1/invoices/{invoice_id}
Update line items, due date, billing period, or metadata on a draft invoice. Finalized invoices are immutable.
Admin only.
Finalize Invoice
POST /api/v1/invoices/{invoice_id}/finalize
Transitions invoice from draft to sent, generates a PDF asynchronously, and sends an email notification.
Admin only.
Void Invoice
POST /api/v1/invoices/{invoice_id}/void
Cancel an invoice. Void is irreversible.
Admin only.
Mark Invoice Paid
POST /api/v1/invoices/{invoice_id}/mark-paid
Manually mark an invoice as paid for non-Stripe payments (wire transfer, ACH, etc.).
Admin only.
Request body
| Field | Type | Description |
|---|---|---|
payment_method | string | e.g. "wire_transfer", "ach", "check" |
payment_reference | string | Reference number or note |
paid_at | string | ISO-8601 timestamp (optional, defaults to now) |
Get Invoice PDF
GET /api/v1/invoices/{invoice_id}/pdf
Returns the PDF URL or generates the PDF on-demand if not yet created.
Create Payment Intent for Invoice
POST /api/v1/invoices/{invoice_id}/payment-intent
Creates a Stripe Payment Intent for the invoice amount. Returns a client_secret for use with Stripe.js.