Webhooks & Async
POST /optimize/async returns immediately with a job_id; poll GET /jobs/{job_id} until status is completed, failed, or cancelled, then read .result. Webhooks let the server notify you instead of polling, but treat delivery as best-effort.
Why go async
/optimize/sync blocks the HTTP connection until the solver finishes or options.time_limit_seconds elapses. For large problems, long time limits, or batch processing where you don't want to hold a connection open, submit to /optimize/async instead.
Submit, poll, retrieve
- Submit.
POST /api/v1/optimize/asyncwith the sameOptimizationRequestbody you'd send to/optimize/sync. It returns202 Acceptedwith ajob_idright away — the solve runs in the background. - Poll.
GET /api/v1/jobs/{job_id}repeatedly (with a sensible interval, e.g. every 2–5 seconds) untilstatusis a terminal value:completed,failed, orcancelled. - Retrieve. Once
statusiscompleted, the job'sresultfield holds the fullOptimizationResponse— the same shape you'd get from/optimize/sync.
curl example
# 1. Submit
JOB_ID=$(curl -s -X POST https://api.fieldgenius.be/api/v1/optimize/async \
-H "Content-Type: application/json" \
-H "X-API-Key: your-adapter-key" \
-H "X-Client-Key: your-client-key" \
-d @request.json | jq -r '.job_id')
# 2. Poll
while true; do
STATUS=$(curl -s https://api.fieldgenius.be/api/v1/jobs/$JOB_ID \
-H "X-API-Key: your-adapter-key" \
-H "X-Client-Key: your-client-key" | jq -r '.status')
echo "status: $STATUS"
if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ] || [ "$STATUS" = "cancelled" ]; then
break
fi
sleep 3
done
# 3. Retrieve
curl -s https://api.fieldgenius.be/api/v1/jobs/$JOB_ID \
-H "X-API-Key: your-adapter-key" \
-H "X-Client-Key: your-client-key" | jq '.result'
Python example (httpx)
import time
import httpx
BASE = "https://api.fieldgenius.be/api/v1"
HEADERS = {
"X-API-Key": "your-adapter-key",
"X-Client-Key": "your-client-key",
}
with httpx.Client(timeout=30, headers=HEADERS) as client:
submit = client.post(f"{BASE}/optimize/async", json=request_payload)
submit.raise_for_status()
job_id = submit.json()["job_id"]
while True:
job = client.get(f"{BASE}/jobs/{job_id}").json()
if job["status"] in ("completed", "failed", "cancelled"):
break
time.sleep(3)
if job["status"] == "completed":
result = job["result"]
print(result["status"], result["score"]["total"])
else:
print("job did not complete:", job["status"])
You can cancel a still-running job with POST /api/v1/jobs/{job_id}/cancel.
Webhooks (not yet available)
The request body accepts a webhooks section (shown below) and the API will not reject a request that includes one. However, no notification is actually sent when a job completes — the field is currently stored and otherwise ignored. Do not rely on webhooks yet: use polling as described above, which is fully supported today. This page will be updated once webhook delivery ships.
The planned shape, for reference:
{
"webhooks": [
{
"url": "https://your-service.example.com/fg-webhooks",
"events": ["completed", "failed"],
"headers": { "Authorization": "Bearer your-shared-secret" }
}
]
}
events defaults to ["completed", "failed"] if omitted. headers is a plain dict intended to be merged into the outbound webhook request once delivery is implemented, commonly used to carry an auth token your endpoint would check.
- Best Practices — when to choose async over sync based on problem size.
- Result Caching — identical async requests are served from cache or attach to an already-running job instead of re-solving.
- Live Solve Tracking — watch an async solve's progress and salvage a result on cancel.
- Durable Job Queue — make async job records survive a server restart or crash.
- POST /optimize/async reference
- Async Jobs reference