Developer

BRD AgriAI API

A read-only REST API for the farm data already in your BRD AgriAI account — fields, weather, irrigation scheduling, soil health, yield history, equipment, and market prices. Script against your own farm.

Introduction

Every endpoint below is real and live — it's the same data and the same logic your BRD dashboard uses, exposed as JSON. This is v1.0, read-only: nothing in this API creates or modifies records in your account. Write access (logging a spray application, adding a harvest entry, etc.) may follow in a future version.

Prefer not to write HTTP calls by hand? See the official Python client library below, or explore every endpoint interactively in Swagger UI.

Authentication

Authenticate with a personal API key, generated at bishopresearch.com → Dashboard → Settings → API Keys. Pass it as a bearer token on every request:

Authorization: Bearer brd_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
The plaintext key is shown exactly once, at creation time. BRD stores only a one-way hash of it — if you lose a key, revoke it and generate a new one. Keys are scoped to your account only: they can only read data you already own.

Base URL & versioning

https://bishopresearch.com/api/v1

Every path documented below (e.g. /fields) is relative to this base URL. The v1 in the path is the version — breaking changes will ship as a new version prefix rather than changing v1's behavior underneath you.

Rate limits

60 requests per minute, per API key. Exceeding it returns HTTP 429:

{"detail": "Rate limit exceeded: 60 requests/minute per API key."}

The Python library retries 429 and 5xx responses automatically with exponential backoff before raising.

Errors

Errors are a JSON body with a single detail field describing what went wrong, and a standard HTTP status code:

StatusMeaning
401Missing, invalid, or revoked API key
404Resource not found (or not yours)
422Request understood but rejected — e.g. a field with no location set
429Rate limit exceeded
5xxSomething went wrong on BRD's end
{"detail": "Field not found"}

Account

GET/me

The account this API key belongs to.

curl https://bishopresearch.com/api/v1/me \
  -H "Authorization: Bearer $BRD_API_KEY"
client.me()

Response — real example, captured live:

{
  "email": "testfarmer999@example.com",
  "full_name": "Test Farmer",
  "subscription_tier": "seedling",
  "created_at": "2026-03-15T21:20:47.707494Z"
}

Fields

GET/fields

List every field on your account.

curl https://bishopresearch.com/api/v1/fields \
  -H "Authorization: Bearer $BRD_API_KEY"
client.fields.list()

Response — real example, captured live:

{
  "fields": [
    {
      "id": 1,
      "name": "North 80",
      "acres": 80.0,
      "crop": "Corn",
      "soil_type": "Silt loam",
      "lat": 41.5868,
      "lon": -93.625,
      "boundary": null,
      "notes": "",
      "agro_polygon_id": null,
      "tillage_practice": "conventional",
      "planting_date": null,
      "created_at": "2026-03-15T21:23:06.463595Z",
      "observation_count": 0
    }
  ]
}

GET/fields/{field_id}

Get a single field by ID (must belong to your account, or this returns 404).

curl https://bishopresearch.com/api/v1/fields/1 \
  -H "Authorization: Bearer $BRD_API_KEY"
client.fields.get(1)

Weather

GET/fields/{field_id}/weather

The current Open-Meteo forecast for a field's location. Returns 422 if the field has no lat/lon set.

curl https://bishopresearch.com/api/v1/fields/1/weather \
  -H "Authorization: Bearer $BRD_API_KEY"
client.fields.weather(1)

Response — real example, captured live (forecast truncated to 1 of 7 days):

{
  "field_id": 1,
  "field_name": "North 80",
  "forecast": [
    {
      "date": "2026-08-16",
      "high": 78.3,
      "low": 69.4,
      "precip": 0.0,
      "code": 3,
      "et0": 0.11,
      "wind_mph": 13.4
    }
  ],
  "cumulative_gdd": 2780.2,
  "season_precip_in": 32.62,
  "next7_total_precip": 0.79,
  "frost_risk_7d": false,
  "heavy_rain_7d": false,
  "current_high": 78.3,
  "current_low": 69.4
}

Irrigation

GET/fields/{field_id}/irrigation

FAO-56 irrigation schedule for a field, built from real ET0/precipitation forecasts and a crop Kc curve.

ParamTypeDefaultNotes
daysint7Clamped to 1–14
curl "https://bishopresearch.com/api/v1/fields/1/irrigation?days=3" \
  -H "Authorization: Bearer $BRD_API_KEY"
client.fields.irrigation(1, days=3)

Response — real example, captured live:

{
  "field_id": 1,
  "field_name": "North 80",
  "crop": "Corn",
  "kc_coefficient": 0.35,
  "gdd_accumulated": 2780.0,
  "gdd_since_planting": false,
  "schedule": [
    {
      "date": "2026-08-16",
      "et0_in": 0.11,
      "etc_in": 0.038,
      "precip_in": 0.0,
      "daily_deficit_in": 0.038,
      "cumulative_deficit_in": 0.038,
      "irrigate": false
    }
  ],
  "total_et0_in": 0.38,
  "total_etc_in": 0.13,
  "total_precip_in": 0.55,
  "days": 3
}

Soil Health

GET/soil-health

Cross-field soil health summary, built from your own recorded lab tests — latest test per field, a rating, deficit-based lime/P/K planning estimates, and farm-wide averages.

curl https://bishopresearch.com/api/v1/soil-health \
  -H "Authorization: Bearer $BRD_API_KEY"
client.soil_health.summary()

Response — real example, captured live (no soil test recorded yet for this field):

{
  "fields": [
    {"field_id": 1, "field_name": "North 80", "acres": 80.0, "latest_test": null, "rating": "Unknown"}
  ],
  "recommendations": [
    {"field_id": 1, "field_name": "North 80", "lime_tons_ac": null, "p_lbs_ac": null, "k_lbs_ac": null, "cost_per_ac": null}
  ],
  "aggregates": {"avg_ph": null, "avg_om": null, "avg_p": null, "avg_k": null},
  "note": "Lime/P/K estimates are deficit-based planning figures from your latest soil test, not a calibrated lab buffer-pH recommendation. Confirm with your agronomist or lab before applying."
}

Yield History

GET/yield-history

Yield history built from your own recorded harvest entries — one point per field per season you've entered. No county/state averages are fabricated when you have no data yet.

curl https://bishopresearch.com/api/v1/yield-history \
  -H "Authorization: Bearer $BRD_API_KEY"
client.yield_history.list()

Response — real example, captured live:

{
  "fields": [
    {"field_id": 1, "field_name": "North 80", "acres": 80.0, "crop": "Corn", "years": []}
  ],
  "note": "Built from your entered harvest records (Harvest Log). Add entries there for fields with no history shown here."
}

The Python library's client.yield_history.list() returns the fields array directly.

Equipment

GET/equipment

Your logged equipment (a manually-maintained fleet inventory — name, year, make/model, hours, last service date, status).

curl https://bishopresearch.com/api/v1/equipment \
  -H "Authorization: Bearer $BRD_API_KEY"
client.equipment.list()

Response — real example, captured live:

{"equipment": []}

Market Prices

GET/market/prices

Corn/soybean/wheat price estimates plus real day-over-day change (not field-specific). live: false means the server doesn't have a USDA AMS key configured and prices are estimates — check data_source.

curl https://bishopresearch.com/api/v1/market/prices \
  -H "Authorization: Bearer $BRD_API_KEY"
client.market.prices()

Response — real example, captured live:

{
  "corn": {"futures": 4.6, "change": 0.0, "change_pct": 0.0},
  "soybeans": {"futures": 11.1, "change": 0.0, "change_pct": 0.0},
  "wheat": {"futures": 6.1, "change": 0.0, "change_pct": 0.0},
  "data_source": "Estimated (USDA_MARS_API_KEY not configured)",
  "live": false,
  "updated_at": "2026-08-16T21:22:59.701473"
}

Python Library

The official brdagriai package wraps every endpoint above in a resource-oriented client, with typed exceptions and automatic retry on rate limits / transient server errors.

Install

pip install brdagriai

Quickstart

# Generate a key at bishopresearch.com → Dashboard → Settings → API Keys
from brdagriai import Client

client = Client(api_key="brd_live_...")
# or: export BRD_API_KEY=brd_live_... and just call Client()

for field in client.fields.list():
    schedule = client.fields.irrigation(field["id"], days=7)
    print(field["name"], schedule["schedule"])

Resource methods

CallEndpoint
client.me()GET /me
client.fields.list()GET /fields
client.fields.get(id)GET /fields/{id}
client.fields.weather(id)GET /fields/{id}/weather
client.fields.irrigation(id, days=7)GET /fields/{id}/irrigation
client.soil_health.summary()GET /soil-health
client.yield_history.list()GET /yield-history
client.equipment.list()GET /equipment
client.market.prices()GET /market/prices

Errors

from brdagriai import Client, NotFoundError, RateLimitError, AuthenticationError

client = Client()
try:
    client.fields.get(999999)
except NotFoundError:
    print("no such field")
ExceptionHTTP status
AuthenticationError401
NotFoundError404
ValidationError422
RateLimitError429 (after retries exhausted)
ServerError5xx (after retries exhausted)
ConnectionErrorno response received (network/timeout)

Context manager

with Client(api_key="brd_live_...") as client:
    print(client.me())
# connection closed automatically
Source, tests, and the full README: the brdagriai package ships alongside this API — built on httpx, sync-only for now with an async client a natural (not yet built) follow-on. No pagination is implemented: every v1 resource returns a small, complete list scoped to your own farm.