{"openapi":"3.1.0","info":{"title":"EuroMakers Directory API","version":"1.2.0","summary":"Read the EuroMakers directory of European software.","description":"EuroMakers is the home of European software: every product is checked before it goes live and shows where it is made. This free, read-only API returns the published directory. It needs no key. Each IP address may make 60 requests per 60 seconds across all endpoints, cached answers included; over it, a 429 with Retry-After and X-RateLimit-Limit. Every 200 carries an ETag: send it in If-None-Match for a 304. Responses carry no CORS headers, so call the API from a server, not from a browser on another site. For bulk reads and browsers, use the snapshot files: the same JSON as static files, rebuilt every night, free, with no rate limit and CORS (https://data.euromakers.org/v1/manifest.json). This is version 1: fields and paths are only ever added, never renamed or removed. Errors use a JSON object with `error` (message), `code`, and `hint`. Documentation: https://www.euromakers.org/developers. See also https://www.euromakers.org/llms.txt.","contact":{"name":"EuroMakers","url":"https://www.euromakers.org/contact"},"termsOfService":"https://www.euromakers.org/terms"},"externalDocs":{"description":"Documentation, including the snapshot files","url":"https://www.euromakers.org/developers#snapshot"},"servers":[{"url":"https://www.euromakers.org","description":"Production"}],"tags":[{"name":"Directory","description":"Read-only data of the published directory."}],"paths":{"/api/software":{"get":{"operationId":"listSoftware","tags":["Directory"],"summary":"Every published product.","description":"An array of products, ordered by category id and then by id.","externalDocs":{"description":"The same JSON as a snapshot file, rebuilt every night, with no rate limit and CORS for browsers.","url":"https://data.euromakers.org/v1/software.json"},"parameters":[{"name":"If-None-Match","in":"header","required":false,"description":"The ETag of an earlier answer. When it still matches, the answer is a 304 with no body.","schema":{"type":"string"}}],"responses":{"200":{"description":"Every published product.","headers":{"Cache-Control":{"description":"Answers are cached at the edge and may be up to a day old.","schema":{"type":"string","examples":["public, max-age=60, s-maxage=86400, stale-while-revalidate=604800"]}},"ETag":{"description":"Identifies this exact answer; send it back in If-None-Match.","schema":{"type":"string","examples":["\"3f9a0c1e5b7d2a4c6e8f0a1b2c3d4e5f\""]}}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Software"}},"example":[{"id":"proton-mail","name":"Proton Mail","description":"End-to-end encrypted email from Switzerland.","audience":["b2b","individual"],"country":"Switzerland","website":"https://proton.me/mail","longDescription":"Proton Mail is the flagship encrypted email …","features":["End-to-end encrypted email","…"],"useCases":["business-email"],"category":"communication"}]}}},"304":{"description":"Not modified: the If-None-Match ETag still matches. No body.","headers":{"ETag":{"description":"Identifies this exact answer; send it back in If-None-Match.","schema":{"type":"string","examples":["\"3f9a0c1e5b7d2a4c6e8f0a1b2c3d4e5f\""]}}}},"429":{"description":"Too many requests","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","examples":[60]}},"X-RateLimit-Limit":{"description":"The limit that was reached, per 60 seconds: 60 for one IP address, 600 when the API as a whole is busy.","schema":{"type":"integer","examples":[60]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Too many requests","code":"rate_limited","hint":"Retry after the seconds in Retry-After, or read the snapshot files, which have no limit: https://data.euromakers.org/v1/software.json"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Internal server error","code":"internal_error","hint":"Retry later. If this persists, use /contact."}}}}}},"503":{"description":"Catalog temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Catalog temporarily unavailable","code":"catalog_unavailable","hint":"Retry later. The catalog database failed to load."}}}}}}}}},"/api/software/{id}":{"get":{"operationId":"getSoftwareById","tags":["Directory"],"summary":"One published product.","description":"One product. An unknown or unpublished id is a 404.","parameters":[{"name":"id","in":"path","required":true,"description":"The product’s id: lowercase letters, digits and hyphens.","schema":{"type":"string","pattern":"^[a-z0-9-]{1,80}$","maxLength":80},"example":"proton-mail"},{"name":"If-None-Match","in":"header","required":false,"description":"The ETag of an earlier answer. When it still matches, the answer is a 304 with no body.","schema":{"type":"string"}}],"responses":{"200":{"description":"One published product.","headers":{"Cache-Control":{"description":"Answers are cached at the edge and may be up to a day old.","schema":{"type":"string","examples":["public, max-age=60, s-maxage=86400, stale-while-revalidate=604800"]}},"ETag":{"description":"Identifies this exact answer; send it back in If-None-Match.","schema":{"type":"string","examples":["\"3f9a0c1e5b7d2a4c6e8f0a1b2c3d4e5f\""]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Software"},"example":{"id":"proton-mail","name":"Proton Mail","description":"End-to-end encrypted email from Switzerland.","audience":["b2b","individual"],"country":"Switzerland","website":"https://proton.me/mail","longDescription":"Proton Mail is the flagship encrypted email …","features":["End-to-end encrypted email","…"],"useCases":["business-email"],"category":"communication"}}}},"304":{"description":"Not modified: the If-None-Match ETag still matches. No body.","headers":{"ETag":{"description":"Identifies this exact answer; send it back in If-None-Match.","schema":{"type":"string","examples":["\"3f9a0c1e5b7d2a4c6e8f0a1b2c3d4e5f\""]}}}},"404":{"description":"Software not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Software not found","code":"not_found","hint":"List known ids with GET /api/software, then retry with an existing kebab-case id."}}}}}},"429":{"description":"Too many requests","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","examples":[60]}},"X-RateLimit-Limit":{"description":"The limit that was reached, per 60 seconds: 60 for one IP address, 600 when the API as a whole is busy.","schema":{"type":"integer","examples":[60]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Too many requests","code":"rate_limited","hint":"Retry after the seconds in Retry-After, or read the snapshot files, which have no limit: https://data.euromakers.org/v1/software.json"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Internal server error","code":"internal_error","hint":"Retry later. If this persists, use /contact."}}}}}}}}},"/api/software/countries":{"get":{"operationId":"listSoftwareCountries","tags":["Directory"],"summary":"Countries of origin.","description":"An array of country names, each once, in directory order (not sorted).","externalDocs":{"description":"The same JSON as a snapshot file, rebuilt every night, with no rate limit and CORS for browsers.","url":"https://data.euromakers.org/v1/countries.json"},"parameters":[{"name":"If-None-Match","in":"header","required":false,"description":"The ETag of an earlier answer. When it still matches, the answer is a 304 with no body.","schema":{"type":"string"}}],"responses":{"200":{"description":"Countries of origin.","headers":{"Cache-Control":{"description":"Answers are cached at the edge and may be up to a day old.","schema":{"type":"string","examples":["public, max-age=60, s-maxage=86400, stale-while-revalidate=604800"]}},"ETag":{"description":"Identifies this exact answer; send it back in If-None-Match.","schema":{"type":"string","examples":["\"3f9a0c1e5b7d2a4c6e8f0a1b2c3d4e5f\""]}}},"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}},"example":["Germany","France","Slovakia","…"]}}},"304":{"description":"Not modified: the If-None-Match ETag still matches. No body.","headers":{"ETag":{"description":"Identifies this exact answer; send it back in If-None-Match.","schema":{"type":"string","examples":["\"3f9a0c1e5b7d2a4c6e8f0a1b2c3d4e5f\""]}}}},"429":{"description":"Too many requests","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","examples":[60]}},"X-RateLimit-Limit":{"description":"The limit that was reached, per 60 seconds: 60 for one IP address, 600 when the API as a whole is busy.","schema":{"type":"integer","examples":[60]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Too many requests","code":"rate_limited","hint":"Retry after the seconds in Retry-After, or read the snapshot files, which have no limit: https://data.euromakers.org/v1/software.json"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Internal server error","code":"internal_error","hint":"Retry later. If this persists, use /contact."}}}}}},"503":{"description":"Catalog temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Catalog temporarily unavailable","code":"catalog_unavailable","hint":"Retry later. The catalog database failed to load."}}}}}}}}},"/api/categories/counts":{"get":{"operationId":"countSoftwareByCategory","tags":["Directory"],"summary":"Products per category.","description":"An object of category id to number of products. Categories without products are left out.","externalDocs":{"description":"The same JSON as a snapshot file, rebuilt every night, with no rate limit and CORS for browsers.","url":"https://data.euromakers.org/v1/categories.json"},"parameters":[{"name":"If-None-Match","in":"header","required":false,"description":"The ETag of an earlier answer. When it still matches, the answer is a 304 with no body.","schema":{"type":"string"}}],"responses":{"200":{"description":"Products per category.","headers":{"Cache-Control":{"description":"Answers are cached at the edge and may be up to a day old.","schema":{"type":"string","examples":["public, max-age=60, s-maxage=86400, stale-while-revalidate=604800"]}},"ETag":{"description":"Identifies this exact answer; send it back in If-None-Match.","schema":{"type":"string","examples":["\"3f9a0c1e5b7d2a4c6e8f0a1b2c3d4e5f\""]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer","minimum":1}},"example":{"artificial-intelligence":13,"cloud":16,"communication":14}}}},"304":{"description":"Not modified: the If-None-Match ETag still matches. No body.","headers":{"ETag":{"description":"Identifies this exact answer; send it back in If-None-Match.","schema":{"type":"string","examples":["\"3f9a0c1e5b7d2a4c6e8f0a1b2c3d4e5f\""]}}}},"429":{"description":"Too many requests","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","examples":[60]}},"X-RateLimit-Limit":{"description":"The limit that was reached, per 60 seconds: 60 for one IP address, 600 when the API as a whole is busy.","schema":{"type":"integer","examples":[60]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Too many requests","code":"rate_limited","hint":"Retry after the seconds in Retry-After, or read the snapshot files, which have no limit: https://data.euromakers.org/v1/software.json"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Internal server error","code":"internal_error","hint":"Retry later. If this persists, use /contact."}}}}}},"503":{"description":"Catalog temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"default":{"value":{"error":"Catalog temporarily unavailable","code":"catalog_unavailable","hint":"Retry later. The catalog database failed to load."}}}}}}}}}},"components":{"schemas":{"ApiError":{"type":"object","additionalProperties":false,"required":["error","code","hint"],"properties":{"error":{"type":"string","description":"Human-readable explanation of what went wrong."},"code":{"type":"string","description":"Stable machine-readable error code for branching.","examples":["not_found","rate_limited","internal_error","catalog_unavailable"]},"hint":{"type":"string","description":"What to try next: another path or a retry."}}},"Software":{"type":"object","additionalProperties":false,"required":["id","name","description","audience","country","website","longDescription","features","useCases","category"],"properties":{"id":{"type":"string","description":"Stable id, also the end of the product’s page address.","pattern":"^[a-z0-9-]{1,80}$","examples":["proton-mail"]},"name":{"type":"string","description":"Product name.","examples":["Proton Mail"]},"description":{"type":"string","description":"One-sentence description."},"audience":{"type":"array","items":{"type":"string","enum":["b2b","individual"]},"description":"Who it’s for: b2b, individual or both.","minItems":1,"uniqueItems":true},"country":{"type":"string","description":"Country of origin.","examples":["Switzerland"]},"website":{"type":"string","format":"uri","description":"The product’s website."},"longDescription":{"type":"string","description":"A few paragraphs about the product."},"features":{"type":"array","items":{"type":"string"},"description":"Main features.","minItems":1},"useCases":{"type":"array","items":{"type":"string"},"description":"One to four use-case ids.","minItems":1,"maxItems":4,"uniqueItems":true,"examples":[["business-email"]]},"category":{"type":"string","description":"Category id, as in /categories/{id}.","examples":["communication"]},"verified":{"type":"boolean","const":true,"description":"true when the maker verified ownership; absent otherwise."},"logoUrl":{"type":"string","format":"uri","description":"Logo (PNG, JPEG or WebP); absent when there is none."}}}}}}