Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Gas Quebec public Cities API
version: 1.6.0
summary: Live Quebec fuel prices (regular, premium, diesel) by station, city, and region.
description: 'Public, unauthenticated read API behind gasquebec.ca. All prices are in Canadian cents per litre (¢/L). Data is sourced from Régie Essence Québec (Régie de l''énergie du Québec) and must be attributed as: "Fuel-price data from Régie Essence Québec (Régie de l''énergie du Québec), presented by Gas Quebec (gasquebec.ca)". Wherever API data is displayed publicly (a website, an app''s public screens, a widget on a public page), that credit must include a visible link to https://www.gasquebec.ca/ or to the page of the city the data covers. Every data response carries a ready-to-use `attribution` field ({ url, text, html }, French and English) and a `Link: ; rel="describedby"` header. Copy-paste snippet: `Prix : Régie de l''énergie du Québec, via Gas Québec` (EN: `Prices: Régie de l''énergie du Québec, via Gas Quebec`). Private use (Home Assistant, personal widgets, scripts) is exempt from the link. Every endpoint is rate-limited to 120 requests/minute per IP and returns 429 with a Retry-After header when exceeded.'
termsOfService: https://www.gasquebec.ca/en/terms
contact:
url: https://www.gasquebec.ca/contact
license:
name: CC BY 4.0 (Gas Quebec original content only; underlying price facts remain subject to the Régie's terms)
url: https://creativecommons.org/licenses/by/4.0/
servers:
- url: https://www.gasquebec.ca
tags:
- name: Cities
paths:
/api/cities:
get:
operationId: listCities
summary: List all tracked municipalities — or, with include=prices, every city's current…
description: 'Directory of Quebec municipalities with price data. Bare, it returns `{ name, slug }` per city, cached an hour; use the slug with /api/cities/{slug} (current prices), /api/fair-price, and city pages (https://www.gasquebec.ca/villes/{slug}). With `?include=prices` it is the bulk read: every city''s average regular, premium and diesel (¢/L), station count, coordinates, region, borough flag and last price change, cached five minutes — one call instead of one per city for a regional map or a province-wide dashboard. Averages only: `cheapest` needs a city''s station pool and lives on /api/cities/{slug}. Limits on every public data endpoint: 120 requests/minute and 20,000/day per address, counting only requests the edge cache does not answer; the daily 429 carries a `hint` and a `Retry-After` to midnight UTC.'
responses:
'200':
description: City directory — the slug list, or with include=prices every city's averages
content:
application/json:
schema:
oneOf:
- type: object
properties:
cities:
type: array
items:
type: object
properties:
name:
type: string
slug:
type: string
source:
$ref: '#/components/schemas/Source'
attribution:
$ref: '#/components/schemas/Attribution'
- $ref: '#/components/schemas/CityDirectory'
example:
cities:
- slug: levis
name: Lévis
region: chaudiere-appalaches
stationCount: 31
lat: 46.7382
lng: -71.2465
isBorough: false
updatedAt: '2026-09-21T15:40:12.000Z'
prices:
regular:
average: 151.3
premium:
average: 176.8
diesel:
average: 158.2
links:
page:
fr: https://www.gasquebec.ca/villes/levis
en: https://www.gasquebec.ca/en/cities/levis
prices: https://www.gasquebec.ca/api/cities/levis
unit: ¢/L
currency: CAD
meta:
source: Gas Québec
attribution:
url: https://www.gasquebec.ca/
text:
fr: 'Prix : Régie de l''énergie du Québec, via Gas Québec'
en: 'Prices: Régie de l''énergie du Québec, via Gas Quebec'
html:
fr: 'Prix : Régie de l''énergie du Québec, via <a href="https://www.gasquebec.ca/">Gas Québec</a>'
en: 'Prices: Régie de l''énergie du Québec, via <a href="https://www.gasquebec.ca/">Gas Quebec</a>'
license: https://creativecommons.org/licenses/by/4.0/
staleAfterDays: 7
headers:
ETag:
description: Version of this body. Send it back as If-None-Match to get a 304 while it is unchanged.
schema:
type: string
Link:
description: 'Points at the attribution rule: <https://www.gasquebec.ca/api#attribution>; rel="describedby"'
schema:
type: string
'304':
description: Not Modified — the If-None-Match ETag is still current; keep the copy you have. Empty body; ETag and Cache-Control are repeated.
headers:
ETag:
description: Version of this body. Send it back as If-None-Match to get a 304 while it is unchanged.
schema:
type: string
'429':
$ref: '#/components/responses/RateLimited'
parameters:
- name: include
in: query
required: false
schema:
type: string
enum:
- prices
description: '`prices` switches to the bulk variant (CityDirectory). Omit for the slug list.'
- name: If-None-Match
in: header
required: false
schema:
type: string
description: The ETag of the copy you already hold. While the body is unchanged the answer is an empty 304.
tags:
- Cities
/api/cities/{slug}:
get:
operationId: getCityPrices
summary: 'Current fuel prices for one city: cheapest and average per fuel, plus every…'
description: 'The JSON alternative to reading a city page. Returns exactly what https://www.gasquebec.ca/villes/{slug} shows in its price tiles — cheapest and average regular, premium and diesel — computed from the same station pool, plus every station listed under the city. Unconfirmed prices — frozen for 7+ days, or disputed by a corroborated visitor report — are still listed with `stale: true` but never feed `prices`; when no station has a fresh price for a fuel, its `cheapest` and `average` are `null`. A known city with no stations of its own is a 200 with an empty `stations` list, not a 404. Cached at the edge for 5 minutes and purged when the city''s prices change, so polling more often than that returns the same body. Suited to Home Assistant `rest` sensors, dashboards, spreadsheets and scripts.'
parameters:
- name: slug
in: path
required: true
schema:
type: string
pattern: ^[a-z0-9-]{1,80}$
description: City slug from /api/cities or /api/search, e.g. `levis`, `quebec`, `montreal`, `saint-jean-sur-richelieu`. A slug the site has since renamed or merged (`quebec-city`, `deschaillons`, …) resolves to its current city, and `citySlug` in the body names it.
- name: If-None-Match
in: header
required: false
schema:
type: string
description: The ETag of the copy you already hold. While the body is unchanged the answer is an empty 304.
responses:
'200':
description: The city's current prices
content:
application/json:
schema:
$ref: '#/components/schemas/CityPrices'
example:
citySlug: levis
city: Lévis
region:
slug: chaudiere-appalaches
fr: Chaudière-Appalaches
en: Chaudière-Appalaches
stationCount: 31
updatedAt: '2026-09-10T15:40:12.000Z'
unit: ¢/L
currency: CAD
prices:
regular:
cheapest: 146.9
average: 151.3
stationCount: 30
premium:
cheapest: 166.9
average: 171.8
stationCount: 27
diesel:
cheapest: 152.4
average: 156.0
stationCount: 22
stations:
- stationId: rq2-4f9e…
name: Costco Lévis
brand: Costco
address: 1000 Rue des Riveurs
lat: 46.7396
lng: -71.2789
prixOrdinaire: 146.9
prixSuper: 166.9
prixDiesel: 152.4
updatedAt: '2026-09-10T13:02:00.000Z'
stale: false
links:
page:
fr: https://www.gasquebec.ca/villes/levis
en: https://www.gasquebec.ca/en/cities/levis
fairPrice: https://www.gasquebec.ca/api/fair-price?citySlug=levis
meta:
source: Gas Québec
dataSource:
name: Régie essence Québec
publisher: Régie de l'énergie du Québec
url: https://regieessencequebec.ca/
attribution:
url: https://www.gasquebec.ca/villes/levis
text:
fr: 'Prix : Régie de l''énergie du Québec, via Gas Québec'
en: 'Prices: Régie de l''énergie du Québec, via Gas Quebec'
html:
fr: 'Prix : Régie de l''énergie du Québec, via <a href="https://www.gasquebec.ca/villes/levis">Gas Québec</a>'
en: 'Prices: Régie de l''énergie du Québec, via <a href="https://www.gasquebec.ca/villes/levis">Gas Quebec</a>'
license: https://creativecommons.org/licenses/by/4.0/
staleAfterDays: 7
headers:
ETag:
description: Version of this body. Send it back as If-None-Match to get a 304 while it is unchanged.
schema:
type: string
Link:
description: 'Points at the attribution rule: <https://www.gasquebec.ca/api#attribution>; rel="describedby"'
schema:
type: string
'304':
description: Not Modified — the If-None-Match ETag is still current; keep the copy you have. Empty body; ETag and Cache-Control are repeated.
headers:
ETag:
description: Version of this body. Send it back as If-None-Match to get a 304 while it is unchanged.
schema:
type: string
'404':
description: Unknown city slug. The body carries a `hint` naming /api/cities and /api/search. Never cached.
'429':
$ref: '#/components/responses/RateLimited'
'503':
description: Price store temporarily unreachable; never cached. Retry on the next polling cycle.
tags:
- Cities
components:
schemas:
FuelStats:
type: object
description: Summary for one fuel over the city's fresh stations (price updated within 7 days). Null when no fresh station posts that fuel.
properties:
cheapest:
type:
- number
- 'null'
description: Lowest fresh price, ¢/L — the city page's "lowest price" tile
average:
type:
- number
- 'null'
description: Mean of fresh prices to one decimal, ¢/L — the city page's "average" tile
stationCount:
type: integer
description: Fresh stations posting this fuel
CitySummary:
type: object
properties:
slug:
type: string
name:
type: string
region:
type: string
description: Region slug, e.g. `saguenay-lac-saint-jean`.
stationCount:
type: integer
lat:
type:
- number
- 'null'
lng:
type:
- number
- 'null'
isBorough:
type: boolean
description: A borough of a larger city; its stations also count under the parent.
updatedAt:
type:
- string
- 'null'
format: date-time
description: Last price change in this city.
prices:
type: object
properties:
regular:
type: object
properties:
average:
type:
- number
- 'null'
description: Mean posted price, ¢/L, over the city's stations; null when none posts this fuel.
premium:
type: object
properties:
average:
type:
- number
- 'null'
description: Mean posted price, ¢/L, over the city's stations; null when none posts this fuel.
diesel:
type: object
properties:
average:
type:
- number
- 'null'
description: Mean posted price, ¢/L, over the city's stations; null when none posts this fuel.
links:
type: object
properties:
page:
type: object
properties:
fr:
type: string
en:
type: string
prices:
type: string
description: The per-city endpoint, with `cheapest` and every station.
CityDirectory:
type: object
properties:
cities:
type: array
items:
$ref: '#/components/schemas/CitySummary'
unit:
type: string
enum:
- ¢/L
currency:
type: string
enum:
- CAD
meta:
type: object
properties:
attribution:
$ref: '#/components/schemas/Attribution'
CityPrices:
type: object
properties:
citySlug:
type: string
description: Canonical slug — the one to poll. A renamed or merged slug (quebec-city, deschaillons, …) resolves here.
city:
type: string
region:
type: object
properties:
slug:
type: string
fr:
type:
- string
- 'null'
en:
type:
- string
- 'null'
stationCount:
type: integer
description: Every station listed under the city, fresh or stale
updatedAt:
type:
- string
- 'null'
format: date-time
description: When the city aggregate was last rebuilt
unit:
type: string
const: ¢/L
currency:
type: string
const: CAD
prices:
type: object
properties:
regular:
$ref: '#/components/schemas/FuelStats'
premium:
$ref: '#/components/schemas/FuelStats'
diesel:
$ref: '#/components/schemas/FuelStats'
typicalGapRegular:
type:
- number
- 'null'
description: 'Typical ¢/L between the city''s cheapest non-Costco station and their mean, regular fuel: 30-day median of noon and 6 pm samples, rounded down. Null when the city lacks the samples.'
stations:
type: array
description: Fresh stations first, cheapest regular first; stale stations trail
items:
$ref: '#/components/schemas/CityPricesStation'
links:
type: object
properties:
page:
type: object
properties:
fr:
type: string
format: uri
en:
type: string
format: uri
fairPrice:
type: string
format: uri
meta:
type: object
properties:
source:
type: string
dataSource:
type: object
description: Attribution for the underlying price data — must be preserved when redistributing
attribution:
$ref: '#/components/schemas/Attribution'
license:
type: string
format: uri
staleAfterDays:
type: integer
Source:
type: string
description: Attribution for the underlying price data — must be preserved when redistributing
Attribution:
type: object
description: 'Ready-to-use link-back credit. Required wherever the data is displayed publicly (API terms: https://www.gasquebec.ca/en/terms); private use is exempt.'
properties:
url:
type: string
format: uri
description: 'Page to link to: the city page for city data, otherwise https://www.gasquebec.ca/'
text:
type: object
properties:
fr:
type: string
en:
type: string
html:
type: object
description: '`text` with "Gas Québec" as a link to `url`, ready to paste'
properties:
fr:
type: string
en:
type: string
required:
- url
- text
- html
example:
url: https://www.gasquebec.ca/villes/levis
text:
fr: 'Prix : Régie de l''énergie du Québec, via Gas Québec'
en: 'Prices: Régie de l''énergie du Québec, via Gas Quebec'
html:
fr: 'Prix : Régie de l''énergie du Québec, via <a href="https://www.gasquebec.ca/villes/levis">Gas Québec</a>'
en: 'Prices: Régie de l''énergie du Québec, via <a href="https://www.gasquebec.ca/villes/levis">Gas Quebec</a>'
CityPricesStation:
type: object
description: One station under the city. Price fields share their names with NearbyStation.
properties:
stationId:
type: string
name:
type: string
brand:
type: string
address:
type: string
lat:
type:
- number
- 'null'
lng:
type:
- number
- 'null'
prixOrdinaire:
type:
- number
- 'null'
description: Regular, ¢/L
prixSuper:
type:
- number
- 'null'
description: Premium, ¢/L
prixDiesel:
type:
- number
- 'null'
description: Diesel, ¢/L
updatedAt:
type:
- string
- 'null'
format: date-time
description: When the station last reported a price change
stale:
type: boolean
description: 'True when the price is unconfirmed: frozen for 7+ days, or disputed by a corroborated visitor report (in which case `updatedAt` can be recent). Listed for completeness, excluded from `prices`.'
responses:
RateLimited:
description: Rate limit exceeded. Honour the Retry-After header. Public data endpoints allow 120 requests/minute and 20,000/day per address, counting only requests the edge cache does not answer; the daily 429 adds a `hint` and a `Retry-After` to midnight UTC.