Invoices

Billing for completed flights.

15 endpoints · base URL https://api.aerscheduler.com

get/invoices

List invoices

Every invoice in the organization. Administrators only , this is the whole membership's payment history plus revenue aggregates, so it is treated as a financial surface rather than an operational one. Dispatchers get the per-reservation invoice instead.

Query parameters

startDatestringStart of the window, ISO 8601. Include an offset or Z.
endDatestringEnd of the window, ISO 8601.
qstringFree-text filter. Matches the fields a person would search on.
paidbooleanFilter on paid state.
voidedbooleanFilter on voided state. paid=false on its own still includes voided invoices, which nobody owes; pass voided=false for outstanding.
overduebooleanOnly invoices that are past due: unpaid, not voided, and carrying a dueAt in the past. An invoice with no due date is never overdue. Matches the Overdue status of the revenue report.
limitintegerRows to return, 1,1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row , total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKThe invoices.→ { data: Invoice[] }
400Bad RequestThe date range is unparseable.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/invoices \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/invoices

Create an invoice

Bills a member for something that isn't a flight , a checkout fee, a headset, a late cancellation. Line items are validated against the organization before anything is written.

For billing a completed flight, use POST /reservations/{id}/invoices instead: it prices the booking from the meters you recorded.

Request body

The invoice. Exactly one of customer or guest is required.

customerobjectBill a member. Mutually exclusive with guest.
guestobjectBill a non-member by name and email. Mutually exclusive with customer.
memostringOptional note shown on the invoice.
itemsrequiredobject[]Line items. unitPrice is in cents, before tax. Sales tax follows the organization's own setup (see GET /organizations/salesTax): a line in a category the organization taxes is taxed at that category's rate, taxable overrides that for one line, and a customer marked exempt is never taxed. A line that sends neither category nor taxable is never taxed, so clients written before sales tax existed keep raising the bills they show.
dueAtstringWhen payment is due.
dueInintegerDays until due, used when Stripe needs a relative due.
serviceFeeTaxablebooleanTax the organization's service fee line (or not), whatever the organization's rule for Fees says. Absent follows the rule.
expectedTotalintegerOptional. The total from POST /invoices/preview. When it no longer matches (a tax rate, rule or exemption changed in between), nothing is raised and the answer is 409 with the new total.

Responses

200OKSuccess.→ { data: Invoice }
201CreatedThe invoice, with Stripe's tax on each line and total = subtotal + tax.→ { data: Invoice }
400Bad RequestA line item or the customer failed validation, a line is taxable but the organization has no rate, or a taxed charge would go on a member's account balance (ledger mode), which cannot hold sales tax.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409expectedTotal no longer matches: the bill changed since it was priced.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/invoices \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[]}'
get/invoices/{invoiceId}

Get an invoice

One invoice with its line items. An aircraft owner from outside the organization reads only their own bills, and gets what they need to read and pay one: its number, dates, status, memo, lines with their tax, totals, how a desk payment came in (paymentMethod, checkNumber, paymentReceivedOn), the payment and PDF links, and the work order it is for. Not the organization's QuickBooks sync state, its note about the payment, or which of its staff raised, voided or marked it paid. billTo (name, billing address, phone, email) is on the bill for the person billed and for administrators.

Path parameters

invoiceIdrequiredintegerThe invoice id.

Responses

200OKSuccess.→ { data: Invoice }
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
404Not FoundNo such invoice.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/invoices/:invoiceId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
patch/invoices/{invoiceId}

Mark an invoice paid, or void it

Send markPaid: true to record a payment taken outside the card flow, optionally saying how: paymentMethod, checkNumber (only with check), paymentReceivedOn (the day it arrived, YYYY-MM-DD; today in the organization's calendar when left out, never in the future) and paymentNote. Stripe is told the invoice was paid outside it, and the person billed is sent a receipt. Or send markVoided: true. Payment fields without markPaid are refused. Requires the admin role.

Path parameters

invoiceIdrequiredintegerThe invoice id.

Request body

What to do.

markPaidbooleanRecord it paid.
markVoidedbooleanVoid it.
paymentMethodstring | null
checkNumberstring | nullOnly with paymentMethod: check.
paymentReceivedOnstring | nullThe day the money arrived. Not in the future.
paymentNotestring | null

Responses

200OKSuccess.→ { data: Invoice }
400Bad RequestAlready voided, a field is not valid, or payment fields without markPaid.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X PATCH https://api.aerscheduler.com/invoices/:invoiceId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"markPaid":true,"markVoided":true}'
post/invoices/preview

Price an invoice without raising it

Takes exactly the body of POST /invoices and answers what that call would charge: each line with its sales tax, the organization's service fee line, tax per rate, and the total. Nothing is written and Stripe is not called. The same permission as creating the invoice.

Send the total back as expectedTotal on the create to be sure nothing moved in between.

Responses

200OKSuccess.→ { data: InvoicePreview }
400Bad RequestThe body would fail POST /invoices for the same reason.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/invoices/preview \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/invoices/summary

Summarise invoices

Revenue and outstanding totals for a window, in cents, with the counts behind them. Administrators only, like the list.

Takes the same startDate, endDate and q as GET /invoices, so it describes exactly the invoices that endpoint would return , except paid, which narrows the list but not this. Use it instead of adding up a list you fetched: lists are capped at 1,000 rows, so summing what you received would give you the total of an arbitrary thousand invoices for any organization with more than that.

Query parameters

startDatestringStart of the window, ISO 8601. Include an offset or Z.
endDatestringEnd of the window, ISO 8601.
qstringFree-text filter. Matches the fields a person would search on.
voidedbooleanFilter on voided state. outstanding already excludes voided invoices; this narrows revenue too.

Responses

200OKThe totals.→ { data: object }
400Bad RequestThe date range is unparseable.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/invoices/summary \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/invoices/{invoiceId}/files

List an invoice's files

The vendor's invoice, a receipt, an 8130-3 attached to the bill. url works for 15 minutes. Administrators read every file; the person billed reads only the ones shown to them (visibility: owner). Anybody else is answered 403, as for an id that is not this organization's.

Path parameters

invoiceIdrequiredintegerThe invoice id.

Query parameters

limitintegerRows to return, 1,1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row , total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKThe files, oldest first.→ { data: InvoiceFile[] }
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenNot yours, or not this organization's.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/invoices/:invoiceId/files \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/invoices/{invoiceId}/files

Attach files to an invoice

Send fileNames (up to 5 per request; jpg, png, heic or pdf), visibility (shop by default, owner to show them to the person billed) and a label for a single file. The answer has the new rows in data and, in the same order, signedUrlData: a presigned POST for each file, which the client posts the bytes to. An invoice holds up to 30 files. Requires the admin role. Refused in the demo.

Path parameters

invoiceIdrequiredintegerThe invoice id.

Request body

The files to attach.

fileNamesstring[]
visibility"shop" | "owner"
labelstring | null

Responses

201CreatedThe rows and where to upload each file.
400Bad RequestA file name or the count is not valid.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenNot allowed, not this organization's, or the demo.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/invoices/:invoiceId/files \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fileNames":[],"visibility":"shop"}'
post/invoices/{invoiceId}/remind

Send a payment reminder

Emails the member about an outstanding invoice. Requires the admin role.

Path parameters

invoiceIdrequiredintegerThe invoice id.

Responses

200OKSuccess.→ { data: object }
204No ContentSuccess. No body.
400Bad RequestAlready paid, or reminded too recently.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/invoices/:invoiceId/remind \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/invoices/orgUsers/{orgUserId}

List a member's invoices

Your own, or anyone's if you are an administrator.

Path parameters

orgUserIdrequiredintegerThe membership id.

Query parameters

startDatestringStart of the window, ISO 8601. Include an offset or Z.
endDatestringEnd of the window, ISO 8601.
paidbooleanFilter on paid state.
voidedbooleanFilter on voided state. paid=false on its own still includes voided invoices, which nobody owes; pass voided=false for outstanding.
overduebooleanOnly invoices that are past due: unpaid, not voided, and carrying a dueAt in the past. An invoice with no due date is never overdue. Matches the Overdue status of the revenue report.
limitintegerRows to return, 1,1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row , total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKThe invoices.→ { data: Invoice[] }
400Bad RequestNot your invoices, and you are not an administrator.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/invoices/orgUsers/:orgUserId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/invoices/reservation/{reservationId}

Get a reservation's invoice

The bill for one flight. Dispatchers can read this even though they cannot list the organization's invoices.

Path parameters

reservationIdrequiredintegerThe reservation id.

Responses

200OKSuccess.→ { data: Invoice }
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
404Not FoundThat flight has not been invoiced.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/invoices/reservation/:reservationId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
patch/invoices/{invoiceId}/files/{fileId}

Change an invoice's file

Its label, or who it is shown to (visibility). Requires the admin role.

Path parameters

invoiceIdrequiredintegerThe invoice id.
fileIdrequiredintegerThe file id.

Request body

The fields to change.

labelstring | null
visibility"shop" | "owner"

Responses

200OKThe file.→ { data: InvoiceFile }
400Bad RequestA field is not valid.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenNot allowed.
404Not FoundFile not found.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X PATCH https://api.aerscheduler.com/invoices/:invoiceId/files/:fileId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label":"…","visibility":"shop"}'
delete/invoices/{invoiceId}/files/{fileId}

Remove an invoice's file

It stops listing; the stored object is kept. Requires the admin role.

Path parameters

invoiceIdrequiredintegerThe invoice id.
fileIdrequiredintegerThe file id.

Responses

204No ContentSuccess. No body.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenNot allowed.
404Not FoundFile not found.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X DELETE https://api.aerscheduler.com/invoices/:invoiceId/files/:fileId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/invoices/{invoiceId}/files/from-job

Add a job's files to its invoice

Copies the work order's files onto the invoice raised for it: every one not already there, or those named in fileIds. Each keeps its label and who it is shown to. Nothing is uploaded. Requires the admin role. Refused in the demo.

Path parameters

invoiceIdrequiredintegerThe invoice id.

Request body

Which files, or none for all.

fileIdsinteger[]

Responses

201CreatedThe files added; empty when every one was already there.→ { data: InvoiceFile[] }
400Bad RequestNot a work order's invoice, or a file is not on its job.
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenNot allowed, or not this organization's.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/invoices/:invoiceId/files/from-job \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fileIds":[]}'
get/invoices/reservation/{reservationId}/invoiceTotals

Get a reservation's totals

What the flight comes to, broken down, without creating an invoice.

Path parameters

reservationIdrequiredintegerThe reservation id.

Responses

200OKSuccess.→ { data: object }
401UnauthorizedNo token, an expired token, a malformed one, or a session token naming a membership that is no longer yours ("Your session is out of date"). Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
404Not FoundNo such reservation.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/invoices/reservation/:reservationId/invoiceTotals \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"