Skip to content

Data API

The API opens once its data store is live. Keys are not issued yet.

Status

The API is not serving data yet. Until it opens, a request is refused, no keys are issued and nothing on this page can be relied on to work. This page describes what will be offered.

What it is

One endpoint per comparison (mobile, internet, tv, phone). It returns the offers meconomy.ch shows with stored evidence, each with its source and the reader named in evidence.reader: parser (MEconomyBot, from the provider’s own page), official (an official source) or human (a person in an attended read).

Not included: prices we keep by hand, other comparisons, the provider’s own text and the stored evidence files. Where a figure is not stated, the field is null, which means “not stated”, not “none”.

Getting a key

Ask through the contact page with the topic “API key”, and name the organisation or project and the purpose. Keys are free and issued by MEconomy. One key is issued per organisation or project.

Keep the key secret and on a server. Requests from a browser page are not supported: the API sends no CORS headers, and a key in page code is visible to everyone who opens the page.

Request

Send a GET request with the key in the Authorization header. The only parameter is provider, optional, a provider slug. A key in the address is refused.

curl -H "Authorization: Bearer mek_your-key" \
  "https://meconomy.ch/api/v1/mobile/offers?provider=example"

Response

The shape of an answer, with each field shown as its type; the sample holds no value. The body has the format meconomy-offers-v1, the time it was generated, the number of offers, the number withheld because a record failed our checks, the licence and the scope.

{
  "format": "meconomy-offers-v1",
  "vertical": "<mobile | internet | tv | phone>",
  "provider": "<string | null>",
  "generated_at": "<string>",
  "count": "<integer>",
  "withheld": "<integer>",
  "licence": {
    "id": "CC-BY-4.0",
    "url": "https://creativecommons.org/licenses/by/4.0/",
    "attribution": "MEconomy, meconomy.ch"
  },
  "scope": "<string>",
  "offers": [
    {
      "offer_id": "<string>",
      "provider": "<string>",
      "vertical": "<string>",
      "plan_name": "<string>",
      "currency": "<string>",
      "price_unit": "<string>",
      "price": "<number>",
      "price_after": "<number | null>",
      "promo_kind": "<string>",
      "promo_months": "<integer | null>",
      "valid_until": "<string | null>",
      "offer_until": "<string | null>",
      "list_price": "<number | null>",
      "setup_fee": "<number | null>",
      "setup_fee_promo": "<number | null>",
      "setup_fee_after": "<number | null>",
      "initial_free_months": "<integer | null>",
      "min_term_months": "<integer | null>",
      "condition_kind": "<string>",
      "availability_scope": "<string>",
      "now": {
        "price": "<number>",
        "price_after": "<number | null>",
        "display": "<string>",
        "cheapest_eligible": "<boolean>"
      },
      "evidence": {
        "source_url": "<string>",
        "read_at": "<string>",
        "last_checked_at": "<string>",
        "evidence_sha256": "<string>",
        "parser_version": "<string>",
        "reader": "<string>"
      }
    }
  ]
}
Fields of an offer
FieldTypeMeaning
offer_idstringStable identifier of the offer (the plan fingerprint used on meconomy.ch).
providerstringProvider slug, for example the value to pass as the provider parameter.
verticalstringThe comparison the offer belongs to: mobile, internet, tv or phone.
plan_namestringName of the plan as the product is called.
currencystringCurrency of every amount in the offer. CHF.
price_unitstringWhat the price covers: month, 28d, 30d, year, once or unit.
pricenumberList price in the currency, as read from the provider’s page.
price_afternumber | nullPrice after a limited promotion ends; null when none is stated.
promo_kindstringKind of promotion: none, struck, indefinite_discount, duration, dated, lifetime or window.
promo_monthsinteger | nullLength of a duration promotion in months; null when not stated.
valid_untilstring | nullDate a dated promotion ends (YYYY-MM-DD); null when not stated.
offer_untilstring | nullDate the offer can be ordered until (YYYY-MM-DD); null when not stated.
list_pricenumber | nullRegular price the provider shows struck through; null when not stated.
setup_feenumber | nullOne-time activation or setup fee; null when not stated.
setup_fee_promonumber | nullReduced setup fee during a promotion; null when not stated.
setup_fee_afternumber | nullSetup fee after the promotion ends; null when not stated.
initial_free_monthsinteger | nullMonths at no charge at the start; null when not stated.
min_term_monthsinteger | nullMinimum contract term in months; 0 means none.
condition_kindstringWho the offer is for: none, new_customer, existing_customer, youth, family, combo or other.
availability_scopestringWhere it can be had: national, regional or address.
nowobjectThe price in force at generated_at, worked out from the promotion fields.
evidenceobjectWhere and when the figures were read, and the hash of the stored page.
Fields of now
FieldTypeMeaning
pricenumberPrice in force at generated_at.
price_afternumber | nullPrice that follows once the current promotion ends; null when none.
displaystringregular, special or special_ended.
cheapest_eligiblebooleanWhether the offer is the cheapest of its plan group that a customer can order.
Fields of evidence
FieldTypeMeaning
source_urlstringThe provider page the figures were read from (https).
read_atstringWhen the figures last changed on that page (UTC, ISO 8601).
last_checked_atstringWhen the page was last checked (UTC, ISO 8601).
evidence_sha256stringSHA-256 (64 hex) of the stored page the figures were read from.
parser_versionstringCommit (40 hex) of the reader that extracted the figures.
readerstringWho read the page: parser, official or human.

Limits

  • 600 calls a day per key. The count restarts at 00:00 UTC.
  • The 200 and 429 answers carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds until the restart); other errors do not.
  • When the limit is used up the answer is 429 with Retry-After.

Errors

An error is {"error": {"code": "…", "message": "…"}} with the status below.

Error codes
CodeStatusMeaning
missing_key401No Authorization header was sent.
bad_key401The key is malformed or unknown.
revoked403The key was revoked.
limit_reached429The key’s daily limit is used up; see Retry-After.
unknown_vertical404The comparison in the path does not exist.
bad_request400A parameter is not allowed or not valid.
method_not_allowed405Only GET is supported.
not_available503The data store is not live yet.
upstream502The data store did not answer.

Licence and attribution

The data is licensed under CC BY 4.0. Credit “MEconomy, meconomy.ch” with a link to https://meconomy.ch wherever you show it. Prices are facts as we read them at the stated time; they can change at any moment, and the provider’s own page is binding. No warranty. We may revoke a key that is shared, resold or used beyond its limit.

Your data

For each key we keep the organisation or project name, a contact email, the stated purpose and a daily count of calls per comparison; no IP address and no request content. We keep them while the key is active. 12 months after a key is revoked we clear the name, the contact email and the purpose; the daily counts stay. More in the privacy policy.

Changes

Version 1 only gains fields. A change that removes or renames one becomes version 2, announced on this page 90 days before.