You have a key. Here is how to pull data.
Your instructor issued you a per-student API key. Everything below uses that one key. All requests and responses are JSON.
Base URL and auth
The student API is versioned under /api/student/v1. Send your key as a bearer token on every request. A missing, revoked, or expired key returns 401 with the stable code invalid_api_key.
https://app.blueforge.dev/api/student/v1
curl -s "https://app.blueforge.dev/api/student/v1/shares" \ -H "Authorization: Bearer $BLUEFORGE_API_KEY"
The watermark and records pattern
Read one logical table at a time. The watermark is the last arrival_ts you have seen. Records are returned with arrival_ts greater than since, ordered ascending. Pass the response's nextCursor back as since to page forward. This is the pattern that handles late-arriving records correctly, and it is what real data engineering looks like.
# First call: omit "since" to read from the start of the buffer
curl -s "https://app.blueforge.dev/api/student/v1/shares/$SHARE_ID/records?table=web_events&limit=1000" \
-H "Authorization: Bearer $BLUEFORGE_API_KEY"
# Response body: { "data": { "table", "records": [...], "nextCursor", "watermark" } }
# Next call: pass the previous data.nextCursor as "since".
curl -s "https://app.blueforge.dev/api/student/v1/shares/$SHARE_ID/records?table=web_events&since=$NEXT_CURSOR" \
-H "Authorization: Bearer $BLUEFORGE_API_KEY"There is also a long-poll endpoint, /shares/:id/records/stream, that holds the connection up to 30 seconds and returns as soon as new records arrive. After 30 seconds with nothing new it returns an empty records array and the same watermark, which is your signal to reissue immediately.
The SQL endpoint
POST /sql accepts a single read-only SELECT scoped to your share tables. The v1 endpoint is a restricted subset: one SELECT, a simple WHERE, and an optional LIMIT. Anything else is rejected with sql_not_allowed. You use logical table names like web_events; physical names are resolved server-side.
curl -s "https://app.blueforge.dev/api/student/v1/sql" \
-H "Authorization: Bearer $BLUEFORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"SELECT * FROM web_events WHERE arrival_ts > '"'"'2027-01-15T00:00:00Z'"'"' LIMIT 500"}'MCP for agent workflows
If you work through an agent, the same five reads are exposed as MCP tools by a Cloudflare Worker: list_shares, describe_share, read_records, sql, and get_manifest. It authenticates with the same API key passed in MCP config.
https://mcp.blueforge.dev
The manifest
GET /shares/:id/manifest returns the ordered list of every transformation applied to the share, but only after your instructor reveals it. Until then it returns 403 with code manifest_not_released. That is expected; it is the answer key, released at the instructor's discretion.
A runnable example
A dependency-light Python extraction script, the watermark pattern, and a Prefect flow scaffold live in the repository under examples/is566/. For every endpoint and field, see the API reference.