Quickstart: read the catalogue without a key
Three GET endpoints, no authentication, CORS open, JSON responses. Start from the country list, then fetch prices for the country you need.
- GET https://e-vignettes.eu/api/v1/countries — the nine covered countries, their toll operator and a summary of each toll system.
- GET https://e-vignettes.eu/api/v1/countries/at — the full Austria guide: tolled roads, vehicle categories, activation, fines, section tolls, FAQ and the official sources each fact was checked against.
- GET https://e-vignettes.eu/api/v1/products?country=at&type=vignette — live prices, with the government price and the service fee as separate fields.
Errors
Every failure, including an unmatched /api/ URL, returns JSON rather than an HTML error page. The body always carries the same shape: a stable code to branch on, a human message, a hint naming what to change, the HTTP status, and a documentation_url.
The codes are not_found, invalid_parameter, method_not_allowed, upstream_unavailable and internal_error. They are part of the contract and are never renamed.
Selling vignettes: the partner API
Creating an order, validating a vehicle, cancelling or modifying an order and receiving webhooks all happen on the authenticated partner API, not on the public read API above. Register through the partner form to receive separate sandbox and production keys, then build against the sandbox: the full order lifecycle, including webhook events and cancellations, works there without touching real payments or government systems.
Three integration routes exist, and you can mix them: the REST API for full control, an iframe or embeddable widget checkout for a working purchase flow without owning payment logic, and the partner panel for creating orders by hand with no code at all.
MCP server: read the catalogue as tools
This site runs its own Model Context Protocol server at https://e-vignettes.eu/mcp, over Streamable HTTP. It needs no credentials and exposes the read API as four tools: list_countries, get_country, list_products and read_page, the last of which returns any page of the site as Markdown.
It is stateless and dual-era: it serves the current per-request-metadata revision of the protocol, 2026-07-28, and still answers the initialize handshake used by 2025-11-25 and earlier, so older clients keep working. There is no SSE stream and no session; GET and DELETE answer 405, as that revision requires.
Point any MCP client at the endpoint, or read the manifest below to discover it programmatically. The server cannot buy anything — see the partner server for that.
MCP server: let an agent do the ordering
The partner API is also exposed as a Model Context Protocol server, so an LLM agent can browse the catalogue, validate a plate and place an order as tool calls instead of hand-written HTTP. Point any MCP client at the endpoint and authenticate with the same partner API key, sent as an Authorization header of the form Bearer followed by the key; the key lives in the Partner Panel under For Developers.
Build against the sandbox server first — https://sandbox-api.vignette.id/mcp — and switch to https://api.vignette.id/mcp only when you are ready to place real orders. Sandbox and production keys are separate.
The server exposes 11 tools: get_products, get_products_status, get_users, get_user_orders, validate_vehicle, create_order, get_orders, get_order, get_order_status, cancel_pending_order, cancel_deferred_order. A typical purchase is get_products to find the product, validate_vehicle to check the plate, create_order to buy, then get_order_status to follow it from PENDING to ACTIVE.
Rate limits
The public endpoints are rate limited per IP address, and every response says where you stand so you never have to guess. Two policies apply: public-read allows 240 requests per 60 seconds across /api/v1, and mcp allows 120 requests per 60 seconds on the MCP endpoint, which is lower because one tool call can fan out to nine upstream requests.
Each response carries RateLimit-Policy and RateLimit as defined by draft-ietf-httpapi-ratelimit-headers-09 — for example RateLimit-Policy: public-read;q=240;w=60 alongside RateLimit: public-read;r=239;t=43, where r is the requests left and t the seconds until the window resets. The older RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset fields are sent as well, for clients that only read those.
Going over the quota returns 429 with Retry-After in seconds and the usual JSON error body, code rate_limited. Responses are also edge-cached, so honour Cache-Control rather than polling: country data changes a few times a year and prices change when a national operator changes a tariff.
On the partner API the catalogue endpoint is rate limited per partner per minute, with more headroom as volume grows. Cache the catalogue instead of calling it per checkout, and use webhooks rather than polling an order's status.
Versioning and deprecation
The public API is versioned in the URL path. /api/v1 is the current version; a breaking change gets a new path rather than altering v1 underneath you. Additive changes — a new field, a new endpoint, a new enum member — are not breaking, so parse defensively and ignore fields you do not recognise.
Retirement is announced in the responses themselves, not only in a blog post. The moment a version is deprecated, every response from it carries Deprecation with the date the deprecation was announced, Sunset with the date it stops answering, and a Link header with rel=deprecation pointing at this page and rel=successor-version pointing at the replacement. While a version is current it carries none of these, so their absence is itself the signal that nothing is scheduled.
A deprecated version keeps answering for at least 12 months after the announcement, and a Sunset date is never moved closer once published.
Client libraries and SDK
A JavaScript client for the public read API ships in the Vignette ID CLI package, which doubles as a library: createClient() returns listCountries, getCountry and listProducts, and every failure throws an ApiError carrying the server's own code, message and hint so you can branch on the code rather than on a string.
It has no dependencies and runs on Node 18 or newer, in a server, a Lambda or a script. For other languages, generate a client from the OpenAPI document above — it is valid 3.1 with a typed schema on every response, so openapi-generator, Kiota and similar tools consume it without hand-editing.
For AI agents
This site answers Accept: text/markdown with Markdown on every content page, including the homepage and the country guides, so a page can be read without parsing HTML. Unknown paths return a 404 with a Markdown body pointing at the site map.
A site summary in llms.txt format, an expanded companion with per-country facts and live prices, and a when-to-use brief for agents are all published as plain text.
Discovery documents
Everything above is discoverable without reading this page. An agent that knows only the domain can walk the well-known paths and find the rest.
- API catalog (RFC 9727 linkset) — Points at the OpenAPI document, these docs and the health check
- Capability manifest (ARD / ai-catalog) — Every machine-readable surface, with the questions each one answers
- MCP manifest (registry server.json)
- Agent skills index — Three SKILL.md documents with SHA-256 digests
- How to authenticate — Short version: tier 1 needs nothing
- Health check
Tools in the browser (WebMCP)
Pages on this site register read-only tools with the browser's WebMCP model context when the browser supports it, so an agent working inside the reader's tab can look up countries, toll rules and prices, and open a country guide or the shop, without leaving the page or calling the API itself.
The API is still moving between draft shapes, so both the navigator and document locations and both the registerTool and provideContext methods are feature-detected. In a browser without WebMCP nothing is registered and nothing is logged.
Getting help
Integration questions, API keys and commission terms: work@vignette.id. An integration call with the team is available if you want to walk through the API or the iframe setup before writing code.