API keys
A key is a machine credential with an explicit grant: it can do exactly what it was given when it was made — nothing inherits, nothing widens later — and it is walled into its organisation the same way a signed-in person is.
Creating a key
Under Settings → API keys, name the key and tick the privileges it should
hold. You can only delegate privileges you hold yourself; the server refuses escalation
regardless of what a client sends. The token — ffk_… — is shown exactly once:
the server stores only a hash and cannot show it again.
Using it
Send the token as a bearer credential to the same API the app itself uses:
curl https://faldaro.app/api/platform/folders \
-H "Authorization: Bearer ffk_your_token_here"
Every request a key makes passes the same privilege checks and the same database-enforced
tenant isolation as a person's session. A key granted only submission:read
receives a 403 from anything that writes; a key from one organisation simply
cannot see another's rows.
Revocation
Revoking a key takes effect immediately — the next request answers 401, the
same anonymous refusal an invalid token gets. Deactivating a user also revokes the keys
they created in that organisation: a key is delegated authority, and the delegation ends
with the account. Revoked keys stay listed as history; they are never deleted.
The headless API
Two versioned endpoints exist specifically for machines, under /v1. Their
response shapes are a frozen contract: fields are added, never renamed or removed, so a
script written against them keeps working. Both require the
submission:write privilege.
Evaluate runs a payload through a form's live rules — calculated values, hidden fields, outcomes, validation problems — and stores nothing. This is the rating call: price a quote or score an intake from another system without filing anything.
curl https://faldaro.app/api/platform/v1/forms/123/evaluate \
-H "Authorization: Bearer ffk_your_token_here" \
-H "Content-Type: application/json" \
-d '{"data": {"units": 4}}'
{"valid": false,
"calculatedData": {"total": 100},
"hiddenFields": [],
"outcomes": [],
"problems": [{"field": "applicant", "message": "Applicant is required"}]}
valid answers whether the payload as a whole would be accepted — a missing
required value counts, unlike the in-app preview that runs while a form is still being
filled in.
Create files a real submission against the live version, through the same
engine the app uses: formulas re-run server-side, reference numbers allocate once, and
every configured notification, integration and document fires as authored. Pass
"draft": true to save a partial record.
curl https://faldaro.app/api/platform/v1/forms/123/submissions \
-H "Authorization: Bearer ffk_your_token_here" \
-H "Content-Type: application/json" \
-d '{"data": {"applicant": "Ada Lovelace", "units": 4}}'
Every caller has a request budget (120 per minute by default; deployments tune it). Going
over answers 429 with a Retry-After header and
"code": "RATE_LIMITED" — back off for that many seconds and continue. The
budget is counted per key, so one integration exhausting its window never slows another.
Practice worth copying
- One key per system, named for it — a leaked key should implicate one integration.
- Grant the read privilege alone wherever the system only reads.
- Rotate by creating the replacement first, then revoking the old key.
Keys open the MCP server too
The same credential connects Claude and other MCP clients to your account: the
MCP server authenticates with an ffk_ key as its
bearer header, under the same grant and the same isolation. Everything above about
privileges, revocation and rotation applies unchanged.