Contents

Exports and links

Take records out with their receipts, or share one through a link.

The FolioExport object

Attributes

  • id required Type: string
  • kind required Type: "records" "custody" "integrity" "ledger"
  • state required Type: "queued" "running" "ready" "failed" "expired"
  • records required Type: integer
  • size required Type: integer null
  • sha256 required Type: string null
  • created_at_ms required Type: integer
  • ready_at_ms required Type: integer null
  • expires_at_ms required Type: integer null

FolioExport on its own page

Request an export

POST /folio/exports

Needs folio:exports:create: Create exports, custody and integrity reports

records bundles each record's document, receipt, record.json, attachments, a hash manifest and (with folio:audit:read) its custody history; custody, integrity and ledger (needs folio:audit:read) are reports. A records export reads documents, so it also needs folio:documents:read, is a view of each one and takes a reason like opening a record (428 without one where the rules require it). The scope (records, a folder, a matter or a subject) is expanded into its records first; a records export whose documents add up to more than 512 MB is refused (400). Built by a background job; folio.export.ready is sent when done. Only the requester can read or download it.

Parameters

  • Idempotency-Key headerrequired Type: string

    1–255 printable ASCII characters, kept 24 hours.

  • Unforged-Reason-Id headeroptional Type: string

    An open reason (POST /folio/reasons), when the organisation or the folder requires one for this view.

  • Unforged-Reason-Code headeroptional Type: string

    Instead of an open reason: a reason code for this one call (one of your organisation's codes). It is opened for exactly the records the call reads and ledgered like any reason.

  • Unforged-Reason headeroptional Type: string

    The reason's text, with Unforged-Reason-Code (plain ASCII).

Request body

FolioExportRequest

  • kind required Type: "records" "custody" "integrity" "ledger"
  • records optional Type: string[]
  • folder optional Type: string
  • recursive optional Type: boolean
  • matter optional Type: string
  • subject optional Type: string

Returns

  • 202 Type: FolioExport
    Requested
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 404 Type: Problem
    not_found
  • 409 Type: Problem
    conflict, idempotency_conflict, idempotency_in_progress or idempotency_not_replayable
  • 421 Type: Problem
    wrong_region
  • 428 Type: Problem
    reason_required
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
POST /folio/exports · curl
curl -X POST "https://api.unforged.sh/folio/exports" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14" \
  -H "Content-Type: application/json" \
  -d '{
  "kind": "records",
  "records": [
    "rec_01J9X3M8V7K2Q4R5S6T7U8V9W0"
  ]
}'
POST /folio/exports · Python
import requests

r = requests.post(
    "https://api.unforged.sh/folio/exports",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
    json={
        "kind": "records",
        "records": [
            "rec_01J9X3M8V7K2Q4R5S6T7U8V9W0"
        ]
    },
)
print(r.json())
POST /folio/exports · Node.js
const res = await fetch('https://api.unforged.sh/folio/exports', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "kind": "records",
    "records": [
      "rec_01J9X3M8V7K2Q4R5S6T7U8V9W0"
    ]
  }),
});
console.log(await res.json());
Response 202
{
  "id": "exp_01J9X3M8V7K2Q4R5S6T7U8V9W0",
  "kind": "records",
  "state": "queued",
  "records": 1,
  "size": null,
  "sha256": null,
  "created_at_ms": 1790000000000,
  "ready_at_ms": null,
  "expires_at_ms": null
}

An export

GET /folio/exports/{id}

Needs folio:exports:create: Create exports, custody and integrity reports

queued, running, ready (downloadable until expires_at_ms), failed or expired. Only the person who requested it sees it (anyone else: 404).

Parameters

  • id pathrequired Type: string

    A record, queued filing or export id.

Returns

  • 200 Type: FolioExport
    The export
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 404 Type: Problem
    not_found
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
GET /folio/exports/{id} · curl
curl "https://api.unforged.sh/folio/exports/{id}" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /folio/exports/{id} · Python
import requests

r = requests.get(
    "https://api.unforged.sh/folio/exports/{id}",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /folio/exports/{id} · Node.js
const res = await fetch('https://api.unforged.sh/folio/exports/{id}', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());

Download an export

GET /folio/exports/{id}/download

Needs folio:exports:create: Create exports, custody and integrity reports

The bundle, a zip with manifest.json, streamed. Only for the person who requested it (anyone else: 404), who must still hold folio:documents:read for a records export and folio:audit:read for a ledger or custody one (403 otherwise). Ledgered (export.downloaded) before any byte is returned. 409 until it is ready, or once it has expired.

Parameters

  • id pathrequired Type: string

    A record, queued filing or export id.

Returns

  • 200
    The bundle
  • 400 Type: Problem
    invalid_request, invalid_version, idempotency_key_required or invalid_signature
  • 401 Type: Problem
    unauthorized
  • 403 Type: Problem
    permission_denied, org_suspended, or address_not_allowed (your organisation only accepts requests from the addresses it has listed)
  • 404 Type: Problem
    not_found
  • 409 Type: Problem
    conflict, idempotency_conflict, idempotency_in_progress or idempotency_not_replayable
  • 421 Type: Problem
    wrong_region
  • 429 Type: Problem
    rate_limited or quota_exceeded
  • default Type: Problem
    internal
GET /folio/exports/{id}/download · curl
curl "https://api.unforged.sh/folio/exports/{id}/download" \
  -H "Authorization: Bearer $UNFORGED_KEY" \
  -H "Unforged-Version: 2026-10-14"
GET /folio/exports/{id}/download · Python
import requests

r = requests.get(
    "https://api.unforged.sh/folio/exports/{id}/download",
    headers={"Authorization": f"Bearer {UNFORGED_KEY}", "Unforged-Version": "2026-10-14"},
)
print(r.json())
GET /folio/exports/{id}/download · Node.js
const res = await fetch('https://api.unforged.sh/folio/exports/{id}/download', {
  method: 'GET',
  headers: { Authorization: `Bearer ${process.env.UNFORGED_KEY}`, 'Unforged-Version': '2026-10-14' },
});
console.log(await res.json());