Bills
Role names and
user_group_idvalues 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.
List Bills (Pilot Wallet)
Section titled “List Bills (Pilot Wallet)”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.
Query Parameters
Section titled “Query Parameters”| Parameter | Type | Description |
|---|---|---|
| limit | number | Records per page (default: 10) |
Response
Section titled “Response”{ "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}View Bill
Section titled “View Bill”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).
Path Parameters
Section titled “Path Parameters”| Parameter | Type | Description |
|---|---|---|
| id | UUID | Bill ID |
Response
Section titled “Response”{ "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.
Next Bill Number
Section titled “Next Bill 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.
Create Manual Bill
Section titled “Create Manual Bill”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).
Request Body
Section titled “Request Body”| 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 |
Response
Section titled “Response”{ "result": true, "new": true, "UserBills": [ { "id": "xyz789", "user_id": "100", "name": "Manual adjustment", "price": "-50.00", "creator": "Admin User", "client": "John Doe" } ], "errors": []}Bill a Flight
Section titled “Bill a Flight”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).
Query Parameters
Section titled “Query Parameters”| Parameter | Type | Description |
|---|---|---|
| id | UUID | Flight ID |
Request Body (POST)
Section titled “Request Body (POST)”| 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) |
Response
Section titled “Response”{ "defaults": { "tax": "21", "default_airport": "0", ... }, "payment": { "UserBill": { ... } }, "flight": { "Flight": { ... }, "Aircraft": { ... }, "UserBill": { ... } }, "errors": null}Delete Bill
Section titled “Delete Bill”POST /bills/delete.json
Delete a bill and recalculate the pilot’s balance.
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
| bill | UUID | Yes | Bill ID to delete |
Response
Section titled “Response”{ "result": true, "balance": -240.00, "bill": { "UserBill": { "id": "xyz789", "name": "...", "total": "-120.00" } }}Auto-Bill a Flight
Section titled “Auto-Bill a Flight”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.
Request Body (POST)
Section titled “Request Body (POST)”| Field | Type | Required | Description |
|---|---|---|---|
| flight | UUID | Yes | Flight ID |
| user | UUID | No | Override pilot to bill |
Response
Section titled “Response”{ "bill": { "UserBill": { ... } }}Get Pilot Balance
Section titled “Get Pilot Balance”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.
Response
Section titled “Response”{ "balance": -240.50}Create Stripe Payment Intent
Section titled “Create Stripe Payment Intent”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.
Request Body (POST)
Section titled “Request Body (POST)”| Field | Type | Required | Description |
|---|---|---|---|
| amount | number | No | Amount to pay (defaults to current balance) |
Response
Section titled “Response”{ "result": true, "message": "Payment intent created, redirecting to Stripe checkout.", "redirect_url": "https://checkout.stripe.com/..."}Complete Stripe Checkout
Section titled “Complete Stripe Checkout”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.
Path Parameters
Section titled “Path Parameters”| Parameter | Type | Description |
|---|---|---|
| token | string | Stripe Checkout session ID |
Response
Section titled “Response”{ "result": true, "message": "Payment received, thank you!"}Download Bills (XLS)
Section titled “Download Bills (XLS)”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.
List Rates
Section titled “List Rates”GET /bills/rates.json
GET /bills/rates/true.json
List all billing rates for the company. Pass true to return only package rates.
Response
Section titled “Response”{ "rates": [ { "Rate": { "id": "r1", "company_id": "42", "name": "C172 Standard", "hourly_price": "120.00", "pack": false, "deleted": false }, "Aircraft": [ { "id": "45", "registration": "EC-ABC" } ] } ]}View Rate
Section titled “View Rate”GET /bills/rate/{id}.json
Retrieve a single rate with linked aircraft.
Get Rates for Aircraft
Section titled “Get Rates for Aircraft”GET /bills/aircraft/{aircraftId}.json
List all rates configured for a specific aircraft.
List Packages (Pilot)
Section titled “List Packages (Pilot)”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).
Response
Section titled “Response”{ "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" }] } ]}View Package
Section titled “View Package”GET /bills/package/{id}.json
Full details for a package including the pilot, creator, linked rate, bills, and associated flights.
Create / Update Package
Section titled “Create / Update Package”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.
Request Body
Section titled “Request Body”| 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 |
Response
Section titled “Response”{ "new": true, "package": { "UserBillPackage": { "id": "pkg1", "balance": "50.00", ... } }, "bill": "xyz789", "errors": null}Delete Package
Section titled “Delete Package”POST /bills/manager_delete_package.json
Delete a package and its associated bill (if any). Recalculates the pilot’s balance.
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Package ID |
Manager: List All Bills
Section titled “Manager: List All Bills”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.
Named Parameters / POST Filters
Section titled “Named Parameters / POST Filters”| 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) |
Manager: Bill Stats
Section titled “Manager: Bill Stats”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.
Filters (POST body or query string)
Section titled “Filters (POST body or query string)”| Parameter | Description |
|---|---|
| from | Start date (anything strtotime accepts) |
| to | End date (anything strtotime accepts) |
| pilot | Filter by pilot user ID |
Response
Section titled “Response”{ "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.
Manager: List Billable Pilots
Section titled “Manager: List Billable Pilots”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.
Response
Section titled “Response”{ "pilots": [ { "id": "100", "name": "John Doe", "group": "170", "groupname": "Pilot", "price": "120.00" } ]}Manager: List All Packages
Section titled “Manager: List All Packages”GET /bills/manager_packages.json
Paginated list of all packages across all company pilots.
Manager: Billable Flights
Section titled “Manager: Billable Flights”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 |
Manager: Create / Update Rate
Section titled “Manager: Create / Update Rate”POST /bills/manager_rate_edit.json
Create or update a billing rate and assign aircraft.
Request Body
Section titled “Request Body”| 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 |
Manager: Delete Rate
Section titled “Manager: Delete Rate”POST /bills/manager_rate_delete.json
Soft-delete a rate and remove all aircraft-rate associations.
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
| rateId | UUID | Yes | Rate ID to delete |