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/blumee-app:blumee-app-search-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: Blumee Search API
version: 0.1.0
summary: Flower-delivery offers from German partner florists, searchable by text and photo.
description: 'Blumee compares bouquets and potted plants that vetted German florists deliver. This API is
the read side of that catalog: filter it, search it by meaning, or identify the flowers in a
photo and get offers that look like it.
### Three things worth knowing before the endpoint list
**No authentication, and none is coming.** There are no accounts, no keys, no sign-up. Send
requests. What protects the service is spend: 60 requests per minute per caller, plus a
daily budget on the endpoints that call a paid model. See `https://blumee.app/auth.md`.
**Blumee sells nothing.** Every order is placed with the named partner shop, and Blumee earns
an affiliate commission on referred purchases. Nothing here can place an order, and no
endpoint changes state.
**Send buyers through `https://blumee.app/go/{productId}?src=agent`.** That is the link to hand
a person — it records the click, attributes it, and forwards to the partner. Do not fetch it
yourself: a click no human made is worthless to them and corrupts the data on both sides.
The `affiliateUrl` some responses carry is the partner deep link behind it; using it directly
works but drops the attribution that pays for this catalog. And say the link is an ad — in
Germany that disclosure is a legal requirement, not a courtesy.
### Cheaper than this API
If you want the whole catalog rather than an answer to a question, fetch the static export at
`https://blumee.app/agent/offers.json`. It is a CDN file, needs no budget, and is regenerated
on every catalog rebuild. Pages of the site also carry in-browser WebMCP tools, and there are
agent skills at `https://blumee.app/.well-known/agent-skills/index.json`.
### Not described here
The app-internal endpoints (conversational chat, raw identification, telemetry, the build-time
dump, Prometheus metrics) are deliberately left out — they exist, they are not for general use,
and the shapes they return change with the app.'
contact:
name: Blumee
email: info@blumee.app
url: https://blumee.app/de/impressum/
termsOfService: https://blumee.app/de/agb/
license:
name: Blumee terms of use
url: https://blumee.app/de/agb/
servers:
- url: https://api.blumee.app
description: Production
security: []
tags:
- name: Search
description: Find offers by meaning or by photo. Budgeted.
paths:
/v1/search/text:
post:
tags:
- Search
operationId: searchText
summary: Search by meaning
description: 'Free-text search. The server extracts filters from the query with an LLM, embeds the
normalised query and ranks by vector similarity, so it answers a description
("something elegant but not stiff for my boss''s 60th birthday, under 50 EUR")
rather than a keyword list.
For a keyword list, `/v1/catalog` is faster, free and exact.
**Costs money** (one LLM extraction, cached, plus one embedding), so it is also under a daily budget: 200 calls per day from one address, 5000 across everyone, resetting at 00:00 UTC. Over it you get 429 `budget_exhausted`.
The extracted `filters` come back with the hits: show them or use them, because a query
the extractor read differently than you meant is the usual reason a result looks wrong.'
parameters:
- name: X-Device-Id
in: header
required: false
description: 'Optional caller-chosen UUID. It groups a session''s calls so the funnel from search to click can be joined, and it is what ends up as the affiliate `clickref` on a click you hand over. It is not authentication and grants nothing: rate limits are charged to your IP either way.'
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TextSearchRequest'
example:
query: etwas Elegantes zum 60. Geburtstag meiner Chefin, bis 50 Euro
lang: de
limit: 12
responses:
'200':
description: Ranked offers plus the filters the server read out of the query.
content:
application/json:
schema:
$ref: '#/components/schemas/TextSearchResponse'
'400':
description: Request failed validation.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit (`rate_limited`) or daily budget (`budget_exhausted`) exhausted. Both are per-connection first, so a retry from the same address will not help before `Retry-After`.
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
X-RateLimit-Limit:
description: Requests allowed in the current 60-second window.
schema:
type: integer
X-RateLimit-Remaining:
description: Requests left in the current window.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unhandled error.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/v1/search/photo:
post:
tags:
- Search
operationId: searchPhoto
summary: Search by photo
description: 'Upload a photo of a bouquet or a plant; get the species identified and offers that match.
**Costs money** (a Pl@ntNet identification and an OpenAI Vision call), so it is also under a daily budget: 40 calls per day from one address, 800 across everyone, resetting at 00:00 UTC. Over it you get 429 `budget_exhausted`. The Pl@ntNet
quota is a hard external ceiling shared with the mobile app, so this endpoint can refuse
while the rest of the API is fine.
**Ask before you call it.** It costs a paid identification per call and uploads someone
else''s photograph. If you can already see the picture yourself, you do not need this:
describe the arrangement to `/v1/search/text` instead — same catalog, no cost, faster.
`identify.matches[].confidence` are scores, not probabilities: 0.4 on the top match of a
mixed bouquet is normal. An empty `hits` with `intent: "houseplant"` is not a failure — the
catalog is mostly cut flowers.'
parameters:
- name: Accept-Language
in: header
description: Language of the identification labels. `de` or `en`; anything else is treated as `en`.
schema:
type: string
- name: X-Device-Id
in: header
required: false
description: 'Optional caller-chosen UUID. It groups a session''s calls so the funnel from search to click can be joined, and it is what ends up as the affiliate `clickref` on a click you hand over. It is not authentication and grants nothing: rate limits are charged to your IP either way.'
schema:
type: string
format: uuid
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required:
- images
properties:
images:
type: array
minItems: 1
maxItems: 3
description: One to three photos of the same arrangement, 10 MB each, `image/jpeg`, `image/png`, `image/webp` or `image/heic`. One good photo beats three mediocre ones.
items:
type: string
format: binary
mask_b64:
type: string
description: Optional base64 PNG foreground mask. When present, colours are sampled from the masked pixels only.
responses:
'200':
description: What the photo shows, and the offers that match it.
content:
application/json:
schema:
$ref: '#/components/schemas/PhotoSearchResponse'
'400':
description: Request failed validation.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: An image exceeded 10 MB.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: Unsupported image type.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit (`rate_limited`) or daily budget (`budget_exhausted`) exhausted. Both are per-connection first, so a retry from the same address will not help before `Retry-After`.
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
X-RateLimit-Limit:
description: Requests allowed in the current 60-second window.
schema:
type: integer
X-RateLimit-Remaining:
description: Requests left in the current window.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unhandled error.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
TextSearchResponse:
type: object
properties:
hits:
type: array
items:
$ref: '#/components/schemas/SearchHit'
total:
type: integer
minimum: 0
filters:
$ref: '#/components/schemas/ExtractedFilters'
timings:
type: object
properties:
extract:
type: number
minimum: 0
embed:
type: number
minimum: 0
search:
type: number
minimum: 0
total:
type: number
minimum: 0
required:
- extract
- embed
- search
- total
additionalProperties: false
cache:
type: object
properties:
extract:
type: boolean
required:
- extract
additionalProperties: false
required:
- hits
- total
- filters
- timings
- cache
additionalProperties: false
PhotoSearchHit:
type: object
properties:
id:
type: string
format: uuid
title:
type: string
price:
type: string
currency:
type: string
imageUrl:
type:
- string
- 'null'
image:
anyOf:
- type: object
properties:
src:
type: string
width:
anyOf:
- type: integer
exclusiveMinimum: 0
- type: 'null'
height:
anyOf:
- type: integer
exclusiveMinimum: 0
- type: 'null'
variants:
type: array
items:
type: object
properties:
url:
type: string
width:
type: integer
exclusiveMinimum: 0
required:
- url
- width
additionalProperties: false
required:
- src
- width
- height
- variants
additionalProperties: false
- type: 'null'
default: null
partner:
$ref: '#/components/schemas/CatalogPartner'
flowers:
type: array
items:
type: string
colors:
type: array
items:
type: string
occasion:
type:
- string
- 'null'
available:
type: boolean
source:
type: string
enum:
- catalog
- search
similarity:
type: number
minimum: 0
maximum: 1
required:
- id
- title
- price
- currency
- imageUrl
- partner
- flowers
- colors
- occasion
- available
- source
additionalProperties: false
IdentifyResponse:
type: object
properties:
ok:
type: boolean
const: true
language:
type: string
verdict:
type: string
enum:
- flower
- low_confidence
- no_known_genera
- not_a_bouquet
organConfidence:
anyOf:
- type: number
minimum: 0
maximum: 1
- type: 'null'
matches:
type: array
items:
$ref: '#/components/schemas/IdentifyMatch'
generaRollup:
type: array
items:
type: object
properties:
genus:
type: string
confidence:
type: number
minimum: 0
maximum: 1
knownSpecies:
type: boolean
label:
type: string
required:
- genus
- confidence
- knownSpecies
additionalProperties: false
palette:
type: array
items:
type: string
style:
type: string
occasionGuess:
type: string
arrangement:
type: object
properties:
shape:
type: string
symmetry:
type: string
stemCountEstimate:
type: integer
minimum: 0
wrapping:
type: string
required:
- shape
- symmetry
- stemCountEstimate
- wrapping
additionalProperties: false
freshness:
type: string
providersUsed:
type: array
items:
type: string
enum:
- plantnet
- openai-vision
raw:
type: object
properties:
plantnet:
anyOf:
- type: object
properties:
language:
type: string
bestMatch:
type:
- string
- 'null'
predictedOrgans:
type: array
items:
type: object
properties:
organ:
type: string
score:
type: number
required:
- organ
- score
additionalProperties: false
remainingRequests:
type: number
results:
type: array
items:
type: object
properties:
scientificName:
type: string
scientificNameWithoutAuthor:
type: string
genus:
type:
- string
- 'null'
family:
type:
- string
- 'null'
commonNames:
type: array
items:
type: string
score:
type: number
gbifId:
type: string
powoId:
type: string
iucnCategory:
type: string
required:
- scientificName
- scientificNameWithoutAuthor
- genus
- family
- commonNames
- score
additionalProperties: false
required:
- language
- bestMatch
- predictedOrgans
- remainingRequests
- results
additionalProperties: false
- type: 'null'
vision:
anyOf:
- type: object
properties:
model:
type: string
isBouquet:
type: boolean
isPottedPlant:
type: boolean
flowers:
type: array
items:
type: object
properties:
commonName:
type: string
scientificGuess:
type: string
approximateCount:
type: integer
minimum: 0
colors:
type: array
items:
type: string
confidence:
type: number
minimum: 0
maximum: 1
required:
- commonName
- scientificGuess
- approximateCount
- colors
- confidence
additionalProperties: false
colors:
type: array
items:
type: string
style:
type: string
occasionGuess:
type: string
overallConfidence:
type: number
minimum: 0
maximum: 1
arrangement:
type: object
properties:
shape:
type: string
symmetry:
type: string
stemCountEstimate:
type: integer
minimum: 0
wrapping:
type: string
required:
- shape
- symmetry
- stemCountEstimate
- wrapping
additionalProperties: false
freshness:
type: string
usage:
type: object
properties:
promptTokens:
type: integer
minimum: 0
completionTokens:
type: integer
minimum: 0
totalTokens:
type: integer
minimum: 0
required:
- promptTokens
- completionTokens
- totalTokens
additionalProperties: false
required:
- model
- isBouquet
- flowers
- colors
- style
- occasionGuess
- overallConfidence
- arrangement
- freshness
additionalProperties: false
- type: 'null'
required:
- plantnet
- vision
additionalProperties: false
timings:
type: object
additionalProperties:
type: integer
minimum: 0
propertyNames:
enum:
- plantnet
- openai-vision
required:
- ok
- language
- verdict
- organConfidence
- matches
- generaRollup
- providersUsed
- raw
- timings
additionalProperties: false
ExtractedColor:
type: object
properties:
hex:
type: string
pattern: ^#[0-9a-fA-F]{6}$
share:
type: number
minimum: 0
maximum: 1
name:
type: string
required:
- hex
- share
additionalProperties: false
Error:
type: object
description: Every non-2xx response has this shape. `code` is stable and safe to branch on; `message` is prose and may change.
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
enum:
- validation_error
- bad_request
- not_found
- payload_too_large
- unsupported_media_type
- rate_limited
- budget_exhausted
- service_unavailable
- internal
message:
type: string
details:
description: Present on validation errors and budget refusals.
SearchHit:
type: object
properties:
id:
type: string
format: uuid
title:
type: string
description:
type:
- string
- 'null'
price:
type: string
currency:
type: string
imageUrl:
type:
- string
- 'null'
imageUrls:
type: array
items:
type: string
images:
type: array
items:
type: object
properties:
src:
type: string
width:
anyOf:
- type: integer
exclusiveMinimum: 0
- type: 'null'
height:
anyOf:
- type: integer
exclusiveMinimum: 0
- type: 'null'
variants:
type: array
items:
type: object
properties:
url:
type: string
width:
type: integer
exclusiveMinimum: 0
required:
- url
- width
additionalProperties: false
required:
- src
- width
- height
- variants
additionalProperties: false
default: []
partner:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
required:
- id
- name
additionalProperties: false
flowers:
type: array
items:
type: string
colors:
type: array
items:
type: string
occasion:
type:
- string
- 'null'
affiliateUrl:
type: string
similarity:
type: number
required:
- id
- title
- description
- price
- currency
- imageUrl
- imageUrls
- partner
- flowers
- colors
- occasion
- affiliateUrl
- similarity
additionalProperties: false
IdentifyMatch:
type: object
properties:
kind:
type: string
enum:
- species
- genus
- label
scientificName:
type: string
genus:
type: string
family:
type: string
label:
type: string
confidence:
type: number
minimum: 0
maximum: 1
knownSpecies:
type: boolean
speciesId:
type: string
format: uuid
gbifId:
type: string
providers:
type: array
items:
type: string
enum:
- plantnet
- openai-vision
minItems: 1
approximateCount:
type: integer
minimum: 0
colors:
type: array
items:
type: string
aliasesDe:
type: array
items:
type: string
required:
- kind
- scientificName
- confidence
- knownSpecies
- providers
additionalProperties: false
PhotoSearchResponse:
type: object
properties:
identify:
$ref: '#/components/schemas/IdentifyResponse'
intent:
type: string
enum:
- bouquet
- houseplant
- unknown
default: unknown
hits:
type: array
items:
$ref: '#/components/schemas/PhotoSearchHit'
total:
type: integer
minimum: 0
breakdown:
type: object
properties:
catalog:
type: integer
minimum: 0
search:
type: integer
minimum: 0
merged:
type: integer
minimum: 0
required:
- catalog
- search
- merged
additionalProperties: false
extractedColors:
type: array
items:
$ref: '#/components/schemas/ExtractedColor'
default: []
timings:
type: object
properties:
identify:
type: integer
minimum: 0
catalog:
type: integer
minimum: 0
search:
type: integer
minimum: 0
colors:
type: integer
minimum: 0
default: 0
total:
type: integer
minimum: 0
required:
- identify
- catalog
- search
- total
additionalProperties: false
required:
- identify
- hits
- total
- breakdown
- timings
additionalProperties: false
CatalogPartner:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
required:
- id
- name
additionalProperties: false
TextSearchRequest:
type: object
properties:
query:
type: string
minLength: 1
maxLength: 500
lang:
type: string
enum:
- en
- de
filters:
type: object
properties:
flowers:
type: array
items:
type: string
colors:
type: array
items:
type: string
occasion:
type: string
size:
type: string
enum:
- small
- medium
- large
style:
type: string
priceMaxEur:
type: number
exclusiveMinimum: 0
priceMinEur:
type: number
minimum: 0
deliveryMaxDays:
type: integer
exclusiveMinimum: 0
additionalProperties: false
limit:
type: integer
minimum: 1
maximum: 50
default: 20
required:
- query
- lang
additionalProperties: false
ExtractedFilters:
type: object
properties:
flowers:
type: array
items:
type: string
default: []
colors:
type: array
items:
type: string
default: []
occasion:
type:
- string
- 'null'
default: null
style:
type:
- string
- 'null'
default: null
size:
anyOf:
- type: string
enum:
- small
- medium
- large
- type: 'null'
default: null
priceMinEur:
type:
- number
- 'null'
default: null
priceMaxEur:
type:
- number
- 'null'
default: null
deliveryMaxDays:
anyOf:
- type: integer
exclusiveMinimum: 0
- type: 'null'
default: null
normalisedQuery:
type: string
required:
- normalisedQuery
additionalProperties: false
externalDocs:
description: How to use Blumee as an agent, in prose.
url: https://blumee.app/agent/api.md