This guide is for teams integrating FASA into a web app, mobile app, dashboard, or backend service.
fasa_core/: domain and optimization engine (business logic)fasa_api/: HTTP adapter (FastAPI endpoints and transport concerns)data/: required CSV data assets used by the engine
For integrations, treat the HTTP API as the stable boundary.
- Base URL: provided by the deployment team (Cloud Run service URL)
- Auth:
Authorization: Bearer <token>, orX-API-Key: <token>
/healthis public for liveness checks.- Other endpoints require token auth unless
FASA_REQUIRE_AUTH=falsein the environment.
Example:
curl -X GET "${BASE_URL}/supported" \
-H "Authorization: Bearer ${FASA_API_TOKEN}"- Swagger UI:
${BASE_URL}/docs - OpenAPI JSON:
${BASE_URL}/openapi.json
Use the OpenAPI contract for generated clients and payload validation.
Business/auth errors follow:
{
"detail": {
"code": "unauthorized",
"message": "Invalid or missing API token.",
"details": null
}
}Recommended client behavior:
400: show actionable message to user (invalid request values)401: refresh/replace token and retry once422: treat as client payload validation issue503: service not ready; retry with backoff
- Set client timeout to 90-120s for
/formulatecalls. - Retry strategy:
- Retry only on
503and transient network failures. - Use exponential backoff (e.g. 1s, 2s, 4s; max 3 retries).
- Do not retry
400/401/422blindly.
- Retry only on
- Validate connectivity with
/healthand/ready. - Call
/supportedfirst to fetch validspecies,production_system,stage, andcountries. - Build
/formulatepayload from those discovered values. - Always send
premix_price(premix price per kg, same currency asprices). Every feed carries the premix;premix_rateis0.01,0.015or0.02(default0.02), andcost_per_kgincludespremix_rate × premix_price. Premix products cannot be priced inprices. Since 1.0.0premix_enabled,max_fishmeal_cost_share,max_binder_inclusionandcustom_premix_mask_codesare gone; sending them returns 422. - Optionally send
country(ISO-2:KE/NG/ZM) to have each recipe line flaggedlocally_available(true/false;nullwhen nocountryis sent). This is an advisory highlight only — the optimizer is never restricted to local ingredients. - Optionally send
nutrient_limitsand/oringredient_limitsto bound dietary nutrient levels (ASNS spec code ->{min, max}in that code's ASNS unit) or single-ingredient inclusion (FICD code ->{min, max}as a mass fraction of feed). These override the engine's configured limit tables for the codes they name; where ASNS already states the same bound, the tighter value binds. Eachrecipeline echoes the box applied (min_inclusion_percent,max_inclusion_percent,limit_source) and eachcompositionline carries asourcenaming where its target came from. - Watch the units on ingredient limits: you send a fraction (
{"max": 0.15}) and get back a percentage ("max_inclusion_percent": 15.0). Out-of-range request values are rejected with 422, so15sent for 15% fails loudly, but rendering0.15as "0.15%" fails silently — convert in both directions. Nutrient limits are not rescaled: they go in and come back in that spec code's ASNS unit. Since the v11.1 datasets, Vitamin A (V10) and Vitamin D (V11) are in IU/kg (previously mg and µg). - Handle
statusin response (optimal,infeasible,error). - On
infeasible, checkinfeasibility.bound_conflictsbeforeiis_codes: when it is non-empty the ingredient inclusion limits alone cannot add up to the feed mass and no IIS was computed. - To check a recipe the user edited (or one from elsewhere) without re-running the LP,
post it to
/validate-recipewith the samespecies/stage/production_systemand any limit overrides. It returnsin_limits, per-ingredientinclusion_checks, andnutrient_checksin the same shape as/formulate'scomposition. All fields other thanfractionsare optional, so existing callers are unaffected.parameterstakes FICD parameter names; a name the current FICD does not carry returns 400. FICD v11.1 removed the 52 porcine/poultry digestibility parameters (sid_*,sidc_*). - Log request IDs (if the calling client or service provides them) for easier debugging.
- Before upgrading environments:
- compare old vs new
openapi.json - run integration tests against the target deployment
- compare old vs new
- Avoid hardcoding enum-like values outside
/supportedwhen possible. - Track README release notes for contract-impacting changes.