Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/eudr-dev:eudr-dev-agent-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: eudr.dev — EU Deforestation Regulation compliance Agent API
version: 0.3.0
description: eudr.dev is an independent AI agent that helps companies, SMEs, suppliers, buyers — and the AI agents that act on their behalf — navigate Reg. (EU) 2023/1115 via an A2A-native interface. Built on emem (https://github.com/Vortx-AI/emem), the open-source Earth-memory protocol that supplies every signed per-cell fact this agent cites. Generates signed Annex II Due Diligence Statements with content-addressed evidence and offline-verifiable receipts, not affiliated with, endorsed by, or sponsored by the European Commission or any EU institution. See /legal/disclaimer for the scope of service and /docs/audit/verify-offline for the offline-verification procedure.
contact:
name: Vortx AI Private Limited
email: avijeet@vortx.ai
servers:
- url: https://eudr.dev
description: This deployment
tags:
- name: Agent
description: Stateless, semantic /v1/* surface for AI agents.
paths:
/v1/spatial/verify:
post:
summary: Plot polygon → deforestation verdict + evidence CID
description: Hansen GFC + ESA WorldCover + JRC GFC2020 via emem.dev. Returns the verdict against the 2020-12-31 cut-off in Art. 2(13) Reg. (EU) 2023/1115.
operationId: spatialVerify
tags:
- Agent
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SpatialVerifyBody'
responses:
'200':
description: Verdict + evidence
content:
application/json:
schema:
$ref: '#/components/schemas/SpatialVerifyResponse'
'400':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit (60 rpm sliding window per IP)
/v1/evidence/{evidence_cid}:
get:
summary: Page the fact set behind a check
description: Resolve an `evidence_cid` minted by /v1/spatial/verify. The address is BLAKE3 over the canonical CID list, so it is re-derivable from the CIDs a response returned. A 404 means the handle is not held by this process (expired, or a restart); re-running the check returns the same measurements under new addresses rather than recovering these bytes, because each fact is signed with its signing time. For a citation that must outlive a day, cite the statement receipt.
operationId: resolveEvidence
tags:
- Agent
parameters:
- name: evidence_cid
in: path
required: true
schema:
type: string
- name: offset
in: query
schema:
type: integer
minimum: 0
default: 0
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 200
default: 50
responses:
'200':
description: One page of content-addressed facts.
'404':
description: No evidence set is held for this address.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/trace/{task_id}:
get:
summary: The complete derivation chain for a compiled statement
description: Everything here is already inside the signed statement; what this adds is order and attribution. Steps run from the polygon through grid addressing, signed measurement, algorithm evaluation against pinned registries, aggregation, the consignment verdict, citations, the independent guard verdict, the engine signature and the transparency-log anchor. Three keys sign parts of the chain and they are not interchangeable — `signing_parties` keeps them separate. A stage whose evidence is absent is emitted as absent WITH a reason rather than omitted, and `not_established` states what the chain does not show.
operationId: executionTrace
tags:
- Agent
parameters:
- name: task_id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: The derivation chain (schema eudr.execution_trace.v1).
'404':
description: No compile is held under that task_id.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: The compile has not produced a statement yet.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'410':
description: The statement was erased under GDPR Art. 17.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/mcp:
post:
summary: Model Context Protocol endpoint (JSON-RPC, not REST)
description: Dual-era Streamable HTTP MCP. Answers the legacy `initialize` handshake and the stateless 2026-07-28 revision (`server/discover`, per-request `_meta` protocol version, `resultType`, `ttlMs`/`cacheScope`, `Mcp-Method`/`Mcp-Name` validated against the body). This is NOT a REST resource and is described here only so a reader of this document knows it exists; the tool catalog is served by `tools/list`, and /.well-known/mcp.json carries the connection details. GET returns 405.
operationId: mcp
tags:
- Agent
requestBody:
required: true
content:
application/json:
schema:
type: object
description: A single JSON-RPC 2.0 request or notification. Batching is not supported.
responses:
'200':
description: JSON-RPC response.
'202':
description: Notification accepted, no body.
'400':
description: Header/body mismatch (-32020) or unsupported protocol version (-32022).
'404':
description: Unknown method (-32601).
/v1/dds/generate:
post:
summary: Operator + supplier + product + geolocation → signed Annex II Due Diligence…
description: 'Runs the 7-stage compile pipeline: geo → forest → legality → tenure → risk → dds → settle. Returns a SignedReceipt envelope (ed25519, CIDv1).'
operationId: ddsGenerate
tags:
- Agent
security:
- bearerAuth: []
- oauth2:
- eudr:write
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DDSGenerateBody'
responses:
'200':
description: Task started; poll /a2a/tasks/{id} until state=completed.
content:
application/json:
schema:
type: object
'402':
description: The organisation's credit wallet does not cover this compile. Nothing was charged and nothing was compiled.
'429':
description: Rate limit
/api/dds/{task_id}/traces.xml:
get:
summary: The TRACES NT submission XML for a negligible statement (409 for any other…
operationId: tracesXml
tags:
- Agent
parameters:
- name: task_id
in: path
required: true
schema:
type: string
responses:
'200':
description: application/xml
'409':
description: Not a filable (negligible) statement
/v1/receipt/verify:
post:
summary: Signed receipt JSON → boolean + re-derived CID + signer pubkey
operationId: receiptVerify
tags:
- Agent
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SignedReceipt'
responses:
'200':
description: Verification result.
/v1/reference/countries:
get:
summary: Country risk tiers per Implementing Reg. (EU) 2025/1093
operationId: referenceCountries
tags:
- Agent
responses:
'200':
description: 'Country table. Cacheable (Cache-Control: public, max-age=86400, immutable) with strong BLAKE3 ETag.'
/v1/reference/commodities:
get:
summary: Annex I commodity → HS prefix mapping per Reg. (EU) 2023/1115
operationId: referenceCommodities
tags:
- Agent
responses:
'200':
description: Commodity table. Cacheable.
components:
schemas:
DDSGenerateBody:
type: object
description: 'Either this shape, or a sample scenario as published at /samples/scenarios/*.json (with `production` for `geolocation` and `product.quantity_kg` for `net_mass_kg`), bare or wrapped as {"scenario": ...}. A missing field is named in the 400.'
required:
- operator
- supplier
- product
- geolocation
properties:
operator:
type: object
required:
- name
- country_of_establishment
properties:
name:
type: string
country_of_establishment:
type: string
description: ISO-3166-1 alpha-2
address:
type: string
eori:
type: string
role:
type: string
enum:
- operator
- trader
supplier:
type: object
required:
- name
- id
properties:
name:
type: string
id:
type: string
country:
type: string
address:
type: string
email:
type: string
product:
type: object
required:
- hs_code
- description
- net_mass_kg
properties:
hs_code:
type: string
example: '1801.00'
description:
type: string
net_mass_kg:
type: number
trade_name:
type: string
scientific_name:
type: string
geolocation:
type: object
required:
- country
- harvest_window
- plot_geojson
properties:
country:
type: string
description: ISO-3166-1 alpha-2 country of production
harvest_window:
type: string
example: 2025-10-12/2026-02-08
plot_geojson:
$ref: '#/components/schemas/GeoJSONGeometry'
plot_id:
type: string
description: 'The plot''s own id (a field, cadastral or cooperative code); it is filed under it. Never a person''s name: it is carried into a signed, public, append-only fact at the evidence provider.'
plot_area_ha:
type: number
description: 'For a Point plot: its area in hectares. Art. 2(28) allows a Point only for a plot of 4 ha or less; over 4 ha is refused.'
additional_plots:
type: array
description: Every further plot of the consignment.
items:
type: object
required:
- plot_id
- plot_geojson
properties:
plot_id:
type: string
plot_geojson:
$ref: '#/components/schemas/GeoJSONGeometry'
country:
type: string
description: When the plot is in another country than the consignment's.
harvest_window:
type: string
quantity_kg:
type: number
description: This plot's share; undeclared shares split the rest evenly.
area_ha:
type: number
description: 'For a Point plot: its area in hectares (4 ha or less).'
country_subregion:
type: string
producer:
type: object
properties:
name:
type: string
id:
type: string
SpatialVerifyResponse:
type: object
description: The verdict, what was inspected to reach it, and what was NOT checked. Every response names the unresolved checks so a clean deforestation result is never read as a clean due-diligence file.
properties:
deforestation_free:
type:
- boolean
- 'null'
post_cutoff_loss_cells:
type: integer
description: 'Signed population tally of cells with post-cut-off canopy loss, not the shipped sample. This is loss OBSERVED, not deforestation found: see `in_scope_loss_cells`.'
in_scope_loss_cells:
type: integer
description: Cells with post-cut-off loss on the plots that trip the Art. 2(13) gate — the loss the Regulation counts as deforestation. Below `post_cutoff_loss_cells` whenever the responder cleared a plot as non-forest at the cut-off, or under the 0.5 ha the Art. 2(4) forest definition requires. A row the responder cleared does not bar the consignment.
sub_mmu_loss_ha:
type: number
x-conditional: true
description: Hectares of sub-floor loss across the consignment, present only when they reach the floor together and that is why the verdict is indeterminate. One patch below 0.5 ha is not forest; a clearing split across twenty plots is.
forest_baseline:
type: string
description: The forest baseline the responder actually read, as it named it (e.g. `jrc_gfc2020_v4`).
precision_warnings:
type: array
items:
type: object
x-conditional: true
description: The responder's warnings, verbatim, that a plot's coordinates carry fewer than the six decimal digits Art. 2(28) requires of a geolocation. Omitted when there are none.
total_cells:
type: integer
verdict:
type: string
enum:
- negligible
- non_negligible
- not_in_scope
- indeterminate
description: 'Consignment verdict. `not_in_scope` here means the commodity is outside Annex I. A per-plot row''s `not_in_scope` means something else: the land was not forest at the 2020 cut-off, so the plot is deforestation-free by definition, and the consignment verdict can still be `negligible`.'
risk_score:
type: number
nullable: true
country_tier:
type: string
enum:
- low
- standard
- high
cut_off_date:
type: string
example: '2020-12-31'
per_plot:
type: array
description: One row per submitted plot, in submission order. A single-plot request still gets one row.
items:
type: object
properties:
plot_id:
type: string
verdict:
type: string
cells_evaluated:
type: integer
cells_with_post_cutoff_loss:
type: integer
area_ha_approx:
type: number
nullable: true
loss_assessment:
type: string
enum:
- in_scope_deforestation
- not_forest_at_cut_off
- below_minimum_mapping_unit
- no_loss
- undecided
description: What the loss on this plot amounts to in law. A cell count alone does not say, and reading it as though it did barred consignments the same response cleared.
loss_area_ha:
type: number
description: Hectares of post-cut-off loss, as the responder measured it. Omitted when it did not report one.
precision_warning:
type: string
description: The responder's warning that this plot's coordinates are below the six decimal digits Art. 2(28) requires. Omitted when clean.
coverage:
type: object
description: What was actually inspected. A verdict over 2 % of a polygon and a verdict over all of it are different claims.
properties:
cells_evaluated:
type: integer
cell_size_m:
type: number
example: 9.55
sampled_area_ha:
type: number
nullable: true
plot_area_ha:
type: number
nullable: true
sampled_polygon_fraction:
type: number
nullable: true
description: 1.0 is a full sweep.
sampling_note:
type: string
nullable: true
description: The upstream responder's own disclosure, verbatim.
per_cell_rows_returned:
type: integer
description: How many per-cell rows came back with the answer. `cells_evaluated` is the responder's signed population tally and is what every count here is on; these rows are the sample it shipped, and they are fewer.
loss_years_observed:
type: array
items:
type: integer
description: Distinct Hansen loss years in the shipped sample, ascending. Dates what was found; never counts it.
unresolved_checks:
type: array
items:
type: string
description: Checks this engine does not perform. Art. 3(b) legality is documentary and unobserved here.
evidence:
type: object
description: 'Note the nesting: `evidence_cid` lives HERE, not at the top level. An earlier revision of this document put it at the top level, which is a field the response has never carried.'
properties:
evidence_cid:
type: string
nullable: true
description: 'Content address of THIS response''s fact list. BLAKE3 over its canonical JSON, so a caller can re-derive it from the returned CIDs. It is not a fingerprint of the question: emem signs each fact with the moment it was signed, so re-running the same check returns the same measurements under new addresses. Resolve at /v1/evidence/{evidence_cid}.'
fact_count:
type: integer
description: How many facts the check resolved. Always present.
fact_cids:
type: array
items:
type: string
description: 'Omitted entirely when `evidence_detail: "anchor"` was sent.'
responder_pubkey_b32:
type: string
nullable: true
algorithm:
type: string
nullable: true
engine:
type: string
ApiError:
type: object
description: 'Every rejection on the /v1/* surface. A malformed body returns this with HTTP 400 and `error: "invalid_request"` — not a plain-text 422.'
required:
- error
- message
properties:
error:
type: string
description: Stable code to branch on, so a caller never string-matches prose that is free to be reworded.
enum:
- invalid_request
- invalid_json
- invalid_content_type
- upstream_unavailable
- rate_limit_exceeded
- evidence_not_held
- task_not_found
- not_compiled
- erased
- error
message:
type: string
description: A sentence a human can read.
field:
type: string
nullable: true
description: The field at fault, where one is known.
SpatialVerifyBody:
type: object
required:
- commodity
- country
description: Supply either `polygon` (one plot) or `plots` (up to eight). Supplying neither is a 400 naming the omission.
properties:
polygon:
$ref: '#/components/schemas/GeoJSONGeometry'
plots:
type: array
minItems: 1
maxItems: 25
description: Several plots in one request, each keeping its own verdict row. Art. 4(1) taints the whole consignment if any single plot fails, so they belong in one call.
items:
type: object
required:
- geojson
properties:
plot_id:
type: string
maxLength: 64
description: Echoed on the matching verdict row. [A-Za-z0-9-_.:] Keep it opaque — a farm or cadastral code, never a person's name. This one field is carried into a signed, public, append-only fact at the evidence provider, which cannot erase it without breaking the receipts that cite it.
geojson:
$ref: '#/components/schemas/GeoJSONGeometry'
commodity:
type: string
enum:
- cattle
- cocoa
- coffee
- oil_palm
- rubber
- soya
- wood
country:
type: string
description: ISO-3166-1 alpha-2.
minLength: 2
maxLength: 2
quantity_kg:
type: number
nullable: true
hs_code:
type: string
nullable: true
evidence_detail:
type: string
enum:
- cids
- anchor
default: cids
description: '`cids` embeds every per-cell fact CID; `anchor` returns only the address and count, resolvable at /v1/evidence/{evidence_cid}. The verdict is identical either way. On a real plot the array is the large majority of the body.'
SignedReceipt:
type: object
description: ed25519-signed Annex II envelope. Verifiable offline — see /docs/audit/verify-offline.
required:
- payload
- cid
- signature_b64
- pubkey_b32
properties:
payload:
type: object
description: Canonical Annex II JSON.
cid:
type: string
description: CIDv1 of the canonical payload (BLAKE3 + multibase 'b' base32).
signature_b64:
type: string
description: ed25519 signature over the CID bytes, base64-encoded.
pubkey_b32:
type: string
did:
type: string
issued_at:
type: string
format: date-time
GeoJSONGeometry:
type: object
description: GeoJSON Geometry — Polygon, MultiPolygon, or Point. WGS84 (EPSG:4326). Coordinates ordered [lng, lat].
required:
- type
- coordinates
properties:
type:
type: string
enum:
- Polygon
- MultiPolygon
- Point
coordinates: {}
examples:
- type: Polygon
coordinates:
- - - -6.11
- 5.2
- - -6.11
- 5.205
- - -6.105
- 5.205
- - -6.105
- 5.2
- - -6.11
- 5.2
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: 'An API key: sign in at /auth, open /app/#/api-keys, create one (shown once).'
oauth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://eudr.dev/oauth/authorize
tokenUrl: https://eudr.dev/oauth/token
scopes:
eudr:read: read the organisation's records
eudr:write: compile and sign statements
externalDocs:
url: https://eudr.dev/docs
description: Theory, methodology, architecture, and offline-verification guide.