Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.1.0
info:
title: Rett fra Bonden — Lokal Mat API
description: Finn lokale matprodusenter i Norge. Søk blant 1 100+ gårdsbutikker, markeder og REKO-ringer etter kategori, sted og sesong.
version: 1.0.0
servers:
- url: https://rettfrabonden.com
description: Production
paths:
/api/marketplace/search:
get:
operationId: searchFood
summary: Natural language food search
description: >-
Search for local food using natural language in Norwegian or English.
Returns producers ranked by relevance, with distance when a position is
known. For "near me" searches, supply lat + lng (and optionally radius)
— q is then optional, and coordinates alone is a complete search.
Read-only: this never contacts a producer unless start_conversation=true.
parameters:
- name: q
in: query
required: false
description: >-
Natural language search query (Norwegian or English). Optional when
lat and lng are supplied; one of q or lat+lng is required.
schema:
type: string
example: "økologisk ost nær Bergen"
- name: lat
in: query
required: false
description: Latitude (WGS84) of the user's position, for proximity search.
schema:
type: number
minimum: -90
maximum: 90
example: 60.3913
- name: lng
in: query
required: false
description: Longitude (WGS84). Must be supplied together with lat.
schema:
type: number
minimum: -180
maximum: 180
example: 5.3221
- name: radius
in: query
required: false
description: Search radius in km around lat/lng. Default 30, clamped to 1–500.
schema:
type: number
minimum: 1
maximum: 500
default: 30
- name: heleNorge
in: query
required: false
description: Set to "true" to opt out of geo filtering and search all of Norway.
schema:
type: string
enum: ["true"]
- name: start_conversation
in: query
required: false
description: >-
Opt in to starting a conversation with the top matches. Defaults to
off — searching is read-only and never messages a producer.
schema:
type: string
enum: ["true"]
- name: limit
in: query
required: false
description: Max results (default 20)
schema:
type: integer
default: 20
responses:
"200":
description: Search results
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
query:
type: string
count:
type: integer
geoFiltered:
type: boolean
description: >-
True only when the results really were restricted to a
place. False when no position was resolved, or when the
auto-expanding radius had to drop the geo filter to find
anything (see relaxed_filters and note).
geoSource:
type: string
description: Where the position came from — browser, hardcoded, database, kartverket, kommuneinfo, or none.
geoRadiusKm:
type: number
description: The radius actually applied. May be wider than the one requested, because too few results triggered the auto-expand ladder.
relaxed_filters:
type: array
description: Filters that had to be dropped to return anything. Contains "geo" when the search was widened to all of Norway.
items:
type: string
needs_location:
type: boolean
description: True when the query asked for something nearby ("nær meg") but no position was available. Re-issue the request with lat and lng.
note:
type: string
description: Bilingual, human-readable explanation when the search did something other than what was literally asked for.
results:
type: array
items:
type: object
properties:
relevanceScore:
type: number
distanceKm:
type: number
description: >-
Deprecated at the result level — read
agent.location.distanceKm instead, and see the honesty
rule documented there (a centroid-precision producer
reports no kilometre figure at all).
matchReasons:
type: array
items:
type: string
agent:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
categories:
type: array
items:
type: string
tags:
type: array
items:
type: string
location:
type: object
description: >-
Where the producer is, and how precisely we know it.
distanceKm is present ONLY when geoPrecision is "address";
for a city/kommune-centroid position it is omitted on
purpose and distanceLabel carries the honest alternative,
because a kilometre figure measured from a municipal
centroid would be a number we invented. Producers whose
coordinate provenance is unknown (geoPrecision absent —
legacy rows not yet processed by the geocoding worker)
still carry distanceKm, unchanged.
properties:
city:
type: string
lat:
type: number
lng:
type: number
distanceKm:
type: number
description: >-
Straight-line distance from the searched position, in km.
Present only for geoPrecision "address", or for a legacy
row with no geoPrecision at all. Never present for
"city"/"kommune"/"postal".
geoPrecision:
type: string
enum: [address, postal, city, kommune]
description: >-
How the coordinates were resolved. "address" = geocoded
from a real street address (Kartverket adresser/v1/sok).
"city"/"kommune" = an approximate centroid. Absent =
unknown provenance (row not yet processed).
distanceLabel:
type: string
description: >-
Human-readable, honest location phrase — "2,4 km unna"
for address precision, "i Vadsø-området" for a centroid.
Safe to show verbatim; never contains a fabricated number.
/api/marketplace/discover:
post:
operationId: discoverProducers
summary: Structured producer discovery
description: Find producers by category, tags, and location. Use this for precise filtering when the user specifies exact criteria.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
categories:
type: array
items:
type: string
description: "Food categories, e.g. ['Gårdsbutikk', 'Honning', 'Økologisk']"
tags:
type: array
items:
type: string
lat:
type: number
description: Latitude (e.g. 59.91 for Oslo)
lng:
type: number
description: Longitude (e.g. 10.75 for Oslo)
maxDistanceKm:
type: number
default: 50
limit:
type: integer
default: 20
responses:
"200":
description: Matched producers
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
count:
type: integer
results:
type: array
items:
type: object
properties:
relevanceScore:
type: number
distanceKm:
type: number
description: >-
Deprecated at the result level — read
agent.location.distanceKm instead, and see the honesty
rule documented there (a centroid-precision producer
reports no kilometre figure at all).
agent:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
categories:
type: array
items:
type: string
location:
type: object
description: >-
Where the producer is, and how precisely we know it.
distanceKm is present ONLY when geoPrecision is "address";
for a city/kommune-centroid position it is omitted on
purpose and distanceLabel carries the honest alternative,
because a kilometre figure measured from a municipal
centroid would be a number we invented. Producers whose
coordinate provenance is unknown (geoPrecision absent —
legacy rows not yet processed by the geocoding worker)
still carry distanceKm, unchanged.
properties:
city:
type: string
lat:
type: number
lng:
type: number
distanceKm:
type: number
description: >-
Straight-line distance from the searched position, in km.
Present only for geoPrecision "address", or for a legacy
row with no geoPrecision at all. Never present for
"city"/"kommune"/"postal".
geoPrecision:
type: string
enum: [address, postal, city, kommune]
description: >-
How the coordinates were resolved. "address" = geocoded
from a real street address (Kartverket adresser/v1/sok).
"city"/"kommune" = an approximate centroid. Absent =
unknown provenance (row not yet processed).
distanceLabel:
type: string
description: >-
Human-readable, honest location phrase — "2,4 km unna"
for address precision, "i Vadsø-området" for a centroid.
Safe to show verbatim; never contains a fabricated number.
/api/marketplace/agents/{agentId}/info:
get:
operationId: getProducerInfo
summary: Get full producer details
description: Returns complete information about a producer including address, products, opening hours, certifications, and trust score.
parameters:
- name: agentId
in: path
required: true
schema:
type: string
responses:
"200":
description: Producer details with knowledge data
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
agent:
type: object
properties:
id:
type: string
name:
type: string
description:
type: string
knowledge:
type: object
properties:
address:
type: string
products:
type: array
items:
type: string
openingHours:
type: string
about:
type: string
certifications:
type: array
items:
type: string
paymentMethods:
type: array
items:
type: string
deliveryOptions:
type: array
items:
type: string
/api/marketplace/geocode:
get:
operationId: geocodePlace
summary: Geocode a Norwegian place name
description: Resolve a Norwegian place name (city, town, region, fylke, or kommune) to lat/lng coordinates with a suggested search radius. Use when you need explicit coordinates for the discoverProducers endpoint (e.g., 'show me organic farms within 10 km of Florø'). Covers all of Norway via Kartverket Stedsnavn API fallback.
parameters:
- name: place
in: query
required: true
description: Norwegian place name (city, town, region, fylke, kommune)
schema:
type: string
example: "Florø"
responses:
"200":
description: Coordinates found
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
place:
type: string
result:
type: object
properties:
name:
type: string
lat:
type: number
lng:
type: number
radiusKm:
type: number
source:
type: string
enum: [cache, hardcoded, database, kartverket]
"404":
description: Place not found
"400":
description: Missing place parameter
/api/marketplace/catalog/acp-feed.csv:
get:
operationId: getAcpProductFeed
summary: ACP product feed (CSV)
description: >-
RFB-only, ACP-conformant (OpenAI Agentic Commerce Protocol, non-Ads)
CSV product feed of verified, in-stock, non-umbrella producers'
products, so they can be discovered in ChatGPT shopping surfaces.
Discovery-only — no checkout/payment integration
(is_eligible_checkout is always "false"). Reuses the same
filter/source as the JSON feed at /api/marketplace/catalog/feed.
Rows missing a required field (image_url or price) are skipped; the
count skipped is reported in the X-Acp-Feed-Skipped-Count response
header.
responses:
"200":
description: CSV product feed
content:
text/csv:
schema:
type: string
example: |
item_id,title,description,brand,url,image_url,price,availability,is_eligible_search,is_eligible_checkout,target_countries,product_category
prod-123,Økologiske Poteter,Ferske poteter fra gården,Åsen Gård,https://rettfrabonden.com/produsent/asen-gard,https://rettfrabonden.com/images/poteter.jpg,275.00 NOK,in_stock,true,false,NO,grønnsaker
/api/stats:
get:
operationId: getPlatformStats
summary: Platform statistics
description: Returns current platform metrics — total producers, cities covered, and interaction count.
responses:
"200":
description: Platform stats
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: object
properties:
totalAgents:
type: integer
totalCities:
type: integer
totalInteractions:
type: integer