REST API reference
The current v1 contract, from endpoint discovery to query results and audit events.
Base URL and requests
https://api.recursift.app/v1Send an Authorization bearer header on every data request, and Content-Type: application/json for query creation. Responses are JSON. Unknown fields in query bodies are rejected. The /health route is outside /v1 and requires no key.
Routes
| Method / route | Required scope | Response |
|---|---|---|
| GET /me | Any valid key | key_id, customer_id, scopes |
| GET /agents | agents:read | agents, next_cursor |
| POST /queries | query:write | 202 receipt: id, status, agent_total, deadline |
| GET /queries | query:read | queries, next_cursor |
| GET /queries/{id} | query:read | Job, findings, counts, unanswered_agents |
| POST /queries/{id}/cancel | query:write | Receipt; terminal jobs remain unchanged |
| GET /findings | query:read | findings, coverage, next_cursor |
| GET /audit/events | audit:read | events, next_cursor |
Create a query
{
"question": "What operating system are you running?",
"target": {
"agent_ids": [
"YOUR_ENDPOINT_ID"
]
},
"timeout_seconds": 120
}| Field | Constraint |
|---|---|
| question | 1–500 characters after trimming |
| target.agent_ids | 1–100 unique, accessible endpoint IDs |
| timeout_seconds | 5–120 seconds; omitted or 0 defaults to 120 |
| Idempotency-Key header | Optional, at most 128 characters; preserve for retries |
| Request body | At most 16 KiB |
Any unknown or inaccessible target rejects the whole query with 404. An empty target never means the whole fleet. Reusing an idempotency key with a different normalized request returns 409; matching requests return the same job.
Job and finding fields
| Object | Fields |
|---|---|
| Agent | id, hostname, platform, last_seen_at, status |
| Job | id, status, question, created_at, deadline, agent_total, agent_answered, agent_failed, findings, unanswered_agents |
| Finding | agent_id, hostname, status, answer, error, answered_at, query_id |
| Audit event | seq, event_json, prev_hash, hash |
Finding answer, error and answered_at may be null. GET /queries/{id} materializes newly received findings. Answer text is bounded to 4,000 characters; raw evidence rows are not exposed by this API.
Pagination and finding search
List routes accept limit (1–100, default 50) and cursor. Pass the returned next_cursor unchanged and stop when it is empty. Ordering follows stable IDs, not creation time. Audit cursors are sequence numbers.
curl --fail-with-body --get "https://api.recursift.app/v1/findings" \
-H "Authorization: Bearer $RECURSIFT_API_KEY" \
--data-urlencode "search=macOS" \
--data-urlencode "limit=20"Errors
{
"error": {
"code": "not_found",
"message": "Route not found"
}
}| Status | Meaning |
|---|---|
| 400 | Invalid request, target, cursor or limit |
| 401 | Missing or invalid customer key |
| 403 | Insufficient scope or refused browser origin |
| 404 | Unknown route or resource unavailable to this customer |
| 409 | Idempotency conflict |
| 429 | Key, customer or endpoint limit; honor Retry-After |
| 500 / 503 | Service or storage failure; retain request identifiers |
MCP transport errors do not use this REST JSON envelope. The OpenAPI download describes the REST surface.