Looking for the full interactive reference?
Open API Reference →Quickstart
Five minutes to your first authenticated API call and signed webhook delivery. Walks through creating a developer app in the console, declaring scopes, installing on your test org, calling the API in three languages, and verifying a webhook signature.
Step 1
Create a developer app
Builder actions all happen inside the GA Flight console. Sign in as a user with the developer.app:manage permission and create your first app. Pick a name that maps to your integration; you can change it later. The app starts in draft and needs activation before it can mint credentials.
In the console
Step 2
Declare scopes
Scopes declared on the app form the upper bound for any addon listing backed by it. v2.1 is read-only; declare only the public.* scopes you genuinely need. Each scope requires a justification of at least 40 characters — the review policy enforces it. See the scope catalog for the full list of 13 scopes.
# In the console at Settings -> Developers -> Apps -> {your-app},
# add each scope and a justification (>= 40 chars).
required_scopes:
- public.pilots:read # justification: read pilot directory for analytics dashboard
- public.flights:read # justification: list approved flights for monthly export job
- public.events:read # justification: subscribe to event log for webhook-replay UXStep 3
Install on your test org
Dogfood your own listing by installing it on your test organization before publishing publicly. The install flow shows the consumer-side consent modal, then reveals plaintext-once credentials. Capture both the api_key and the webhook signing secret immediately — neither can be read back. See Apps → debugging for revocation and rotation.
In the console
Step 4
Call the API
Use the API key from step 3 to make your first authenticated request. The auth model is simple: a bearer header plus an X-Org-Id header on every request. Three equivalent examples follow — pick the stack closest to your runtime.
cURL — minimal smoke test:
curl https://api.gaflight.io/api/v1/public/pilots \ -H "Authorization: Bearer gaf_pk_<your-token>" \ -H "X-Org-Id: <your-organization-uuid>"
TypeScript / Node 18+ (no SDK required):
// Node 18+ (global fetch). No SDK required.
const res = await fetch(
"https://api.gaflight.io/api/v1/public/pilots",
{
headers: {
Authorization: `Bearer ${process.env.GAFLIGHT_API_KEY}`,
"X-Org-Id": process.env.GAFLIGHT_ORG_ID,
},
},
);
const body = await res.json();
console.log(body.data.length, "pilots");Python 3.10+ with requests:
import os, requests
resp = requests.get(
"https://api.gaflight.io/api/v1/public/pilots",
headers={
"Authorization": f"Bearer {os.environ['GAFLIGHT_API_KEY']}",
"X-Org-Id": os.environ["GAFLIGHT_ORG_ID"],
},
timeout=10,
)
resp.raise_for_status()
print(len(resp.json()["data"]), "pilots")Step 5
Receive and verify a webhook
Webhook endpoints subscribe to a list of event types and receive HMAC-signed deliveries. Verify the signature on every request before processing — the secret was revealed plaintext-once during install. Replays carry the same delivery ID so your handler must be idempotent.
Declare the endpoint in the consumer console:
# Webhook endpoints are created from the consumer console at # Settings -> Integrations -> Webhooks. The signing secret is shown # plaintext-once when the endpoint is created. # Endpoint: https://your-app.example.com/webhooks/gaflight # Event types: flight.approved, flight.submitted, webhook.test # Active: true
Node.js verification handler with Express:
// Node 18+. Verify HMAC before processing.
const crypto = require("crypto");
function verify(rawBody, headerSig, secret) {
const expected =
"sha256=" + crypto.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(headerSig),
);
}
// In your Express handler — keep the raw body around.
app.post("/webhooks/gaflight",
express.raw({ type: "application/json" }),
(req, res) => {
const sig = req.header("X-GA-Webhook-Signature");
if (!sig || !verify(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).end();
}
const event = JSON.parse(req.body.toString("utf8"));
// ... your handler
res.status(204).end();
});Python verification helper:
# Python 3.10+. Verify HMAC before processing.
import hmac, hashlib
def verify(raw_body: bytes, header_sig: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode("utf-8"),
raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, header_sig)Next