Skip to content

Bills

Role names and user_group_id values are listed in User groups.

Billing and wallet management. Requires a non-free company plan. Pilots need billing: true on their user record to appear in billing operations.


GET /bills/index.json

GET /bills/index/{userId}.json

GET /bills/index/{userId}/{offset}.json

List wallet movement records for a pilot. Managers can view any pilot’s bills; regular users (user_group_id ≥ 150 — Chief Pilot and below) see only their own. Linked flight info is included unless the flight’s status is CANCELED or DELETED.

Parameter Type Description
limit number Records per page (default: 10)
{
"bills": [
{
"UserBill": {
"id": "xyz789",
"user_id": "100",
"company_id": "42",
"flight_id": "5678",
"name": "2025-01-10 LEBL-LEMD",
"price": "-120.00",
"total": "-120.00",
"receipt": false,
"created": "2025-01-10 15:00:00"
},
"Flight": {
"callsign": "EC-ABC",
"rules": "IFR",
"offblocks_time": "1736505000",
"block_time": "6900",
"deleted": false
}
}
],
"total": 42
}

GET /bills/view/{id}.json

Full detail for a single bill including client info, company billing settings, and linked flight. Access does not require authentication (allowed in beforeFilter).

Parameter Type Description
id UUID Bill ID
{
"bill": {
"UserBill": {
"id": "xyz789",
"n_id": 12,
"name": "2025-01-10 LEBL-LEMD",
"price": -120.00,
"price_hour": -60.00,
"airport": 0.0,
"fuel": 0.0,
"handling": 0.0,
"others": 0.0,
"collected_tax": 0.0,
"subtotal": -120.00,
"total": -120.00,
"packaged": 0.0,
"packaged_time": 0.0,
"billed_time": 2.0,
"balance": -120.00,
"receipt": false
},
"Flight": {
"date": "2025-01-10",
"callsign": "EC-ABC",
"departure_airport": "LEBL",
"landing_airport": "LEMD",
"flight_time": "6900",
"block_time": "6900",
"rules": "IFR",
"landings": 1
},
"Client": {
"id": "100",
"UserDetail": { "name": "John", "surname": "Doe", "passport": "AB123456", "phone": "+34600000000", "address": "...", "city": "Barcelona", "pc": "08001", "Country": { "name": "Spain" } },
"Company": {
"name": "My FTO",
"CompanyDetail": { "Country": { "name": "Spain" } },
"CompanyBillingSetting": { "tax": "21", "billed_person": "pilot", "send_notification": true }
}
},
"Creator": {
"id": "50",
"UserDetail": { "name": "Admin", "surname": "User" }
},
"UserBillPackageFlight": []
}
}

UserBill.n_id is the bill number. Flight bills and manual bills (flight_id empty) each have their own sequence per company. By default a sequence is consecutive and continues after the most recently created bill of its kind. Companies that enable yearly reset restart it every 1 January and store the year in UserBill.n_year (shown as 2026/1). n_id is null for transactions saved without a number. Bills created before October 2026 keep their old number, which may repeat across years; older bills without a number can be numbered by editing them with assign_number.


GET /bills/next_number.json?created={unix}

The bill number the next bill would receive, so a form can show it before saving. created (Unix timestamp, optional) is the bill date; it decides the year when the company restarts numbering yearly. Restricted to user_group_id ≤ 145. The value is informational: the number is assigned when the bill is saved, so another bill saved in between takes it.

{ "next": { "n_id": 505, "n_year": null } }

n_year is null unless the company restarts numbering every year.


POST /bills/create.json

Create a manual wallet transaction for one or more pilots. If id is provided, updates an existing record. user_id can be a single UUID, an array of UUIDs, or a pilot group UUID (group members are expanded automatically). Restricted to user_group_id ≤ 145 (Flight Dispatcher and above).

Field Type Required Description
user_id string | array Yes (new) Pilot UUID(s) or pilot group UUID
price number Yes (new) Amount (negative = charge, positive = credit)
name string Yes Transaction description
created string No Transaction date (defaults to now)
receipt boolean No Send the receipt notification to the user. It does not control numbering
assign_number boolean No Give the bill a bill number (n_id). false/0 stores it without number and removes an existing one. When omitted, the bill is numbered
id UUID No Existing bill ID to update
{
"result": true,
"new": true,
"UserBills": [
{
"id": "xyz789",
"user_id": "100",
"name": "Manual adjustment",
"price": "-50.00",
"creator": "Admin User",
"client": "John Doe"
}
],
"errors": []
}

GET /bills/flight.json?id={flightId}

POST /bills/flight.json?id={flightId}

Retrieve flight billing data (GET) or create/update a flight bill (POST). Flight must be confirmed (status = LANDED).

Parameter Type Description
id UUID Flight ID
Field Type Required Description
user_id UUID Yes Pilot to bill
price_hour number Yes Hourly rate
price number Yes Total flight price
airport number No Airport fees
fuel number No Fuel charges
handling number No Handling charges
others number No Other charges
rate_id UUID No Rate record to use
notify boolean No Send notification email to pilot
use_packages boolean No Deduct from pilot’s package balance
created string No Bill date (defaults to onblocks_time)
{
"defaults": { "tax": "21", "default_airport": "0", ... },
"payment": { "UserBill": { ... } },
"flight": { "Flight": { ... }, "Aircraft": { ... }, "UserBill": { ... } },
"errors": null
}

POST /bills/delete.json

Delete a bill and recalculate the pilot’s balance.

Field Type Required Description
bill UUID Yes Bill ID to delete
{
"result": true,
"balance": -240.00,
"bill": { "UserBill": { "id": "xyz789", "name": "...", "total": "-120.00" } }
}

GET /bills/autobill/{flightId}.json

GET /bills/autobill/{flightId}/{userId}.json

POST /bills/autobill.json

Automatically generate a bill for a flight using the aircraft’s default rate. Any existing bill for the flight is replaced. Optionally override which pilot to bill.

Field Type Required Description
flight UUID Yes Flight ID
user UUID No Override pilot to bill
{
"bill": { "UserBill": { ... } }
}

GET /bills/balance.json

GET /bills/balance/{userId}.json

Returns the current wallet balance for a pilot. Managers can query any billable pilot. Regular users see only their own balance.

{
"balance": -240.50
}

GET /bills/pay.json

POST /bills/pay.json

Initiate a Stripe Checkout session to allow a pilot to pay their balance. Requires Stripe to be enabled and configured for the company.

Field Type Required Description
amount number No Amount to pay (defaults to current balance)
{
"result": true,
"message": "Payment intent created, redirecting to Stripe checkout.",
"redirect_url": "https://checkout.stripe.com/..."
}

GET /bills/checkout/{token}.json

Process a completed Stripe Checkout session. Called automatically via the Stripe success_url redirect. Verifies payment status, records the credit, and notifies company managers.

Parameter Type Description
token string Stripe Checkout session ID
{
"result": true,
"message": "Payment received, thank you!"
}

GET /bills/download.json

GET /bills/download/{userId}.json

Download all bills as an Excel file. Regular users see only their own. Requires token query param.


GET /bills/rates.json

GET /bills/rates/true.json

List all billing rates for the company. Pass true to return only package rates.

{
"rates": [
{
"Rate": {
"id": "r1",
"company_id": "42",
"name": "C172 Standard",
"hourly_price": "120.00",
"pack": false,
"deleted": false
},
"Aircraft": [
{ "id": "45", "registration": "EC-ABC" }
]
}
]
}

GET /bills/rate/{id}.json

Retrieve a single rate with linked aircraft.


GET /bills/aircraft/{aircraftId}.json

List all rates configured for a specific aircraft.


GET /bills/packages/{userId}.json

GET /bills/packages/{userId}/true.json

List flight-hour packages for a pilot. Pass true to return only valid packages (non-expired with remaining balance).

{
"packages": [
{
"UserBillPackage": {
"id": "pkg1",
"user_id": "100",
"total": "50.00",
"balance": "32.50",
"expiration": "2026-12-31",
"created": "2025-01-01 10:00:00"
},
"Rate": [{ "id": "r1", "name": "C172 Standard", "hourly_price": "120.00" }]
}
]
}

GET /bills/package/{id}.json

Full details for a package including the pilot, creator, linked rate, bills, and associated flights.


POST /bills/manager_purchase_package.json

Create or update a flight-hour package for a pilot. Optionally creates a debit bill for the package cost.

Field Type Required Description
user_id UUID Yes (new) Pilot to assign the package to
rate_id array Yes Array of rate UUIDs to include
total number Yes Total hours in the package
id UUID No Existing package ID to update
expiration string | timestamp No Package expiry date
bill string No 1 to also create a debit bill for the package cost
{
"new": true,
"package": { "UserBillPackage": { "id": "pkg1", "balance": "50.00", ... } },
"bill": "xyz789",
"errors": null
}

POST /bills/manager_delete_package.json

Delete a package and its associated bill (if any). Recalculates the pilot’s balance.

Field Type Required Description
id UUID Yes Package ID

GET /bills/manager_index.json

GET /bills/manager_index/{type}.json

Paginated list of all company bills. type is transactions (default, every non-flight bill), unnumbered (non-flight bills without a bill number), numbered (non-flight bills with a bill number) or flights (flight-linked bills). The manager Bills page uses its tabs Transactions = unnumbered, Bills = numbered and Flights = flights.

Parameter Description
from Start date filter
to End date filter
pilot Filter by pilot user ID
excel Append excel:true for XLS download (requires token)

GET /bills/manager_stats/{type}.json

POST /bills/manager_stats/{type}.json

Aggregated stats over the full filtered set (not paginated). Same type and filters as manager_index — from, to, pilot. Filters can be sent as POST body or query string. Designed to be fetched in parallel with the first page of manager_index and refetched on every filter change. Charts read from this response, not from the paginated bill list.

type: transactions (default, flight_id = ''), unnumbered (flight_id = '' and no n_id), numbered (flight_id = '' and n_id > 0) or flights (flight_id <> '').

totalSeconds is SUM(billed_time) * 3600 (billed_time stored as hours). topClients returns up to 10 entries ordered by ABS(SUM(total)) desc.

Parameter Description
from Start date (anything strtotime accepts)
to End date (anything strtotime accepts)
pilot Filter by pilot user ID
{
"stats": {
"type": "transactions",
"count": 1842,
"total": 125430.55,
"avg": 68.10,
"positive": 145200.00,
"negative": -19769.45,
"totalSeconds": 0,
"monthly": [
{
"month": "2026-01",
"count": 312,
"total": 21500.00,
"positive": 24000.00,
"negative": -2500.00,
"totalSeconds": 0
}
],
"topClients": [
{
"user_id": "100",
"name": "John Doe",
"count": 87,
"total": 9420.00,
"totalSeconds": 0
}
]
}
}

For type=flights, totalSeconds reflects flight billed time across the filtered set.


GET /bills/manager_pilots.json

GET /bills/manager_pilots/{aircraftId}.json

List all active, non-deleted pilots with billing: true. If an aircraft ID is provided, also returns each pilot’s configured hourly price for that aircraft.

{
"pilots": [
{ "id": "100", "name": "John Doe", "group": "170", "groupname": "Pilot", "price": "120.00" }
]
}

GET /bills/manager_packages.json

Paginated list of all packages across all company pilots.


GET /bills/manager_flights.json

Paginated list of flights on billing-enabled aircraft. Supports named parameter filters:

Named Param Description
pilot Filter by PIC or SIC user ID
status billed or notbilled
base Filter by base ID
flight_type Filter by flight type ID
flight_rules Filter by rules (IFR, VFR)
from Filter from date
to Filter to date
excel Append excel:true for XLS download

POST /bills/manager_rate_edit.json

Create or update a billing rate and assign aircraft.

Field Type Required Description
Rate.id UUID No Existing rate ID to update
Rate.name string Yes Rate name
Rate.hourly_price number Yes Price per hour
Rate.pack boolean No Is this a package rate
Rate.aircraft_id array No Aircraft UUIDs to link

POST /bills/manager_rate_delete.json

Soft-delete a rate and remove all aircraft-rate associations.

Field Type Required Description
rateId UUID Yes Rate ID to delete