Skip to main content
Hobbstack

Developers / API reference

Every endpoint, every field

Seven read-only operations, scoped to one organization. Here is what each one returns, what it accepts, and where its result set stops.

Before you start

The rules that apply everywhere

  • Base URL is https://api.hobbstack.com. Every path below is complete — append nothing.
  • Authentication is Authorization: Bearer hbs_pk_… on every endpoint except the calendar feed, which takes the key as a token query parameter. Without it you get 401. That query parameter is the same full key, so a feed URL is a live credential for everything the key can read — give calendar feeds their own read:reservations-only key.
  • Scope is enforced per endpoint; a valid key without the right scope gets 403 and the code INSUFFICIENT_SCOPE.
  • Organization is taken from the key. There is no org parameter, and no key can read another organization’s records.
  • Timestamps are ISO 8601 in UTC. Date-only fields are YYYY-MM-DD.
  • Nothing here writes. There is no POST, PUT, PATCH or DELETE in the public API. A leaked key is a confidentiality problem, never an integrity one — revoke it in the app.

Response shapes are documented here, not in the OpenAPI document

The handlers build plain dictionaries rather than declaring response models, so the generated OpenAPI document describes every 200 as simply “Successful Response” with no schema. The field tables below were read out of the handlers themselves. If the two ever disagree, the running API is right — please tell us and we will fix the page.

Scopes

Which scope unlocks which endpoint

ScopeEndpoints
read:reservations/reservations /reservations.ics
read:aircraft/aircraft
read:squawks/squawks
read:members/members
read:members.full/members
read:maintenance/maintenance-logs /work-orders

Full descriptions and the two things that surprise people — read:members.full not working on its own, and an empty scope list meaning read-all — are on the authentication section.

read:reservations

Reservations

GET /api/v1/external/reservations

Reservations for the key's organization, newest start time first, with optional filters and a cursor. Soft-deleted reservations are excluded.

Response fields

FieldTypeNotes
idstring
aircraft_idstring | null
pilot_idstring | null
instructor_idstring | null
activity_typestringdual_training, solo, ground, checkride, flight_review, checkout
start_timestring | nullISO 8601, UTC
end_timestring | nullISO 8601, UTC
statusstringconfirmed, standby, completed, cancelled, no_show, expired
checked_in_atstring | nullISO 8601, UTC
completed_atstring | nullISO 8601, UTC
Example response
json
{
  "items": [
    {
      "id": "6f2f1c9e-6a3b-4a1c-9a6a-2b1f3c4d5e6f",
      "aircraft_id": "b1c2d3e4-f5a6-4718-8293-a1b2c3d4e5f6",
      "pilot_id": "11111111-2222-4333-8444-555555555555",
      "instructor_id": null,
      "activity_type": "solo",
      "start_time": "2026-08-06T14:00:00+00:00",
      "end_time": "2026-08-06T16:00:00+00:00",
      "status": "confirmed",
      "checked_in_at": null,
      "completed_at": null
    }
  ],
  "next_cursor": null
}

Result set

This is the only paginated endpoint. limit defaults to 100 and caps at 500; next_cursor is non-null whenever a full page came back. Note that the cursor filters on id while the rows are ordered by start_time descending, so paging with after alone will not walk the set in start-time order — for a reliable sweep, window with start_after / start_before and page inside each window.

read:aircraft

Aircraft

GET /api/v1/external/aircraft

Every aircraft in the organization that has not been soft-deleted. Returns a bare JSON array, not an envelope.

Response fields

FieldTypeNotes
idstring
tail_numberstring
aircraft_typestring
display_namestring | null
is_activebooleanfalse while grounded
hobbs_currentnumber | null
tach_currentnumber | null
annual_due_datestring | nullISO 8601 date
last_100hr_hobbsnumber | null
Example response
json
[
  {
    "id": "b1c2d3e4-f5a6-4718-8293-a1b2c3d4e5f6",
    "tail_number": "N172SP",
    "aircraft_type": "C172S",
    "display_name": "172SP (G1000)",
    "is_active": true,
    "hobbs_current": 4821.6,
    "tach_current": 4390.2,
    "annual_due_date": "2027-03-31",
    "last_100hr_hobbs": 4780.0
  }
]

Result set

Unpaginated — the whole fleet comes back in one array.

read:squawks

Squawks

GET /api/v1/external/squawks

Reported discrepancies for the organization, newest first. Filter by status, aircraft, or whether the squawk grounds the aircraft.

Response fields

FieldTypeNotes
idstring
aircraft_idstring
descriptionstring
severitystringminor, major, grounding
statusstringopen, in_progress, resolved, deferred
is_groundingboolean
created_atstring | nullISO 8601, UTC
resolved_atstring | nullISO 8601, UTC
Example response
json
[
  {
    "id": "9c8b7a65-4321-4fed-8cba-0987654321fe",
    "aircraft_id": "b1c2d3e4-f5a6-4718-8293-a1b2c3d4e5f6",
    "description": "Left main tire worn to cord on outboard shoulder",
    "severity": "grounding",
    "status": "open",
    "is_grounding": true,
    "created_at": "2026-08-04T18:22:10+00:00",
    "resolved_at": null
  }
]

Result set

Hard-capped at the 500 most recent squawks with no cursor. An organization with more history will silently see only that window, so filter (status, aircraft_id, is_grounding) rather than expecting the full set.

read:members

Members

GET /api/v1/external/members

Membership records for the organization. Contact details appear only when the key also carries read:members.full.

Response fields

FieldTypeNotes
user_idstring
role_idstring | null
role_namestring | null
statusstring
is_discoveryboolean
joined_atstring | nullISO 8601, UTC
emailstringread:members.full only
first_namestringread:members.full only
last_namestringread:members.full only
phonestring | nullread:members.full only
Example response
json
[
  {
    "user_id": "11111111-2222-4333-8444-555555555555",
    "role_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
    "role_name": "Member",
    "status": "active",
    "is_discovery": false,
    "joined_at": "2026-02-11T09:04:33+00:00"
  }
]

Result set

Unpaginated — every non-deleted membership in one array.

read:maintenance

Maintenance logs

GET /api/v1/external/maintenance-logs

FAR 43.9 maintenance record entries, most recent event date first. Built for audit exports.

Response fields

FieldTypeNotes
idstring
aircraft_idstring
event_typestring100hr, annual, oil_change, ad, other
event_datestring | nullISO 8601 date
hobbs_at_eventnumber | null
tach_at_eventnumber | null
ap_cert_numberstring | null
ia_cert_numberstring | null
ia_namestring | null
ia_sign_offstring | null
return_to_serviceboolean | null
performed_by_namestring | null
performed_by_cert_numberstring | null
performed_atstring | nullISO 8601, UTC
last_100hr_hobbsnumber | null
annual_due_datestring | nullISO 8601 date
work_performedstringtruncated to the first 1000 characters
Example response
json
[
  {
    "id": "3d3d3d3d-1111-4222-8333-444444444444",
    "aircraft_id": "b1c2d3e4-f5a6-4718-8293-a1b2c3d4e5f6",
    "event_type": "100hr",
    "event_date": "2026-07-28",
    "hobbs_at_event": 4780.0,
    "tach_at_event": 4351.4,
    "ap_cert_number": "3512345",
    "ia_cert_number": null,
    "ia_name": null,
    "ia_sign_off": null,
    "return_to_service": true,
    "performed_by_name": "R. Alvarez",
    "performed_by_cert_number": "3512345",
    "performed_at": "2026-07-28T22:10:00+00:00",
    "last_100hr_hobbs": 4780.0,
    "annual_due_date": "2027-03-31",
    "work_performed": "Performed 100-hour inspection per Cessna 172S maintenance manual..."
  }
]

Result set

Hard-capped at the 500 most recent entries with no cursor. Filter by aircraft_id for a complete per-aircraft history.

read:maintenance

Work orders

GET /api/v1/external/work-orders

Open and historical work orders for the organization, newest first.

Response fields

FieldTypeNotes
idstring
aircraft_idstring
titlestring | null
work_typestring | null
statusstringopen, in_progress, completed, cancelled
ap_signer_idstring | null
ia_signer_idstring | null
created_atstring | nullISO 8601, UTC
completed_atstring | nullISO 8601, UTC
Example response
json
[
  {
    "id": "7e7e7e7e-8888-4999-8aaa-bbbbbbbbbbbb",
    "aircraft_id": "b1c2d3e4-f5a6-4718-8293-a1b2c3d4e5f6",
    "title": "Replace left main tire",
    "work_type": "unscheduled",
    "status": "open",
    "ap_signer_id": null,
    "ia_signer_id": null,
    "created_at": "2026-08-04T18:40:02+00:00",
    "completed_at": null
  }
]

Result set

Hard-capped at the 500 most recent work orders with no cursor. Filter by status to narrow.

read:reservations

Reservation calendar feed

GET /api/v1/external/reservations.ics

The same reservations as an iCalendar feed, so a member can subscribe in Apple Calendar, Google Calendar or Outlook. Authenticated with the key in the URL because no calendar client sends an Authorization header on a subscription URL. Returns text/calendar, not JSON.

Mint a read:reservations-only key for calendar feeds

The token in this URL is a full API key, not a feed-only token. Anyone who has the URL has everything that key can read — member email addresses and phone numbers if it carries read:members.full, and every endpoint in the API if it was created with no scopes ticked. Create a dedicated key with read:reservations and nothing else for calendar subscriptions, and never paste a broad key into a calendar client. If a feed URL is ever shared or screenshotted, revoke that key rather than editing the subscription: the URL is already in the calendar provider's subscription record and in browser history, and revoking is the only thing that takes it out of service.

Response fields

FieldTypeNotes
UIDstringhbs-resv-<reservation id>@hobbstack.com
DTSTART / DTENDstringUTC basic format, e.g. 20260806T140000Z
SUMMARYstringaircraft id followed by the activity type
STATUSstringthe reservation status, upper-cased
Example response
ics
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Hobbstack//External API//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
UID:hbs-resv-6f2f1c9e-6a3b-4a1c-9a6a-2b1f3c4d5e6f@hobbstack.com
DTSTART:20260806T140000Z
DTEND:20260806T160000Z
SUMMARY:b1c2d3e4-f5a6-4718-8293-a1b2c3d4e5f6 solo
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR

Result set

The 500 most recent reservations by start time. Reservations missing a start or end time are skipped.

Want the machine-readable version?

The OpenAPI document is served without authentication, so any code generator can read it directly: https://api.hobbstack.com/api/v1/external/openapi.json