Retrieve results with one-time tokens
POST /evaluate returns a single-use, short-lived JWT (result_token) you can present to GET /results/{token} once to fetch the full sanitised evaluation results. This is the lightest-weight delivery path for one-off integrations.
When to use this
- One-off CLI tools and CI jobs that submit + wait + grab results in one process.
- Lightweight serverless functions that don't want to keep state.
- Anywhere you'd rather not parse
evaluationsandscenariosresponses separately.
When not to use this
- Long-running consumers where the 15-minute TTL is a risk. Use webhooks.
- Anywhere you may want to refetch results later. Use
GET /scenarios/{id}/results(idempotent, cacheable).
Token properties
| Property | Value |
|---|---|
| TTL | 900 seconds (15 minutes) |
| Single-use | Yes — the first successful call consumes the token |
| Bound to | The specific evaluation_id that produced it |
| Auth | Token in path; no Authorization header required |
| HMAC | Not required on GET /results/{token} |
Happy path
# 1. Submit. Save the token and evaluation_id.
RESP=$(curl -sS -X POST "$BASE/evaluate" \
-H "Authorization: Bearer $API_KEY" \
-H "X-FB-Signature: $(sign POST $PREFIX/evaluate $BODY)" \
-H "Content-Type: application/json" \
-d "$BODY")
EVAL_ID=$(echo "$RESP" | jq -r .data.evaluation_id)
TOKEN=$(echo "$RESP" | jq -r .data.result_token)
# 2. Poll lightweight status (bounded — ~4 minutes at 2s cadence).
MAX_ATTEMPTS=120
for ((attempt=1; attempt<=MAX_ATTEMPTS; attempt++)); do
S=$(curl -sS "$BASE/evaluations/$EVAL_ID" \
-H "Authorization: Bearer $API_KEY" \
-H "X-FB-Signature: $(sign GET $PREFIX/evaluations/$EVAL_ID '')" | jq -r .data.status)
case "$S" in complete|error) break ;; esac
if [[ "$attempt" -eq "$MAX_ATTEMPTS" ]]; then
echo "Timed out waiting for evaluation $EVAL_ID" >&2
exit 1
fi
sleep 2
done
# 3. Single-fetch with the token.
curl -sS "$BASE/results/$TOKEN" | jq
Status responses
If the backing evaluation is not yet complete when you call /results/{token}:
{
"ok": true,
"data": {
"status": "processing",
"message": "Results not yet available"
}
}
In this case the token is not consumed. Wait until GET /evaluations/{id} reports complete, then call /results/{token} once.
If the evaluation is complete:
{
"ok": true,
"data": {
"scenarios": [
{
"scenario_id": "4729318",
"name": "Lead sync to CRM",
"violations": [],
"module_summary": [],
"evaluated_codes": ["SEC-1", "SEC-5"],
"passing_count": 4,
"failing_count": 1
}
]
}
}
Errors
| Status | error | Cause | Recommended action |
|---|---|---|---|
| 400 | Malformed token | Token payload missing sub | Re-submit via POST /evaluate |
| 401 | Invalid, expired, or already-used result token | TTL passed, token consumed, or signature mismatch | Switch to GET /evaluations/{id} then GET /scenarios/{id}/results |
| 404 | Evaluation not found | Referenced evaluation deleted | Re-submit |
Fallback to polling
If the token expires before you fetch:
# Status...
curl -sS "$BASE/evaluations/$EVAL_ID" \
-H "Authorization: Bearer $API_KEY" \
-H "X-FB-Signature: $(sign GET $PREFIX/evaluations/$EVAL_ID '')"
# ...then per-scenario detail (idempotent, no token).
curl -sS "$BASE/scenarios/4729318/results" \
-H "Authorization: Bearer $API_KEY" \
-H "X-FB-Signature: $(sign GET $PREFIX/scenarios/4729318/results '')"
Next steps
- Handle webhooks — push delivery.
- Your first evaluation — the polling + per-scenario detail flow.