Skip to content

GET /v1/export/decisions

Stream every decision in a window as JSON-Lines (NDJSON), one row per line, terminated by a single inline trailer line that carries an SHA-256 checksum over the body. Designed as the lock-in killer: you can leave any time, with all the data Floopy used to optimize on your behalf.

GET https://api.floopy.ai/v1/export/decisions
Authorization: Bearer <your-floopy-api-key>
  • Permission: read_permission.
  • Plan flag: has_audit_api and plan_features.log_retention_days >= 30. Available on Pro and Enterprise plans.
  • Behind the per-org canary kill switch.
FieldTypeRequiredConstraintsDefault
fromISO8601YesInclusive start.
toISO8601YesInclusive end. to - from ≤ 90 days.
formatstringNoCurrently only jsonl. Anything else returns 415.jsonl

A pre-flight estimated row-count check rejects exports whose result set would exceed floopy_export_max_rows (default 5_000_000) with 400 estimated_payload_too_large.

  • Content-Type: application/x-ndjson
  • One JSON object per line, identical shape to GET /v1/decisions/{request_id} (with the pinned EXPORT_FIELDS projection — bodies are never exported).
  • The last line is an inline JSONL trailer that carries integrity and aggregation metadata.

When any decision in the window had used_shared_pool_prior == true, the response also carries:

Floopy-Aggregation-Notice: contains-shared-pool-influenced-decisions

This is a hint — the authoritative signal lives in the trailer’s aggregation_signal_present field.

The last line of the stream is the trailer. It is detected by the literal marker key _floopy_export_trailer: true.

{
"_floopy_export_trailer": true,
"outcome": "completed",
"row_count": 12345,
"byte_count": 18234567,
"checksum_sha256": "5f4dcc3b5aa765d61d8327deb882cf99b8adb1c1d2c95b4f9e2c3a4d5e6f7a8b",
"aggregation_signal_present": false
}
FieldTypeDescription
_floopy_export_trailerbooleanAlways true. Use this key as the marker for the trailer line.
outcomestringcompleted, deadline_exceeded, error, or client_disconnect.
row_countintegerNumber of data rows streamed before the trailer.
byte_countintegerNumber of body bytes streamed before the trailer (data lines only).
checksum_sha256hex stringSHA-256 over the body bytes preceding the trailer (each data line including its terminating \n).
aggregation_signal_presentbooleantrue if at least one row carried used_shared_pool_prior == true.

The checksum is computed over the uncompressed body bytes excluding the trailer line itself. A mismatch on the consumer side indicates a truncated transfer or in-flight corruption.

A consumer can verify integrity locally by splitting off the trailer line, recomputing SHA-256 over the rest, and comparing.

Terminal window
RESPONSE=$(curl -s \
-H "Authorization: Bearer $FLOOPY_API_KEY" \
"https://api.floopy.ai/v1/export/decisions?from=$FROM&to=$TO")
# The trailer is the last line containing the marker key.
TRAILER_LINE=$(echo "$RESPONSE" | tail -n 1)
BODY=$(echo "$RESPONSE" | sed '$d') # all but the last line
CLAIMED=$(echo "$TRAILER_LINE" | jq -r '.checksum_sha256')
COMPUTED=$(printf '%s\n' "$BODY" | shasum -a 256 | awk '{print $1}')
if [ "$CLAIMED" = "$COMPUTED" ]; then
echo "OK"
else
echo "TAMPERED — claimed=$CLAIMED computed=$COMPUTED"
exit 1
fi
echo "outcome=$(echo "$TRAILER_LINE" | jq -r '.outcome') rows=$(echo "$TRAILER_LINE" | jq -r '.row_count')"

Notes:

  • On Linux replace shasum -a 256 with sha256sum.
  • The gateway terminates each data line with \n, and printf '%s\n' re-appends a single trailing newline so the recomputation matches what the gateway hashed.
  • If the trailer’s outcome is deadline_exceeded, error, or client_disconnect, the export was cut short. The checksum is still valid for the body actually delivered, but the dataset is incomplete; re-issue the request with a narrower window.
Statuserror codeWhen
400invalid_rangeMissing from/to, or from >= to.
400range_too_wideto - from > 90 days.
400estimated_payload_too_largePre-flight row estimate exceeds floopy_export_max_rows.
403plan_required (feature: "audit_api" or "audit_api_retention")Plan lacks the flag or the 30-day retention floor.
404not_foundKill switch off for this organisation, or endpoint unmounted. Identical bytes by design.
415unsupported_formatformat other than jsonl.
429export_in_progressAnother export is already running for this organisation; carries retry_after_seconds and Retry-After.
5xxinternalUpstream failure.
Terminal window
FROM="2026-04-01T00:00:00Z"
TO="2026-05-01T00:00:00Z"
curl -s -H "Authorization: Bearer $FLOOPY_API_KEY" \
"https://api.floopy.ai/v1/export/decisions?from=$FROM&to=$TO" \
> decisions.jsonl
tail -n 1 decisions.jsonl | jq .
  • One concurrent export per organisation. The next call returns 429 export_in_progress until the in-flight export finishes (or the 30-minute deadline trips).
  • 30-minute wall-clock deadline. When tripped, the trailer carries outcome: "deadline_exceeded". The audit log row records aborted_quota.
  • Pinned field projection. Exports use a fixed allowlist of columns — bodies (request_body, response_body) are never exported.
  • Single start per 5 minutes per organisation in addition to the lock, to keep the start rate bounded.