API

Getting started with the FFxF API

Create a key, order an hourly machine and drive it from your own code, in four calls.

The API does from your code what you do in the console: order a machine, boot it, reinstall it, destroy it. It takes exactly the same path: same quotas, same credit, same refusals. If the console says no, the API says no, for the same reason.

This guide goes from an empty account to a running machine, in four calls.

1. Create a key

In the console, Account → API keys. Name it after what it does (CI runners, monitoring) and tick only the scopes that tool needs. A key that merely watches has no business holding the right to destroy.

The token is shown once. We keep only its fingerprint: lose it and you revoke it and make another. It cannot be recovered.

2. The first call

Check the key against your own account. This is also the response to read before any order: it says what you can spend.

bash
curl -s https://api.ffxf.net/v1/account \
     -H "Authorization: Bearer $FFXF_TOKEN"
bash
{
  "data": {
    "currency": "CAD",
    "credit": { "balance": "124.60" },
    "hourly": { "burn_rate": "0.069", "runway_hours": 1805.8, "active_machines": 3 },
    "quota": { "limit": 5, "used": 3, "remaining": 2 }
  }
}

burn_rate is what your fleet spends per hour, runway_hours how long that lasts at the current balance. A script watching those two numbers is never surprised.

3. Pick from the catalogue

Regions, plans and images are readable without a key: you can write your script before you even have an account.

bash
curl -s https://api.ffxf.net/v1/images?plan=nano | jq '.data[].slug'

The ?plan= filter keeps only the images that fit: on the Nano's 20 GB, a Windows image asking for 32 is simply absent from the list, rather than failing at order time.

4. Order a machine

Start with a dry run. dry_run runs every check (quota, credit, stock, compatibility) and prices the order without creating anything.

bash
curl -s https://api.ffxf.net/v1/vms \
     -H "Authorization: Bearer $FFXF_TOKEN" \
     -H "Idempotency-Key: $(uuidgen)" \
     -H "Content-Type: application/json" \
     -d '{"plan":"nano","region":"montreal","image":"debian-13",
          "hostname":"runner-01","billing":"hourly","dry_run":true}'
bash
{
  "data": {
    "would_succeed": true,
    "hourly_rate": "0.018",
    "month_equivalent": "13.14",
    "required_credit": "0.44",
    "balance": "124.60",
    "runway_hours_after": 1428.0,
    "checks": [ { "name": "quota", "status": "pass" }, { "name": "credit", "status": "pass" } ]
  }
}

required_credit is 24 hours of usage here: that is the advance an hourly rental asks for. Drop dry_run and the machine goes into build.

The Idempotency-Key header is required, and it is not a formality: if your request times out with no answer, replaying it with the same key returns the first response instead of creating a second machine.

5. Follow the build

The response carries the machine and an action. Nothing is instant: a disk is cloned, an address reserved, an image booted.

bash
curl -s https://api.ffxf.net/v1/actions/90112 \
     -H "Authorization: Bearer $FFXF_TOKEN" | jq .data.status

Poll until the status leaves running. On failure the action carries the reason: no guessing through logs.

6. Destroy

bash
curl -s -X DELETE "https://api.ffxf.net/v1/vms/4312?confirm=runner-01" \
     -H "Authorization: Bearer $FFXF_TOKEN"

The hostname must be repeated in confirm. An id mispasted in a loop would destroy the wrong machine, and a disk does not come back. Hourly deletion is immediate, the hour under way is owed, and the meter stops with the machine.

Support & discussions

Technical questions, incident reports, or infrastructure discussions, the team is reachable on Discord, Telegram, X, Instagram, Reddit, and IRC.