Developer reference

MyForestPass API, version 1

An HTTP interface to the records your organisation holds in MyForestPass. Most of it is read-only. A small, deliberately narrow write path exists for stands and map features, and it is governed by separate scopes: a read key can never write. No key, of any kind, can reach outside the organisation that issued it.

Base address

https://myforestpass.com/api/public/v1

Authentication

Send your key as a bearer token. Keys are issued in the platform under Integrations, then API keys, and are shown exactly once.

curl https://myforestpass.com/api/public/v1/woodlands \
  -H "Authorization: Bearer mfp_live_…"

Scopes

A key holds only the scopes chosen at issue. Each resource requires one.

ScopeGrants
forests:readOrganisations, forests and managed properties.
stands:readStand records and approved stand metrics.
passports:readIssued passport metadata and public verification state.
twin:readSurvey missions, sealed epochs and approved tree datasets.
monitoring:readMonitoring programme summaries and observation counts.
lifecycle:readLifecycle stage summaries for a woodland.
certification:readCertification status summaries.
traceability:readTimber lot and consignment summaries.
reports:readMetadata for issued reports. Never the report contents.
gis:readMap layers and map feature metadata.
climate:readRecorded climate runs, indicators, suitability and adaptation prompts.
ecosystem:readEcosystem assessments, recorded evidence and computed indicators.
exchange:readThe organisation's own listings and their evidence links, with claim status attached.
stands:writeUpdate stand attributes. Grant sparingly.
gis:writeCreate and update map features as unverified source data.

Resources

GET /api/public/v1/organisationsforests:read

The organisation this key belongs to.

Filters: none

GET /api/public/v1/woodlandsforests:read

Woodlands and managed properties.

Filters: county, country, certification_status, primary_management_pathway

GET /api/public/v1/standsstands:read

Stand records for a woodland.

Filters: woodland_id, dominant_species, management_status

GET /api/public/v1/stand-metricsstands:read

Derived and measured stand metrics, with their evidence state.

Filters: woodland_id, stand_id, metric_kind, evidence_status

GET /api/public/v1/passportspassports:read

Passport metadata and verification state. Never the QR token.

Filters: woodland_id, subject_type, verification_status

GET /api/public/v1/twin-missionstwin:read

Survey missions.

Filters: woodland_id, stand_id, status, capture_method

GET /api/public/v1/twin-epochstwin:read

Sealed survey epochs.

Filters: woodland_id, mission_id, stand_id

GET /api/public/v1/tree-datasetstwin:read

Machine-extracted tree datasets and their review state.

Filters: woodland_id, stand_id, review_status

GET /api/public/v1/monitoring-programmesmonitoring:read

Monitoring programme summaries.

Filters: woodland_id, status, frequency

GET /api/public/v1/lifecycle-reportslifecycle:read

Issued report metadata and content hash. Never the report body.

Filters: woodland_id, report_kind

GET /api/public/v1/certificationscertification:read

Certification status summaries.

Filters: woodland_id, status, scheme_id

GET /api/public/v1/timber-lotstraceability:read

Timber lot summaries.

Filters: woodland_id, stand_id, status, species

GET /api/public/v1/consignmentstraceability:read

Consignment summaries and custody state.

Filters: woodland_id, timber_lot_id, status, custody_state

GET /api/public/v1/map-layersgis:read

Map layer definitions.

Filters: woodland_id, feature_type

GET /api/public/v1/map-featuresgis:read

Map feature metadata and geometry, as GeoJSON.

Filters: woodland_id, stand_id, layer_id, feature_type, evidence_status

GET /api/public/v1/climate-assessmentsclimate:read

Recorded climate runs, with the engine version and scenarios each one used.

Filters: woodland_id, stand_id, status

GET /api/public/v1/climate-indicatorsclimate:read

Indicator values with provenance, confidence, uncertainty and — where a figure could not be produced — the reason it is blank.

Filters: woodland_id, assessment_id, indicator_key, scenario, horizon_year

GET /api/public/v1/climate-species-suitabilityclimate:read

Indicative species suitability screen results.

Filters: woodland_id, assessment_id, species, scenario, horizon_year

GET /api/public/v1/climate-adaptation-optionsclimate:read

Advisory adaptation prompts derived from indicator values.

Filters: woodland_id, assessment_id, scenario, priority

GET /api/public/v1/ecosystem-assessmentsecosystem:read

Ecosystem-services assessments and the framework version each one used.

Filters: woodland_id, stand_id, status

GET /api/public/v1/ecosystem-indicatorsecosystem:read

Computed ecosystem indicators. Condition measures only — never credits, valuations or compliance statements.

Filters: woodland_id, assessment_id, service, indicator_key

GET /api/public/v1/ecosystem-evidenceecosystem:read

The recorded observations an ecosystem indicator was calculated from.

Filters: woodland_id, assessment_id, service, evidence_kind, metric_key

GET /api/public/v1/exchange-listingsexchange:read

Listings owned by this organisation. `claim_status` states whether the listing is evidence-backed, indicative/modelled or self-declared.

Filters: woodland_id, kind, status, visibility, claim_status, county, country

GET /api/public/v1/exchange-listing-evidenceexchange:read

What each listing figure is based on. `provenance` and `claim_basis` say whether a number was measured, derived or modelled.

Filters: listing_id, source_table, provenance, claim_basis, evidence_status

Append a UUID to fetch one record, for example /api/public/v1/stands/<id>.

Writing

Writes are confined to the resources below, each behind its own :write scope. Anything that arrives over the API is recorded as unverified source data: it is never marked verified, and it does not bypass the platform’s own review steps.

PATCH /api/public/v1/standsstands:write

Update stand attributes. Areas and species remain subject to platform review.

Updatable fields: name, compartment_reference, area_hectares, dominant_species, establishment_year, yield_class, notes

POST / PATCH /api/public/v1/map-featuresgis:write

Create and update map features. Everything written arrives as unverified source data.

Creatable fields: woodland_id, name, feature_type, geometry, reference, description, attributes

Updatable fields: name, reference, description, geometry, attributes

Every write needs an idempotency key

Send Idempotency-Key with each write. A retry using the same key and the same body returns the original response — marked Idempotent-Replay: true — rather than repeating the change. The same key with a different body is refused.

Every update states the version it edits

Include the record_version you read. If the record has moved on, the request is refused with version_conflict and the current version, so a change made by somebody else is never silently overwritten. The version is applied as a condition of the write itself, so two simultaneous callers cannot both succeed.

curl -X PATCH https://myforestpass.com/api/public/v1/stands/<id> \
  -H "Authorization: Bearer mfp_live_…" \
  -H "Idempotency-Key: fieldwork-2026-02-04-0001" \
  -H "Content-Type: application/json" \
  -d '{"record_version": 3, "dominant_species": "Douglas fir"}'

A field the catalogue does not list is an error, not something quietly dropped. Every write is logged against the key, with its correlation identifier, whether it succeeded or not.

Pagination and filtering

Use limit (default 50, maximum 200) and offset. Add updated_since with an ISO 8601 timestamp to fetch changes only. An unrecognised filter is refused rather than ignored.

{
  "data": [ … ],
  "meta": { "limit": 50, "offset": 0, "returned": 50, "total": 214, "has_more": true }
}

Rate limits

Each key has a per-minute limit set when it is issued. Responses carry X-RateLimit-Limit and X-RateLimit-Remaining; a refused request returns 429 with Retry-After.

Errors

Every failure returns the same shape, including a correlation identifier you can quote when asking for help.

{
  "error": {
    "code": "insufficient_scope",
    "message": "This key does not hold the stands:read scope.",
    "correlation_id": "0f0c…",
    "documentation": "https://myforestpass.com/api-docs"
  }
}
CodeHTTPMeaning
unauthorized401No key was sent, or the key is not recognised.
revoked401The key was revoked. Issue a new one.
expired401The key passed its expiry date.
insufficient_scope403The key does not hold the scope this resource requires.
not_found404No record with that identifier is visible to this key.
unknown_resource404The path does not name a version 1 resource.
invalid_request400A filter or identifier was not accepted.
rate_limited429The key exceeded its per-minute limit. Retry after the stated interval.
server_error500The request could not be completed.
method_not_allowed405That resource does not accept this method.
idempotency_key_required400A write was sent without an Idempotency-Key header.
idempotency_key_reused409That idempotency key was already used for a different body.
record_version_required428A PATCH was sent without the record_version being edited.
version_conflict409The record moved on since you read it. Re-read and retry.
validation_failed422The body named a field that cannot be written, or a value that is not acceptable.
invalid_geometry422The geometry supplied is not valid GeoJSON.
outside_organisation403The record named belongs to another organisation.

What the API does not do

Issue a key in the platform