CanQuery API documentation

Build your first Canadian public-data integration with working examples, resource capabilities, typed endpoint reference and practical guidance for limits, pagination and retries.

Plans & credits

Your first API request

  1. Create and verify a Free account.
  2. Create an API key and save it in the CANQUERY_API_KEY environment variable on your server. Never expose it in a website or public repository.
  3. Read metadata before querying rows:
curl "https://canquery.com/api/v1/resources/ckan-toronto-open-data-resource-6d0229af-bc54-46de-9c2b-26759b01dd05" \
  -H "Authorization: Bearer $CANQUERY_API_KEY"

JSON successes normally contain data, pagination.nextCursor and meta. CSV exports, vector tiles, empty responses and /healthz have separate formats. Use an API key for new integrations. Anonymous compatibility is currently available.

A reporting workflow you can reuse

Discover a dataset, choose a resource, inspect its query_mode and preparation metadata, then filter the recorded fields. This example selects STREET_NAME equal to KING in Toronto’s active-permits resource.

curl --get "https://canquery.com/api/v1/resources/ckan-toronto-open-data-resource-6d0229af-bc54-46de-9c2b-26759b01dd05/query" \
  -H "Authorization: Bearer $CANQUERY_API_KEY" \
  --data-urlencode 'filters={"STREET_NAME":"KING"}' \
  --data-urlencode 'limit=5'

For a bounded CSV, use the same filters with /query.csv. Export starts at offset zero and includes at most 10,000 rows. Keep provenance, publisher licence and retrieval time with your report. The dataset contains active applications and permits, not a complete history.

Toronto active building permits: source and context · Guide: active versus cleared permits and street filters

Prepare a public file for a research extract

Use ECCC CABIN Yukon River resource 718489a5-d132-4ee9-ab6f-0e2644297b78. The selected CSV is not available through the federal DataStore. CanQuery decodes the UTF-16 download, imports and hosts a table, and supports bounded requests. ECCC also provides separate CABIN tools; this is not a claim that the publisher has no other interfaces.

Publisher catalogue and Open Government Licence–Canada · Original CSV · Publisher database tools

  1. GET resource metadata. If a current prepared table exists, continue to the query.
  2. For an eligible unprepared or stale resource, POST /prepare.
  3. For a 202 response, poll its job serially at least three seconds apart, honour Retry-After and stop at done or failed. Stop locally after ten minutes and retain the job ID; this does not fail or cancel shared work.
  4. Re-read metadata for the schema, freshness and preparation timestamp.
  5. GET /query with filters={"Year/Année":2024,"Family/Famille":"Chironomidae"}, sort=_id asc and limit=10.

The example counts matching records, not individual organisms or water quality. You still interpret taxonomy, coverage and publisher-specific values. Preserve publisher modification, preparation and retrieval dates as separate events. Enable JavaScript for runnable curl, Python and Node.js recipes and the verified result excerpt.

Credits for the requests shown, using an existing API key
WorkflowCredits
Inspect a ready resource, then query rows2
Inspect, admit a new preparation, poll, inspect the prepared schema, query rows103
Later inspect and query while the copy remains ready2

Polling costs zero. Joining existing work reduces the complete preparation sequence to 3 credits. A direct repeat query costs 1; an optional CSV export adds 25. An aggregate instead of the cold sequence’s row query totals 112. Discovery and other additional successful requests use their own credits.

Check what a resource supports

  • datastore: live upstream rows and equality filters; no aggregation.
  • ingested: prepared local rows, recorded-column filters, aggregation and whole-file profiles.
  • ingestable: eligible file; explicitly request /prepare, poll the returned job, then re-read metadata.
  • file-only: use the original download. Map capability is separate.

Preparation can return 200 for a current copy or 202 with shared work. Limits and publisher availability apply. /ingest remains a legacy compatibility endpoint and does not refresh a ready copy.

Endpoint reference

Download OpenAPI 3.1: typed parameters, response schemas and examples. Enable JavaScript for searchable parameters and code examples.

Map example: Uxbridge ward boundaries and GIS downloads

GET /api/v1/datasets — Search datasets

Discover admitted catalogue records. Availability of metadata does not guarantee a working file, table or map. Catalogue reads never request preparation. Follow pagination.nextCursor until null. Repeated values of one filter match any of them; different filters must all match. With facets, each group is counted without its own filter; counts are null when unavailable.

ParameterLocationTypeRequiredDescription
qquerystringNoCatalogue search text, trimmed; at most 200 characters.
orgqueryarrayNoPublisher name or identity; repeatable.
formatqueryarrayNoRecorded resource format; repeatable.
keywordqueryarrayNoRecorded dataset keyword; repeatable.
placequerystringNoCanonical place ID or slug; includes configured inherited coverage.
sourcequeryarrayNoCatalogue source ID; repeatable.
levelqueryarrayNoLevel of government; provincial includes territorial and municipal includes regional. Repeatable.
mappablequerystringNoOnly datasets with maps. Use true or 1; omit to disable. false is invalid.
queryablequerystringNoOnly datasets with a live table or a ready prepared copy. Use true or 1; omit to disable.
sortquerystringNorelevance keeps search ranking; title order follows lang.
langquerystringNoFrench when fr; otherwise English.
facetsquerystringNoAdd meta.total and meta.facets. Use true or 1; omit to disable.
limitqueryintegerNoPage size; values above 100 are clamped to 100.
cursorqueryintegerNoNonnegative offset. Pass pagination.nextCursor unchanged; omit for the first page.
GET /api/v1/datasets/{idOrName} — Get a dataset

Resolve a canonical dataset ID or published name/slug. Includes resources, capabilities and source-specific licence/provenance.

ParameterLocationTypeRequiredDescription
idOrNamepathstringYesCanonical dataset ID or published name/slug.
GET /api/v1/organizations — List publishers

Literal bilingual publisher search with optional source/place scope. Uses catalogue pagination.

ParameterLocationTypeRequiredDescription
qquerystringNoLiteral bilingual publisher search.
sourcequerystringNoCatalogue source ID.
placequerystringNoCanonical place ID or slug; includes configured inherited coverage.
limitqueryintegerNoPage size; values above 100 are clamped to 100.
cursorqueryintegerNoNonnegative offset. Pass pagination.nextCursor unchanged; omit for the first page.
GET /api/v1/organizations/{name} — Get a publisher

Publisher identity, catalogue and capability counts, and place context.

ParameterLocationTypeRequiredDescription
namepathstringYesPublisher name or identity, at most 200 characters.
GET /api/v1/places — List places

Search canonical geographical identities and their direct/inherited coverage. Uses catalogue pagination.

ParameterLocationTypeRequiredDescription
qquerystringNoCatalogue search text, trimmed; at most 200 characters.
kindquerystringNoPlace type.
parentquerystringNoCanonical parent ID or slug.
featuredquerystringNoUse true or 1 for featured places; omit to disable.
limitqueryintegerNoPage size; values above 100 are clamped to 100.
cursorqueryintegerNoNonnegative offset. Pass pagination.nextCursor unchanged; omit for the first page.
GET /api/v1/places/{idOrSlug} — Get a place

Resolve a canonical ID, slug or durable alias. Includes ancestry, children, viewport and coverage. API lookup does not redirect like an HTML alias.

ParameterLocationTypeRequiredDescription
idOrSlugpathstringYesCanonical place ID, slug or historical alias.
GET /api/v1/sources — List catalogue sources

Persisted publisher portals, provenance hosts, catalogue counts and last successful sync. This endpoint is not paginated.

ParameterLocationTypeRequiredDescription
placequerystringNoCanonical place ID or slug; includes configured inherited coverage.
GET /api/v1/resources/{id} — Inspect resource capabilities

Read query_mode, preparation, ingestion, map and provenance before querying. A map can exist on a file-only table resource. Metadata reads neither prepare files nor renew local-copy activity. Preparation time differs from publisher modification time; source changes can remain undiscovered when publisher version metadata is unchanged.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
GET /api/v1/resources/recently-unlocked — List recently prepared resources

Recent ready local copies. The historical route name is retained. Reading the list does not prepare files.

ParameterLocationTypeRequiredDescription
placequerystringNoCanonical place ID or slug; includes configured inherited coverage.
limitqueryintegerNoPage size; values above 20 are clamped to 20.
GET /api/v1/resources/popular — List popular resources

Counts CanQuery query-log hits, not publisher downloads.

ParameterLocationTypeRequiredDescription
placequerystringNoCanonical place ID or slug; includes configured inherited coverage.
daysqueryintegerNoLookback days; values above 30 are clamped.
limitqueryintegerNoPage size; values above 20 are clamped to 20.
GET /api/v1/resources/{id}/query — Query rows or aggregate

Ready local snapshots take precedence over live CKAN DataStore. Live DataStore supports equality filters only, with no aggregation. Local aggregates cover the complete filtered snapshot; total then counts groups, not rows. Local reads renew copy activity and successful queries record popularity. Local responses include meta.snapshot, retrieval time and deployment limits. Supply snapshot on subsequent pages to require identical stored rows and schema; 409 requires an explicit new extraction. Catalogue provenance and publisher modification timestamps are observed at retrieval, not frozen at preparation. source_metadata_version is not a downloaded-content checksum. A 409 never automatically enqueues preparation; inspect metadata and explicitly use /prepare when supported. Aggregations have an additional 30 requests/minute limit and consume expensive-request concurrency.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
snapshotquerystringNoRequire this exact local snapshot. A replaced or unavailable copy returns 409 SNAPSHOT_UNAVAILABLE; no automatic fallback or preparation. This token does not promise retention or source-content freshness.
qquerystringNoSearch within resource rows (not catalogue search); at most 200 characters. Local search uses case-insensitive ILIKE patterns.
filtersquerystringNoURL-encoded JSON object, at most 2,000 characters and 20 column keys of 1–63 characters. Exact recorded field names; conditions combine with AND. Scalars mean equality. Objects use op and value: eq, lt, gt, lte, gte, contains. Live DataStore supports eq only. eq:null means IS NULL locally; contains preserves % and _ SQL wildcard meanings.
sortquerystringNoExact field name, optionally followed by asc or desc. Local row sorting also accepts _id; aggregates accept key or value. An exact field name wins over a direction suffix. Live DataStore values are limited to 100 characters.
group_byquerystringNoPrepared tables only: exact recorded grouping field. Required together with agg.
aggquerystringNoPrepared tables only. count forbids agg_column; other functions require it. sum/avg require a numeric field.
agg_columnquerystringNoRecorded measure field for sum, avg, min or max; forbidden with count.
bucketquerystringNoOptional temporal grouping; group_by must be DATE or TIMESTAMPTZ.
limitqueryintegerNoPage size; values above 100 are clamped to 100.
offsetqueryintegerNoRow/group offset; independent of catalogue cursor. Avoid relying on a stable snapshot across page calls.
GET /api/v1/resources/{id}/query.csv — Export a bounded CSV

Exports from offset zero, at most 10000 rows (deployment cap; hard maximum 10,000). Same query capabilities as /query, including local full-snapshot aggregation before limiting groups. There is no CSV pagination or full-file guarantee. Use the original download for complete publisher files. Formula-like spreadsheet cells are neutralized. A failure after headers closes the partial response: discard incomplete output and retry within limits. Keyed failed/interrupted exports are refunded. Ten exports/minute plus plan request/concurrency limits.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
snapshotquerystringNoRequire this exact local snapshot. A replaced or unavailable copy returns 409 SNAPSHOT_UNAVAILABLE; no automatic fallback or preparation. This token does not promise retention or source-content freshness.
qquerystringNoSearch within resource rows (not catalogue search); at most 200 characters. Local search uses case-insensitive ILIKE patterns.
filtersquerystringNoURL-encoded JSON object, at most 2,000 characters and 20 column keys of 1–63 characters. Exact recorded field names; conditions combine with AND. Scalars mean equality. Objects use op and value: eq, lt, gt, lte, gte, contains. Live DataStore supports eq only. eq:null means IS NULL locally; contains preserves % and _ SQL wildcard meanings.
sortquerystringNoExact field name, optionally followed by asc or desc. Local row sorting also accepts _id; aggregates accept key or value. An exact field name wins over a direction suffix. Live DataStore values are limited to 100 characters.
group_byquerystringNoPrepared tables only: exact recorded grouping field. Required together with agg.
aggquerystringNoPrepared tables only. count forbids agg_column; other functions require it. sum/avg require a numeric field.
agg_columnquerystringNoRecorded measure field for sum, avg, min or max; forbidden with count.
bucketquerystringNoOptional temporal grouping; group_by must be DATE or TIMESTAMPTZ.
GET /api/v1/resources/{id}/preview — Preview a file before preparation

For a CSV that CanQuery can prepare but has no ready copy and no live DataStore: reads the first 256 KiB of the publisher’s file (a ranged request; nothing is stored) and returns its header with inferred types and up to 50 rows as the file’s text. truncated means the sample ended before the file did. Nothing is prepared, renewed or recorded; the cached sample lasts ten minutes. A successful sample is priced as a metadata read; 409 PREVIEW_NOT_NEEDED (a prepared copy or live table exists), 422 PREVIEW_UNSUPPORTED (other formats or unreadable content) and 502 PREVIEW_UPSTREAM or PREVIEW_TIMEOUT (the publisher fails or stalls) cost nothing but still count toward request limits. Anonymous requests are limited to thirty a minute; keyed requests follow the plan request limit.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
GET /api/v1/resources/{id}/profile — Profile a prepared table

Requires a ready local snapshot. Describes the whole file, not current filters. At most the first 60 recorded non-_id fields; numeric fields add min/max/avg and date fields min/max. Successful reads renew activity. Twenty requests/minute plus plan request/concurrency limits.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
snapshotquerystringNoRequire this exact local snapshot. A replaced or unavailable copy returns 409 SNAPSHOT_UNAVAILABLE; no automatic fallback or preparation. This token does not promise retention or source-content freshness.
POST /api/v1/resources/{id}/prepare — Prepare or refresh a file

No body. Returns 200 for a current copy or 202 for a new/shared job. Only a newly admitted job deducts preparation credits. A terminal failure without a result published by that job returns the actual debit to its original allowance period exactly once. Retries retain the charge; stopping polling does not fail the job. A failed refresh returns its own charge even if an older copy still serves. A successful empty table counts as success; later expiry or eviction does not return credits. This is an account-credit reversal, not a payment refund. Current copies, joins and polling cost zero but still count toward request limits. Keyed new jobs are capped at 20/account/hour; anonymous admission has a configured per-IP limit. A shared active-queue ceiling and format/size/row/column/storage caps also apply. A stale copy can continue serving during refresh. Paused admission returns 429 even for current copies. Anonymous requests from self-identified crawlers can read current copies and join shared jobs but cannot start new ones (429 AUTOMATED_CLIENT). Honour cooldown Retry-After; a new source version can bypass the old cooldown. No scheduled-refresh guarantee.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
POST /api/v1/resources/{id}/ingest — Prepare a file (legacy)

No body. Compatibility endpoint; new integrations should use /prepare for freshness and refresh. It returns an existing ready copy without refreshing stale data. Five requests/hour, plus shared limits. New-job charging matches /prepare.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
POST /api/v1/resources/{id}/activity — Renew local-copy activity

No body. Renews an existing ready copy without preparing a file or recording popularity. A 409 means the copy is unavailable or replaced; re-read metadata. Zero credits still counts toward request limits.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
GET /api/v1/jobs/{id} — Poll a preparation job

Poll one request at a time with a bounded delay and honour Retry-After on errors. A done job is historical: re-read resource metadata before querying because a prepared copy may expire. Failure messages are sanitized; failure_reason and retry_at explain retry eligibility. Zero credits still counts toward request limits.

ParameterLocationTypeRequiredDescription
idpathintegerYesPositive job ID returned by preparation.
GET /api/v1/resources/{id}/map — Get a bounded map viewport

Enveloped WGS84 GeoJSON for admitted ArcGIS, local PostGIS or PMTiles maps. live=true identifies the viewport interface; it does not promise a publisher fetch on every call. Check returned/truncated; requests are capped at 1,000 features and 8 MiB. PMTiles viewport decoding also bounds tile count. Sixty viewport calls/minute plus plan request/concurrency limits.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
bboxquerystringYesRequired WGS84 west,south,east,north: -180 ≤ west < east ≤ 180 and -90 ≤ south < north ≤ 90.
zoomqueryintegerNoInteger zoom level.
limitqueryintegerNoFeature ceiling; out-of-range values return 400.
GET /api/v1/resources/{id}/map/tiles/{version}/{z}/{x}/{y}.pbf — Get a vector tile

PMTiles maps only. Copy the current tiles template/version and zoom range from resource metadata. Coordinates must fit the tile grid and archive zoom range. Anonymous successful tiles cache immutably for one year; keyed responses remain private, no-store. Up to 240 tiles/minute, also subject to the keyed plan request limit.

ParameterLocationTypeRequiredDescription
idpathstringYesResource ID from dataset or resource metadata.
versionpathstringYesCurrent map version from resource metadata.
zpathintegerYesZoom within this archive’s min_zoom/max_zoom (0–22).
xpathintegerYesTile coordinate from 0 through 2^z − 1.
ypathintegerYesTile coordinate from 0 through 2^z − 1.
GET /api/v1/stats — Get catalogue statistics

Briefly cached counts; capabilities overlap. These are dated observations, not guaranteed coverage or publisher availability.

GET /api/v1/insights/top-downloads — Get the publisher download leaderboard

Publisher-reported download statistics with selected representatives. Distinct from CanQuery query popularity; meta.period identifies the reporting month.

ParameterLocationTypeRequiredDescription
langquerystringNoFrench when fr; otherwise English.
GET /api/v1/insights/featured — Get prepared chart previews

Up to 12 validated previews from already prepared Top 100 representatives. No preparation is admitted. Context gives aggregation, snapshot time, displayed/total groups and known missing metrics; this is neither a chart-rendering API nor a scheduled-refresh service.

ParameterLocationTypeRequiredDescription
langquerystringNoFrench when fr; otherwise English.
GET /api/v1/blog — List data guides

Published guide summaries; reads bundled content without querying the catalogue.

ParameterLocationTypeRequiredDescription
langquerystringNoGuide language; must be en or fr.
placequerystringNoGuide place slug.
datasetquerystringNoCanonical dataset ID or published slug.
GET /api/v1/blog/{lang}/{slug} — Get a data guide

Published guide edition including sanitized bodyHtml and translation links.

ParameterLocationTypeRequiredDescription
langpathstringYesGuide edition language.
slugpathstringYesPublished localized guide slug.
GET /api/v1/repo — Get repository metadata

Cached public GitHub star count. data may be null when GitHub is unavailable.

GET /api/v1/ops — Inspect job and map health

Public and unmetered. HTTP 200 or 503 uses the same envelope according to data.ok. Preparation counters alone do not change ok; inspect queue age and worker state separately. Health does not guarantee every file is available.

GET /healthz — Check database and federal upstream

Site-root path /healthz (not /api/v1/healthz). Public, unmetered, unenveloped reachability check; not a worker or catalogue-wide availability check.

GET /api/v1/readyz — Check application and database availability

Site-root path. Public, unmetered and no-store. Checks database connectivity without requiring an upstream publisher or worker to be healthy.

GET /api/v1/ops/components/{component} — Inspect one operational component

Public, unmetered and no-store. Sanitized host observations older than 180 seconds fail closed with HTTP 503. Independent components separate availability, preparation, maps, sources, commercial backlogs, backups and storage. Existing /ops semantics remain unchanged.

ParameterLocationTypeRequiredDescription
componentpathstringYesOperational component to inspect.
GET /api/v1/openapi.json — Download the OpenAPI contract

Public, unmetered OpenAPI 3.1 document. Import into compatible developer tools. Examples are synthetic and do not establish current publisher data or availability.

Operate reliably

Catalogue lists use the returned nextCursor offset string until null. Row queries use limit/offset and data.total; separate requests do not guarantee one unchanged snapshot. Local filters use exact recorded columns and combine with AND. CSV exports are capped; discard partial output after a failed stream.

Account keys share credits, request rates and expensive-request concurrency. X-CanQuery-Credits-Remaining includes pending reservations. Successful cached requests count. Successful cached requests count. Failed ordinary requests and interrupted exports return their credits. A new preparation deducts 100 credits; a terminal failure without a result published by that job returns its actual debit once to the original allowance period. Retries retain the debit. A client timeout does not fail or cancel the shared job. A failed refresh returns its charge even if an older table remains usable. Valid empty tables count as success; later expiry or eviction does not return credits. This is an account-credit adjustment, not a cash refund. Joining jobs and polling cost zero credits but still count toward request limits.

Distinguish QUOTA_EXCEEDED from RATE_LIMIT, CONCURRENCY_LIMIT, PREPARATION_BUSY, PREPARATION_COOLDOWN and AUTOMATED_CLIENT. Honour Retry-After and bound retries; do not repeatedly retry exhausted allowances, authentication errors or unsupported files. Include X-Request-Id when contacting support.

Publisher modification time, preparation time and retrieval time differ. Copies may expire, upstream files may change, and there is no scheduled-refresh guarantee.

Explore CanQuery