Met de FixControl Public API kun je vanuit je eigen tools FixControl uitlezen en aansturen — een eigen dashboard, een PM-script, een interne automatisering. Het basispad is /api/public/v1/ op je FixControl-host.
Een API-key aanmaken
- Open Settings → Integraties → Publieke API.
- Klik Key aanmaken.
- Geef hem een naam (zodat je hem terug kunt vinden) en kies scopes — zie hieronder.
- Klik Aanmaken. De volledige token wordt één keer getoond. Zet hem direct in je secret manager.
De UI bewaart de prefix (fck_live_a1b2…) en de aanmaaktijd zodat je de key later kunt herkennen, maar de volledige token is niet terug te halen. Kwijt? Trek 'm in en maak een nieuwe aan.
Scopes
Een key draagt één of meer scopes. Kies de kleinste set die het werk doet.
| Scope | Endpoints |
|---|---|
issues:read | GET /api/public/v1/issues, GET /api/public/v1/issues/:key |
issues:write | POST /api/public/v1/issues |
patches:read | GET /api/public/v1/patches, GET /api/public/v1/patches/:id |
patches:write | gereserveerd voor toekomstige write-acties op patches — vandaag geen endpoints |
integrations:read | GET /api/public/v1/integrations/status |
webhooks:read | GET /api/public/v1/webhooks |
webhooks:write | POST /api/public/v1/webhooks |
Een key zonder scopes kan zich wel authenticeren, maar elke geautoriseerde endpoint geeft 403 met code: insufficient_scope.
Authenticatie
Elke request heeft een Authorization: Bearer <token>-header nodig. De token is gebonden aan één tenant — er is geen aparte tenant-querystring of body-veld; de tenant wordt afgedwongen vanuit de key.
curl https://<jouw-host>/api/public/v1/issues \
-H "Authorization: Bearer fck_live_a1b2c3d4..."Een ontbrekende token geeft 401 met code: missing_token. Een ongeldige of ingetrokken token geeft 401 met code: invalid_token. Een geldige token zonder de juiste scope geeft 403 met code: insufficient_scope.
Rate limits
Elke key heeft een token-bucket-budget van 60 requests per minuut (1 token per seconde nominaal, met een burst van 60). De bucket is per-key, dus twee keys in dezelfde tenant delen geen budget.
Bij overschrijding krijg je 429 Too Many Requests met Retry-After in seconden en code: rate_limited. Heb je voor een legitieme use-case meer ruimte nodig, neem contact op.
Endpoints
Issues
# Recente issues opvragen (tenant van de key)
GET /api/public/v1/issues
→ { "items": PublicIssue[] }
# Eén issue ophalen op key
GET /api/public/v1/issues/:key
→ PublicIssue
# Een issue aanmaken
POST /api/public/v1/issues
{
"title": "Checkout faalt op mobiel",
"kind": "BUG",
"priority": "high",
"reporter": "alex@acme.com",
"summary": "Optionele samenvatting",
"body": "Optionele lange beschrijving",
"customer": "Optionele klantnaam",
"flags": ["payment"],
"assignee": "Optionele interne id"
}
→ 201 Created → PublicIssuePublicIssue bevat: key, tenant, kind, title, summary, body, priority, status, readiness, confidence, flags, reporter, assignee, customer, createdAt, updatedAt, externalTracker, externalKey, externalUrl, externalStatus.
Patches
# Patches lijsten (nieuwste eerst)
GET /api/public/v1/patches?limit=100 # limit: 1..200
→ { "items": PublicPatch[] }
# Eén patch ophalen
GET /api/public/v1/patches/:id
→ PublicPatchPublicPatch draagt patch-id, workspace-id, versie, status, aantal bestanden, additions/deletions, bestandslijst en timestamps.
Integraties
GET /api/public/v1/integrations/status
→ { "items": [
{ "id": "...", "type": "github", "name": "...", "status": "connected",
"provider": "github", "authKind": "app",
"createdAt": "...", "lastError": null },
...
] }Geen tokens, refresh-tokens, installation-id's of recipient-routingregels in het antwoord — alleen de publiek-veilige samenvatting.
Webhooks
# Uitgaande webhooks lijsten
GET /api/public/v1/webhooks
→ { "items": PublicWebhook[] }
# Aanmaken — geeft het plaintext-secret PRECIES ÉÉN keer terug.
POST /api/public/v1/webhooks
{
"name": "Billing notifier",
"url": "https://hooks.acme.com/fc",
"events": ["issue.created", "patch.approved"],
"enabled": true
}
→ 201 Created → { "webhook": PublicWebhook, "secret": "ws_AB3cD..." }Geldige event-waarden: issue.created, issue.updated, patch.ready, patch.approved, patch.failed, pr.created, integration.error. Zie de webhooks-handleiding voor het delivery-formaat en de signature.
Error-responses
Elke fout geeft JSON in dit formaat:
{ "error": "Leesbare melding", "code": "stabiele_machine_code" }De HTTP-status geeft de categorie; code is de stabiele identifier voor je client-logica.
| Status | code-voorbeelden |
|---|---|
| 400 | missing_field, invalid_field, invalid_url, invalid_events, invalid_body |
| 401 | missing_token, invalid_token |
| 403 | insufficient_scope |
| 404 | not_found |
| 429 | rate_limited (met Retry-After-header) |
| 5xx | internal_error |
OpenAPI
De OpenAPI 3.1-spec wordt geserveerd op:
GET /api/public/v1/openapi.jsonDat is de bron van de waarheid — laat je codegenerator hierop wijzen. De docs volgen de spec.
Best practices
- Behandel de token als een wachtwoord. Nooit committen, nooit in logs printen.
- Eén key per integratie. Makkelijker te roteren, te auditen en te scopen.
- Roteer regelmatig. Maak de nieuwe key, switch je client, trek dan pas de oude in.
- Webhooks boven polling. Abonneer een uitgaande webhook in plaats van
GET /issueste pollen. - Behandel 429 met backoff. Honoreer de
Retry-After-header in plaats van direct opnieuw te proberen.
Veelgestelde vragen
Is de API hetzelfde als de interne API van het dashboard? Nee. Het dashboard praat met interne routes die een session-cookie nodig hebben en niet stabiel zijn. De Public API op /api/public/v1/... is wat we committen — geversioneerd en met OpenAPI-spec.
Kan een key meerdere tenants benaderen? Nee. Keys zijn per ontwerp tenant-gescoped.
Wat als een key lekt? Trek hem direct in via Settings → Integraties → Publieke API. Intrekken is direct — in-flight requests met de oude key krijgen binnen seconden 401. Check daarna de audit-log voor activiteit met die key.