Skip to main content

Tutorial10 min

Ingest the report feed

Read every report your Client Account has access to, newest first. You page with an opaque cursor until it runs out, and narrow the feed with taxonomy filters.
API reference
Endpoint
GET /reports
Auth
X-API-Key
Query
cursor, pageSize, filters
Returns
200 { data, pageSize, nextCursor }

Before you start​

  1. A Core API base URL

    Pick the environment you are building against. Base URLs has the details.

    • ProductionProvided at onboardingMutual TLS required
    • Sandboxhttps://staging-api.emergentriskinternational.com/api/v1Same contract as production
    • Localhttp://127.0.0.1:3001/api/v1apps/backend on your machine
  2. An API Key

    Organization-scoped, sent in the X-API-Key header and issued by ERI support. See Authentication.

    Running the backend locally

    Bootstrap the first key from apps/backend. The script prints the raw key once, so store it outside the repository.

    pnpm migrations:up
    pnpm api-keys:bootstrap
  3. Somewhere to store reports

    A table or bucket keyed by report id. You write each report by id, so a re-run updates rows instead of duplicating them.

  1. Step 1: Request the first page​

    Call /reports without a cursor. Reports come back newest first, by publicationDate.

    pageSize is a request, not a promise. Leave it out and the server uses its default; ask for more than its maximum and it clamps. The size it actually used comes back as pageSize.

    List items carry the metadata only. The Markdown body and images come from Retrieve a report.

    Terminal
    export CORE_API_BASE_URL="http://127.0.0.1:3001/api/v1"
    export ERI_API_KEY="<raw API Key from bootstrap or ERI support>"
    curl -G "$CORE_API_BASE_URL/reports" \
    -H "X-API-Key: $ERI_API_KEY" \
    --data-urlencode "pageSize=2"
    200 OK
    {
    "data": [
    {
    "id": "01a04100-0000-7000-8000-000000000001",
    "title": "Daily Risk Forecast - 2026-09-01",
    "publicationDate": "2026-09-01T10:53:16.189Z",
    "region": "Global",
    "reportType": "Daily Risk Forecast",
    "regions": ["Global"],
    "countries": [],
    "topics": [],
    "sectors": []
    },
    {
    "id": "01a04100-0000-7000-8000-000000000002",
    "title": "South China Sea - Supply Chain Advisory",
    "publicationDate": "2026-08-31T10:53:16.189Z",
    "region": "East & Southeast Asia",
    "reportType": "Supply Chain Report",
    "regions": ["East & Southeast Asia"],
    "countries": ["China"],
    "topics": [],
    "sectors": ["Maritime"]
    }
    ],
    "pageSize": 2,
    "nextCursor": "eyJwdWJsaWNhdGlvbkRhdGUiOiIyMDI2LTA4LTMxVDEwOjUzOjE2LjE4OVoiLCJpZCI6IjAxYTA0MTAwLTAwMDAtNzAwMC04MDAwLTAwMDAwMDAwMDAwMiJ9"
    }
  2. Step 2: Follow the cursor​

    Send nextCursor back as cursor to get the next page. Keep going until nextCursor is null: that page is the last one.

    The cursor is opaque. Pass it back exactly as received and never build or edit one. A cursor the API cannot decode returns 422; start again from the first page.

    curl -G "$CORE_API_BASE_URL/reports" \
    -H "X-API-Key: $ERI_API_KEY" \
    --data-urlencode "pageSize=2" \
    --data-urlencode "cursor=<nextCursor from the previous page>"
  3. Step 3: Narrow with filters​

    Filter by contentType, region, country, topic and sector. Repeat a parameter for several values, up to 50 each.

    Values are OR within one parameter and AND across parameters. The example below reads reports tagged Europe or MENA that are also about Cyberthreat.

    Values come from the platform taxonomy and match exactly, case included. A value outside it returns 400 rather than an empty page, so a typo never looks like a quiet day.

    Keep the same filters on every page you request with a cursor.

    Region and content type values at the time of writing

    The taxonomy can grow. If a value starts failing with 400, check it against the latest list from ERI.

    • region: Asia Pacific, Central & South America, China & Taiwan, East & Southeast Asia, Europe, Global, MENA, North America, South & Central Asia, Sub-Saharan Africa
    • contentType: Artificial Intelligence Risk Monthly, Country Reports, Daily Risk Forecast, Geostrategic Trade Monitor, Global Risk Digest, Intelligence Monitoring Room, Rapid Reaction Brief, Strategic Conflict Outlook, Strategic Risk Forecast, Supply Chain Report

    Countries, topics and sectors are longer lists. Use the names exactly as reports carry them, for example Estonia, Cyberthreat or Maritime.

    curl -G "$CORE_API_BASE_URL/reports" \
    -H "X-API-Key: $ERI_API_KEY" \
    --data-urlencode "region=Europe" \
    --data-urlencode "region=MENA" \
    --data-urlencode "topic=Cyberthreat"
  4. Step 4: Handle the response​

    Errors share one JSON envelope. Domain errors carry a stable code to branch on; validation errors list the failing parameters in errors. Pick a status to see the exact body.

    200OK
    When
    A page of reports, newest first. An empty data array is a valid page, not an error.
    What to do
    Store the reports, then request the next page while nextCursor is not null.
    Response body
    {
    "data": [
    {
    "id": "01a04100-0000-7000-8000-000000000004",
    "title": "Baltic Corridor - Cyber Threat Bulletin",
    "publicationDate": "2026-08-29T10:53:16.189Z",
    "region": "Europe",
    "reportType": "Rapid Reaction Brief",
    "regions": ["Europe"],
    "countries": ["Estonia", "Latvia", "Lithuania"],
    "topics": ["Cyberthreat"],
    "sectors": ["Maritime"]
    }
    ],
    "pageSize": 50,
    "nextCursor": null
    }

Your pipeline reads the feed​

Every report your Client Account can read now reaches your store, page by page.