Skip to content
Get started

SDKs & API

The f69 edge API is what your application calls at request time. It is the only HTTP surface external code is expected to use - workspace and flag management happens in the dashboard.

Edge requests authenticate with a service-account bearer token of the shape xxxxxxxx@f69:<uuid>.<secret>. Mint one from the dashboard; the plaintext token is shown once at creation and stored as an Argon2 hash, so if you lose it, mint a new one.

Every token is bound to exactly one environment for its lifetime, and has one of two roles:

  • reader - may evaluate flags.
  • writer - may evaluate flags and identify entities.

Send the token as a standard bearer header:

Authorization: Bearer xxxxxxxx@f69:<uuid>.<secret>

Upserts an entity row keyed (environment, type, external_id). The environment is implicit (it comes from the token); do not send it in the body.

POST /v1/identify
Authorization: Bearer xxxxxxxx@f69:<uuid>.<secret>
Content-Type: application/json
{
"type": "user",
"external_id": "u-alice",
"attributes": {
"country": "NG",
"plan": "pro"
}
}

Constraints:

  • type: 1 - 128 characters.
  • external_id: 1 - 512 characters.
  • attributes: a JSON object; fully replaces the stored attributes on upsert.

Identify requires a writer token. Reader tokens are evaluation-only.

Evaluates one or more flags for a previously-identified entity.

POST /v1/evaluate
Authorization: Bearer xxxxxxxx@f69:<uuid>.<secret>
Content-Type: application/json
{
"id": "u-alice",
"type": "user",
"keys": ["new-checkout", "promo-banner"]
}

Body:

  • id: the same external_id you passed to identify.
  • type: the same entity kind.
  • keys (optional): omit or set to null to evaluate every flag in the project, sorted by feature key. If supplied, must be a non-empty array of feature keys (duplicates dropped, evaluated in first-seen order). keys: [] returns 400; an unknown key returns 404.

Response is a JSON array:

[
{
"key": "new-checkout",
"value": true,
"reason": "TARGETING_MATCH",
"version": "live"
},
{
"key": "promo-banner",
"value": false,
"reason": "DEFAULT",
"version": "live"
}
]

reason is one of TARGETING_MATCH, SPLIT, DEFAULT, FALLBACK, ERROR. version is the manifest version string echoed back to the caller.

Evaluation reads attributes from the stored entity row, not from the request - so identify whenever an entity’s traits change, not on every evaluate.

StatusMeaning
400Empty keys array or malformed body
401Token missing, malformed, or token_reissue_required
403Reader token attempting identify
404Entity never identified in the token’s environment, or unknown flag key

There is no official SDK package yet - call the JSON endpoints directly or wrap them in a thin internal client. The same Rust evaluator that powers edge is published as a library if you need fully offline evaluation; that is the path SDKs will use as they land.

const F69_TOKEN = process.env.F69_TOKEN!;
const F69_EDGE = process.env.F69_EDGE_URL!;
export async function evaluate(
id: string,
type: string,
keys?: string[],
): Promise<Record<string, boolean>> {
const res = await fetch(`${F69_EDGE}/v1/evaluate`, {
method: 'POST',
headers: {
authorization: `Bearer ${F69_TOKEN}`,
'content-type': 'application/json',
},
body: JSON.stringify({ id, type, keys }),
});
if (!res.ok) throw new Error(`f69 evaluate ${res.status}`);
const results = (await res.json()) as Array<{
key: string;
value: boolean;
}>;
return Object.fromEntries(results.map((r) => [r.key, r.value]));
}

Always treat a non-200 from f69 as fail-closed: route past the flag to its known-safe default rather than throwing into the request path.