Crops API: Unified text and image retrieval for maize and rice

Four operations on a single per-crop namespace. Text chat returns ranked passages from the curated crop knowledge base. Text diagnose runs a short, multi-turn disambiguation funnel over the same KB. Media search returns annotated reference images. Media diagnose runs the same disambiguation funnel against the image library. Both funnels are designed for the words farmers actually use, colour, shape, location on the leaf, not technical jargon.

POST /api/v1/crops/{plant}/* Scopes: crop:search / media:search

What is the Crops API?

The Crops API exposes FildraAI's two crop experts, maize and rice, through a single per-crop namespace. Each crop has four operations: text chat (passages from the knowledge base), text diagnose (multi-turn funnel over the KB), media search (reference images), and media diagnose (multi-turn funnel over the image library). Both diagnose funnels accept everyday descriptive language rather than agronomy terminology; when a query is too ambiguous to retrieve confidently the API asks one short clarifying question at a time.

The Crops API supersedes the legacy /api/v1/chat/message and /api/v1/media/{plant}/* routes. Those routes remain live during the migration window but return deprecation headers (see Deprecated routes below). New integrations should target /api/v1/crops/{plant}/* exclusively.

What you do NOT get from this API

To protect the research and curated KB that make the experts useful, responses are scrubbed of internal scoring fields. You will not see candidate ranking weights, the question-bank boost/penalty matrices, the funnel's internal session state, or raw retrieval scores. You see the final answer or the next clarifying question, the same surface our own apps render, and nothing that would let a competitor reconstruct the orchestration logic.

Authentication

All Crops API endpoints require a valid API key. Use the X-Api-Key header (Bearer tokens are also accepted):

X-Api-Key: YOUR_API_KEY
Authorization: Bearer YOUR_API_KEY

Text operations require the crop:search scope. Media operations require the media:search scope. Keys are issued per application from the FildraAI developer dashboard and can be scoped to a single crop (e.g. crop:maize) for tiered billing. Requests without a valid key return 401 Unauthorized; missing scope returns 403 Forbidden.

Usage billing

All POST requests on the Crops API are billed per call, tracked against the API key used in the request. Diagnose-funnel turns are each billed as a single call, three turns to converge counts as three calls. The free tier is capped low (sufficient for evaluation, insufficient for any real product). Heavy callers should contact us about enterprise pricing.

Endpoints

POST /api/v1/crops/{plant}/chat

Text RAG over the crop KB. Send a natural-language query, receive ranked passages with source attribution. Scope: crop:search.

POST /api/v1/crops/{plant}/diagnose

Multi-turn text diagnostic funnel. The API asks 1–3 short clarifying questions before returning a top-candidate disease plus supporting passages. Scope: crop:search.

POST /api/v1/crops/{plant}/media/search

Image search. Query the annotated crop image library by natural-language description. Scope: media:search.

POST /api/v1/crops/{plant}/media/diagnose

Multi-turn image diagnostic funnel. Same staged contract as text diagnose but the funnel asks physical questions (raised vs flat, powder vs no powder) and returns matched reference images. Scope: media:search.

{plant} is currently one of maize or rice. Both crops use the same request and response envelopes; the underlying KB and image catalogue are crop-specific.

Acceptable use

Do not train competing systems on Crops API output.

You may use Crops API responses to render guidance to your own end users (farmers, agronomists, extension workers, integrators). You may NOT use the responses, passages, diagnoses, image metadata, retrieval scores, or session payloads, to build a derivative classifier, knowledge base, or diagnostic system that competes with FildraAI or any FildraAI partner offering. Bulk scraping of the API for model-distillation purposes is a Terms-of-Service violation. We monitor request patterns and reserve the right to revoke keys that show distillation-style usage.

Attribution requirement

Any user-visible surface that renders Crops API content must show "Powered by FildraAI" in a reasonable, persistent location (footer, About panel, response card). This is a low-friction acknowledgement that signals to your users where the underlying expertise comes from and protects everyone from the misperception that an unverified third-party tool is the source of agronomic guidance.

Advisory only, agricultural decisions

The Crops API returns reference information from a curated knowledge base. It does not replace agronomic judgement, local extension support, or laboratory diagnosis. Use it as a decision aid alongside other tools. FildraAI does not warrant outcomes that result from acting on API output alone.

Text chat, passage retrieval

POST /api/v1/crops/{plant}/chat retrieves the top-k most relevant knowledge-base passages for a natural-language query, scoped to the crop in the URL path. This is the right endpoint when you want curated reference content to display alongside a user question.

Required

  • text (string), Natural-language query

Optional

  • locale (string, default en-us), Response language
  • k (integer 1–20, default 6), Maximum passages to return
  • client_request_id (string), Idempotency key for safe retries

Example request

curl -X POST "https://api.fildraai.com/api/v1/crops/maize/chat" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "maize leaf blight",
    "locale": "en-us",
    "k": 6
  }'

Response includes ok, reply (short summary), docs[] (ranked passages with id, title, section, content, score), and a public meta block (plant, locale, k, build_id). Internal facet routing and oversample debug fields are stripped from the response.

Text diagnose, multi-turn funnel

POST /api/v1/crops/{plant}/diagnose runs a staged disambiguation flow. The first turn classifies the query into a symptom frame; if confidence is too low to commit to a diagnosis, the API returns one short clarifying question. Echo the returned session on the next turn with the farmer's answer added, and the funnel narrows. After three answers it commits regardless.

Required

  • q (string), Farmer's natural-language description

Optional

  • locale (string, default en-us)
  • k (integer 1–20, default 6), Passages to return when the funnel commits
  • session (object), Echo the previous response's session on turn 2+, with the answer added under session.answers[question_id]

Example, turn 1

curl -X POST "https://api.fildraai.com/api/v1/crops/maize/diagnose" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "q": "leaves turned brown and dried up",
    "locale": "en-us"
  }'

The MVP funnel asks at most three questions, in priority order:

  1. Growth stage, seedling / vegetative / tillering or jointing / heading or flowering / grain fill / mature
  2. Plant part, leaves / stalk or stem / sheath / panicle or tassel / roots / whole plant
  3. Colour, yellow / orange rust / brown-tan / grey-white / black / purple-red

Response envelope

Every turn returns the same fields: action ("ask_question" or "show_passages"), ambiguity, confidence, candidates[] (top disease slugs), diagnosis (top class when committed), question (with id, ask, options, importance, never the internal boost/penalise dicts), items[], why (user-readable rationale, no score values), and session (opaque, echo back unchanged).

Media search, response schema

The intended successful search response returns a job-style result with matched image items. Production currently returns a 500 job creation error for search and diagnose routes, so treat this schema as the contract to use once the media queue path is healthy again.

{
  "ok": true,
  "count": 5,
  "items": [
    {
      "id": "img_abc123",
      "title": "Rice leaf blight reference image",
      "file": "rice_leaf_blight_001.jpg",
      "plant": "rice",
      "class": "bacterial_leaf_blight",
      "topic": "disease",
      "locale": "en-us",
      "score": 0.91,
      "media_download_url": "https://...",
      "tags": ["leaf", "lesion", "blight"],
      "category": "field",
      "image_group": "rice_blight_set_a"
    }
  ],
  "meta": {
    "query": "yellowing leaves with brown spots",
    "plant": "rice",
    "locale": "en-us",
    "took_ms": 124
  }
}

Each item in items represents a matched reference image. The score field is only present if include_scores was set to true in the request. Internal storage URLs are stripped from the response for security, use media_download_url to access the image.

Media diagnose, staged image funnel

The /diagnose endpoint runs a multi-turn disambiguation flow. Rather than immediately returning images, it may first ask one or more clarifying questions to narrow the search. This is useful when a description could match multiple disease classes.

Turn 1, Initial query

  • Send q and locale; omit session
  • If action is ask_question, show the question from question.ask to the user
  • Store the full session object from the response

Turn 2+, Answer and continue

  • Echo the session object from the previous response
  • Add the farmer's answer inside session.answers[question_id]
  • When action becomes show_images, the items array contains the matched images

Confidence threshold

The diagnostic flow moves to show_images once confidence exceeds 0.75 or after three disambiguation rounds, whichever comes first. The ambiguity field in each response (one of very_high, high, medium, low) reflects current uncertainty.

Farmer language coverage

The funnel does not require a farmer to know plant-pathology vocabulary like lesion, whorl, or chlorotic. It maps everyday descriptive words to symptom groups, then uses those groups to score candidate diseases. The complete keyword table is below, use it to set client-side hints and example prompts.

Symptom group Recognised words What it signals
spots spot, spots, lesion, lesions, mark, marks, dot, dots, speck, specks Generic discrete-mark group. High-ambiguity on its own.
browning brown, browning, brownish, tan, tannish Brown discolouration. Common across many diseases.
yellowing yellow, yellowing, pale, discolor(ed/oured), chlorotic Yellow / pale discolouration.
powder powder, powdery, dust, dusty, puff Strong signal for rusts (maize) and smuts (rice).
raised raised, bump, bumpy, bumps, blister, blisters, pustule, pustules, rough, lumpy Raised texture. Maize: rust pustules. Rice: hispa blister mines.
burnt burnt, burn, burned, scorch, scorched, fire, charred Burn-look symptoms (NCLB, leaf scald).
streak streak, streaks, stripe, stripes, line, lines Linear lesions (bacterial leaf streak, MLB).
halo halo, halos, ring, rings Ring around the lesion. Maize: GLS. Rice: brown spot.
wilt wilt, wilting, wilted, droop, droopy, limp Loss of turgor; whole-plant symptom.
rot rot, rotten, rotting, decay, decaying Tissue breakdown (stalk rot, sheath rot).
orange orange Specific colour. orange + powder is a low-ambiguity signature for rust.
holes hole, holes, eaten, eat, chewed, chew Physical damage; pest indicator rather than disease.

What works today verified

These phrases were all correctly parsed into useful symptom frames during integration testing:

  • "looks brown"browning
  • "starting to look yellow"yellowing
  • "I see brown spots"spots + browning
  • "the spots look like burn"spots + burnt
  • "powdery orange stuff on leaves"powder + orange (low-ambiguity, retrieves immediately without follow-up questions)
  • "lower leaves are wilting"wilt + leaf_position=lower
  • "tiny dots all over"spots

Known gaps to plan around limitation

The current normaliser does whitespace tokenisation and exact keyword match, no stemming, no punctuation stripping. The following inputs return no symptom frame today and fall straight to action: "ask_question" with ambiguity: "very_high":

  • Punctuation attached to a keyword: "brown." or "spots," are tokenised as "brown." / "spots," and miss the table.
  • Inflected forms: "yellowish", "browner" are not in the synonym table. "yellowing" and "brown" do work.
  • Disease names as keywords: "rust", "blight", "smut" are class names the funnel predicts, not inputs it recognises. Farmers using these are usually right, but the funnel will still ask a clarifying question.
  • Vague distress phrases: "looks bad", "my plants are dying", "diseased" carry no physical detail. The funnel will ask the highest-value physical question first (raised vs flat).
  • Hyphenated terms: "green-yellow" is one token and does not match yellow.

Client tip: lowercase the input and strip trailing punctuation before sending. For multi-sentence descriptions, send the most physical sentence (the one with colour/shape/texture words) for the best frame match.

Locale and language support

The locale parameter controls both the language of metadata returned and the search index used. If the requested locale is not available for the given crop, the API falls back to the closest available locale (usually en-us) and sets fallback_used: true in the response.

Supported locales

  • en-us, English
  • sw-ke, Kiswahili (East Africa)
  • fr-af, French (West/Central Africa)
  • zh-cn, Simplified Chinese
  • zh-tw, Traditional Chinese

Fallback behaviour

  • Each response item includes requested_locale and served_locale fields
  • fallback_used: true means the index was served from a different locale than requested
  • If no locale index exists at all, the API returns 404 with error media_not_found

Deprecated routes

The three routes below are the legacy ancestors of the unified Crops API. They remain functional during the migration window but every successful response carries three RFC 8594 headers: Deprecation: true, Sunset: Mon, 31 Aug 2026 00:00:00 GMT, and Link: </api/v1/crops/{plant}/...>; rel="successor-version". After the Sunset date the legacy routes will return 410 Gone.

Legacy route Successor
POST /api/v1/chat/message POST /api/v1/crops/{plant}/chat
POST /api/v1/media/{plant}/search POST /api/v1/crops/{plant}/media/search
POST /api/v1/media/{plant}/diagnose POST /api/v1/crops/{plant}/media/diagnose

Migration tips

The new routes take the plant in the URL path rather than the request body. Otherwise the request shapes are functionally equivalent. The new /diagnose endpoint for text is brand-new, there is no legacy equivalent. Watch the Sunset header in your HTTP client and route migration alerts to your on-call channel.

Error codes

The Media Search API returns standard HTTP status codes. Common error cases:

Client errors (4xx)

  • 400, Missing or invalid parameter (e.g. empty q or missing locale)
  • 401, Missing or invalid API key
  • 403, Key does not have the required scope or audience
  • 404, Media index not found for the requested plant and locale
  • 429, Rate limit exceeded

Server errors (5xx)

  • 500, Internal error (media_search_failed or media_diagnose_failed)
  • 503, Media index is being rebuilt (media_build_pending); retry after a short delay

503 during index rebuild

When a crop index is being rebuilt in the background, search requests return 503 with error code media_build_pending. This is a temporary state, the response message will indicate when the build is expected to complete. Implement exponential backoff before retrying.