v1 · Bulk data
/docs/exports

Bulk exports

Download the complete bills mirror as a stream designed for offline copies: gzip on the wire, one newline-delimited record at a time, and no client-side cursor loop.

GEThttps://api.archivist.dev/v1/exports/bills

Authentication

This is a programmatic API endpoint. Send an API key in the Authorization header on every request:

GET /v1/exports/bills···
curl --compressed https://api.archivist.dev/v1/exports/bills \
  -H "Authorization: Bearer $ARCHIVIST_KEY"

The export uses bearer-key authentication rather than browser sessions or cookies. Missing or invalid keys return 401; revoked or suspended access returns 403. See Errors & limits for the shared status reference.

Stream behavior

The endpoint has no query parameters and no cursor to follow. The server walks the full mirror internally in 500-row pages, then yields records through a pull-driven gzip pipeline so consumers can pipe the response to disk without buffering the export in memory.

What the client receives
  • 200 OK. The success headers include Content-Type: application/x-ndjson and Content-Encoding: gzip.
  • The decoded body is newline-delimited JSON: every line is one BillItem object followed by \n.
  • Records are ordered by congress DESC, number DESC, id DESC.
  • Content-Disposition is attachment; filename="bills.ndjson.gz".

Download with curl

Use --compressed so curl advertises and transparently decodes the gzip response before writing plain NDJSON to disk. The same decoded stream can be piped directly to jq.

curl···
# Stream the full bills mirror; curl decodes Content-Encoding: gzip
curl --compressed --fail-with-body \
  -H "Authorization: Bearer $ARCHIVIST_KEY" \
  -o bills.ndjson \
  https://api.archivist.dev/v1/exports/bills

# Inspect the decoded NDJSON while piping
curl --compressed --fail-with-body \
  -H "Authorization: Bearer $ARCHIVIST_KEY" \
  https://api.archivist.dev/v1/exports/bills \
  | jq -c .

Consume with JavaScript

Standard Node and browser fetch implementations honor Content-Encoding: gzip before exposing response.body. Read chunks incrementally and split on newline boundaries; do not run the normally decoded body through a second gunzip.

export-bills.js···
const res = await fetch('https://api.archivist.dev/v1/exports/bills', {
  headers: { Authorization: `Bearer ${process.env.ARCHIVIST_KEY}` },
});
if (!res.ok) {
  const errorBody = await res.text();
  throw new Error(`Archivist ${res.status}: ${errorBody}`);
}
if (!res.body) throw new Error('Archivist returned no response body');

// Standard Node/browser fetch honors Content-Encoding: gzip before exposing response.body.
// Do not add a second gunzip. Use DecompressionStream('gzip') only when a lower-level
// client explicitly exposes raw compressed bytes.
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

for (;;) {
  const { value, done } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split('\n');
  buffer = lines.pop() ?? '';
  for (const line of lines) {
    if (!line.trim()) continue;
    const bill = JSON.parse(line);
    console.log(`${bill.id} — ${bill.officialTitle}`);
  }
}

buffer += decoder.decode();
if (buffer.trim()) {
  const bill = JSON.parse(buffer);
  console.log(`${bill.id} — ${bill.officialTitle}`);
}

Response schema

The response is a stream, not a JSON envelope. The table describes the success headers and the fields on each decoded BillItem line.

Response schema
FieldTypeRequiredDescription
status200 OK
required
The export stream opened successfully.
Content-Typeapplication/x-ndjson
required
The decoded response body is newline-delimited JSON.
Content-Encodinggzip
required
The body is gzip encoded on the wire. curl --compressed and standard fetch clients decode it before exposing the body.
Content-Dispositionattachment
required
Provides the download filename bills.ndjson.gz.
bodyNDJSON stream
required
One BillItem object per line, with each line terminated by "\n".
body[].idstring
required
Stable bill id in the form {congress}-{type}-{number}.
body[].congressinteger
required
Congress number, for example 118 or 119.
body[].typestring
required
Bill type, for example hr, s, or sjres.
body[].numberinteger
required
The bill number within its type and Congress.
body[].officialTitlestring
required
Official title from the bill mirror.
body[].introducedDatestring | null
required
ISO 8601 calendar date, or null when unavailable.
body[].memberNamestring | null
required
Sponsor name, or null when no member is linked.
body[].memberBioguideIdstring | null
required
Sponsor Bioguide id, or null when unavailable.
body[].memberByCongressKeystring | null
required
Congress-scoped sponsor key, or null when unavailable.
body[].committeeNamesstring
required
Comma-separated committee names from the mirror.
body[].sourceUrlstring | null
required
Canonical source URL, or null when unavailable.
body[].lastSyncedAtstring
required
ISO 8601 timestamp for the last mirror sync.
response.ndjson···
{"id":"118-hr-3076","congress":118,"type":"hr","number":3076,"officialTitle":"Civic Data Continuity Act","introducedDate":"2023-09-12","memberName":"Pelosi, Nancy","memberBioguideId":"P000197","memberByCongressKey":"118-h-P000197","committeeNames":"House Oversight,House Administration","sourceUrl":"https://www.congress.gov/bill/118th-congress/house-bill/3076","lastSyncedAt":"2026-04-22T03:11:08.412Z"}
{"id":"118-hr-3077","congress":118,"type":"hr","number":3077,"officialTitle":"…","introducedDate":null,"memberName":null,"memberBioguideId":null,"memberByCongressKey":null,"committeeNames":"","sourceUrl":null,"lastSyncedAt":"2026-04-22T03:11:08.418Z"}

Notes

  • The endpoint accepts no query parameters and exposes no cursor; one authenticated call covers the full mirror.
  • The export uses one rate-limit tick per call regardless of dataset size. A 429 response includes Retry-After with the next retry window.
  • Authentication and setup failures return JSON errors: 401 for missing or invalid bearer tokens, 403 for revoked or suspended access, and 500 for an unexpected setup failure.
  • Content-Disposition is attachment; filename="bills.ndjson.gz". The filename describes the wire encoding; curl --compressed and native fetch expose decoded NDJSON.
  • Internally the handler reads 500-row cursor pages and yields each line on demand, ordered by congress DESC, number DESC, id DESC.
  • If a database or gzip failure occurs after the 200 response starts, the connection terminates; treat an incomplete NDJSON line or file as a failed export.