Skip to the content.

AgriOps — API Contract

Version: Snapshot 1.2 Date: April 2026 Status: Current implementation snapshot


Overview

The AgriOps REST API exposes a JWT-authenticated /api/v1/ surface for core tenant data. This document describes the endpoints and behaviours currently implemented in the codebase. It is intentionally conservative: this file is a code-aligned snapshot, not a roadmap.

Base URL: /api/v1/ Authentication: JWT Bearer token Format: JSON Schema: No public OpenAPI schema is currently published


Authentication

POST /api/v1/token/

Obtain JWT access and refresh tokens.

Request

{
  "username": "example_user",
  "password": "securepassword"
}

Response 200

{
  "access": "eyJ...",
  "refresh": "eyJ..."
}

POST /api/v1/token/refresh/

Refresh an expired access token.

Request

{
  "refresh": "eyJ..."
}

Auth Model

All API endpoints require authentication unless stated otherwise.

Method-level role enforcement mirrors the server-rendered application:

HTTP method Minimum role required
GET, HEAD, OPTIONS Any authenticated tenant member
POST, PUT, PATCH Staff or above
DELETE Manager or above

This is enforced via get_permissions() on TenantScopedViewSet. Unauthenticated requests receive 401. Authenticated requests below the required role receive 403.


Tenant Scoping


Endpoints

Suppliers

GET /api/v1/suppliers/ List suppliers for the authenticated tenant.

POST /api/v1/suppliers/ Create a supplier. Staff or above required.

GET /api/v1/suppliers/{id}/ Retrieve a supplier in the authenticated tenant.

PATCH /api/v1/suppliers/{id}/ Update a supplier. Staff or above required.

DELETE /api/v1/suppliers/{id}/ Delete a supplier. Manager or above required.

Example response

{
  "id": 1,
  "name": "Plateau Shea Cooperative",
  "category": "cooperative",
  "contact_person": "Amina Yusuf",
  "phone": "+234...",
  "email": "info@example-supplier.com",
  "country": "Nigeria",
  "city": "Jos",
  "is_active": true,
  "reliability_score": "82.50",
  "created_at": "2026-03-01T10:00:00Z"
}

Farms

GET /api/v1/farms/ List farms for the authenticated tenant.

POST /api/v1/farms/ Create a farm. Staff or above required.

GET /api/v1/farms/{id}/ Retrieve a farm in the authenticated tenant.

PATCH /api/v1/farms/{id}/ Update a farm. Staff or above required.

DELETE /api/v1/farms/{id}/ Delete a farm. Manager or above required.

GET /api/v1/farms/eudr-pending/ List farms that are not compliance-readycompliance_status != "compliant". This catches expired and evidence-invalid sign-offs, not just farms with the verification flag off.

GET /api/v1/farms/high-risk/ List farms where deforestation_risk_status=high.

POST /api/v1/farms/import/ Run the farm GeoJSON bulk import pipeline for a tenant supplier.

Read-only fields: is_eudr_verified, verified_date, verification_expiry, and deforestation_risk_status are read-only over the API. A Compliance Readiness sign-off is a manager-only, evidence-gated, audited action (not a raw field write), and deforestation risk is set by the deforestation engine. A write to any of these fields is silently ignored. compliance_status and readiness_state are computed read-only properties.

Example response

{
  "id": 1,
  "supplier": 1,
  "name": "Plot 01 — Barkin Ladi",
  "farmer_name": "Amina Bello",
  "country": "Nigeria",
  "state_region": "Plateau",
  "commodity": "shea",
  "area_hectares": "12.40",
  "deforestation_risk_status": "low",
  "is_eudr_verified": true,
  "verified_date": "2026-02-20",
  "verification_expiry": "2027-02-20",
  "compliance_status": "compliant",
  "readiness_state": "ready",
  "created_at": "2026-03-01T10:00:00Z"
}

Products

GET /api/v1/products/ POST /api/v1/products/ — staff or above required GET /api/v1/products/{id}/ PATCH /api/v1/products/{id}/ — staff or above required DELETE /api/v1/products/{id}/ — manager or above required

Inventory

GET /api/v1/inventory/ POST /api/v1/inventory/ — staff or above required GET /api/v1/inventory/{id}/ PATCH /api/v1/inventory/{id}/ — staff or above required DELETE /api/v1/inventory/{id}/ — manager or above required

GET /api/v1/inventory/low-stock/ List inventory items at or below their low-stock threshold.

Purchase Orders

GET /api/v1/purchase-orders/ POST /api/v1/purchase-orders/ — staff or above required GET /api/v1/purchase-orders/{id}/ PATCH /api/v1/purchase-orders/{id}/ — staff or above required DELETE /api/v1/purchase-orders/{id}/ — manager or above required

Order numbers are unique per tenant (unique_together: company + order_number), not globally unique.

Sales Orders

GET /api/v1/sales-orders/ POST /api/v1/sales-orders/ — staff or above required GET /api/v1/sales-orders/{id}/ PATCH /api/v1/sales-orders/{id}/ — staff or above required DELETE /api/v1/sales-orders/{id}/ — manager or above required

Order numbers are unique per tenant (unique_together: company + order_number), not globally unique.


Error Responses

Typical error shape:

{
  "detail": "Human-readable error message"
}
Code Meaning
400 Bad request / validation error (includes cross-tenant FK rejection)
401 Unauthenticated
403 Authenticated but below required role
404 Not found (also returned for cross-tenant detail access)
429 Rate limited
500 Server error

Cross-tenant access to top-level detail routes returns 404, not 403.


Rate Limiting

Default DRF throttle rates:


Notes