Looking for the full interactive reference?
Open API Reference →Recipe
Accounting export
Export approved flights and invoices on a nightly cron into a generic accounting backend. Suitable when your destination system has a journal-entry API and you control the chart-of-accounts mapping.
Scopes needed
| Scope | Why | Alternative if too broad |
|---|---|---|
| public.flights:read | List approved flights for the export window. | None — required. |
| public.invoices:read | Pull line-item detail for posting against the GL. | Use public.finance:read for summaries only. |
| public.finance:read | Per-period rollups for reconciliation against your books. | Skip if your reconciliation is per-invoice. |
Data flow
┌───────────────┐ ┌─────────────────┐ ┌────────────────┐
│ Nightly cron │ ──▶ │ GET flights+inv │ ──▶ │ Map to GL chart│
└───────────────┘ └─────────────────┘ └───────┬────────┘
│
▼
┌──────────────────────┐
│ POST to your backend │
│ (idempotency-keyed) │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Mark exported in DB │
└──────────────────────┘Implementation
1. Bootstrap — list the records in the export window:
# List approved flights for the window
curl "https://api.gaflight.io/api/v1/public/flights?status=approved&from=2026-05-01&to=2026-05-31&limit=200" \
-H "Authorization: Bearer gaf_pk_<token>" \
-H "X-Org-Id: <org-uuid>"
# Pagination continues with the cursor returned in the response envelope:
# { "data": [...], "cursor": "eyJp..." }2. Enrich — map invoice line items to your chart of accounts:
// Pseudo-code — your service maps GA Flight invoices to your chart-of-accounts.
function toJournalEntry(invoice) {
return {
externalId: `gaflight:${invoice.id}`, // idempotency key
date: invoice.issuedAt,
lines: invoice.lineItems.map(line => ({
account: mapAccount(line.category), // your mapping
debit: line.totalCents,
currency: invoice.currency,
memo: line.description,
})),
};
}3. Close-loop — reverse the journal entry if the invoice is voided after export:
// Webhook handler — fires when an invoice is voided after export.
app.post("/webhooks/gaflight", verifyHmac, (req, res) => {
const { type, data } = req.body.event;
if (type === "compliance.updated" && data.kind === "invoice_voided") {
yourBackend.reverseJournal(`gaflight:${data.invoiceId}`);
}
res.status(204).end();
});Edge cases
- Voided invoices: subscribe to compliance.updated and reverse the journal entry by idempotency key.
- Multi-currency: invoice.currency is per-invoice; do not assume a single org currency.
- FX rate dating: use invoice.issuedAt (not your sync timestamp) as the FX reference date.
- Refund flow: refunds appear as negative-amount line items, not separate invoices.
- Period-close lock: after your books close, only post into the next period; bounce older invoices to a manual queue.
- Pagination cursors: cursors are opaque; do not parse or store them past the run that issued them.
- Rate limits: cap concurrency at 4 parallel requests; the rate-limit window is 60s.
Going live
- Declare the three scopes above on your developer app with ≥40-char justifications each.
- Submit your listing for review (see /developers/review-policy).
- Publish under your org and share the install URL with customer organizations.
- Schedule the cron in your control plane; alert on consecutive failures.
- Document the FX rate source and period-lock rule in your customer-facing runbook.
Generic template