Jacaranda API quickstart
Go from an API key and published world ID to a server-observed, evidence-grounded grade using plain HTTP. No SDK is required. The OpenAPI 3.1 contract is authoritative; this page is a copyable walkthrough of that contract.
What you need
- A Jacaranda API base URL, API key, and published world ID.
curl,python3, and a Bash-compatible shell.- No package installation and no JSON-specific command-line utility.
Keep the API key out of source files and shell history. The prompt below reads it without displaying it. Replace the base URL and world ID with values supplied for your team.
export JACARANDA_API_URL="https://api.your-deployment.example"
export JACARANDA_WORLD_ID="YOUR_PUBLISHED_WORLD_ID"
read -r -s -p "Jacaranda API key: " JACARANDA_API_KEY; printf '\n'
export JACARANDA_API_KEY
export JACARANDA_OPERATION_ID="quickstart-$(date +%s)"
export JACARANDA_WORK_DIR="$(mktemp -d)"
trap 'rm -rf "$JACARANDA_WORK_DIR"' EXIT
1. Create a rollout
operation_id is the idempotency identity. Retrying this exact request
with the same operation ID and world ID recovers the same rollout; do not reuse it
for a different world.
python3 - "$JACARANDA_WORLD_ID" "$JACARANDA_OPERATION_ID" \
> "$JACARANDA_WORK_DIR/make-request.json" <<'PY'
import json
import sys
json.dump({"world_id": sys.argv[1], "operation_id": sys.argv[2]}, sys.stdout)
PY
curl -sS -D "$JACARANDA_WORK_DIR/make.headers" \
-o "$JACARANDA_WORK_DIR/make.json" \
-X POST "$JACARANDA_API_URL/v1/rollouts" \
-H "Authorization: Bearer $JACARANDA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @"$JACARANDA_WORK_DIR/make-request.json"
python3 -m json.tool "$JACARANDA_WORK_DIR/make.json"
export JACARANDA_ROLLOUT_ID="$(python3 -c \
'import json,sys; print(json.load(open(sys.argv[1]))["rollout_id"])' \
"$JACARANDA_WORK_DIR/make.json")"
export JACARANDA_DATA_URL="$(python3 -c \
'import json,sys; print(json.load(open(sys.argv[1]))["data_plane_url"].rstrip("/"))' \
"$JACARANDA_WORK_DIR/make.json")"
Use the returned data_plane_url for warehouse, app, and file traffic.
Keep using the API base URL for rollout lifecycle, task, and grade operations.
2. Get the assigned task
curl -sS -D "$JACARANDA_WORK_DIR/task.headers" \
-o "$JACARANDA_WORK_DIR/task.json" \
-X GET \
"$JACARANDA_API_URL/v1/rollouts/$JACARANDA_ROLLOUT_ID/tasks/next" \
-H "Authorization: Bearer $JACARANDA_API_KEY"
python3 -m json.tool "$JACARANDA_WORK_DIR/task.json"
export JACARANDA_TASK_ID="$(python3 -c \
'import json,sys; print(json.load(open(sys.argv[1]))["task_id"])' \
"$JACARANDA_WORK_DIR/task.json")"
export JACARANDA_PERIOD_START="$(python3 -c \
'import json,sys; print(json.load(open(sys.argv[1]))["estimand"]["period_start"])' \
"$JACARANDA_WORK_DIR/task.json")"
export JACARANDA_PERIOD_END="$(python3 -c \
'import json,sys; print(json.load(open(sys.argv[1]))["estimand"]["period_end"])' \
"$JACARANDA_WORK_DIR/task.json")"
Read prompt, estimand, and deliverable_format
before investigating. The examples below demonstrate all three data surfaces. Adapt
the SQL, API filters, and selected file to the assigned task, and cite only reads that
actually support your conclusion.
3. Investigate through the served estate
Warehouse SQL
Queries are read-only DuckDB SQL with positional parameters and bounded pages. This example summarizes the ledger over the task's period.
python3 - "$JACARANDA_PERIOD_START" "$JACARANDA_PERIOD_END" \
> "$JACARANDA_WORK_DIR/warehouse-request.json" <<'PY'
import json
import sys
json.dump(
{
"sql": (
"SELECT account_code, SUM(debit_cents - credit_cents) AS net_debit_cents "
"FROM general_ledger WHERE period BETWEEN ? AND ? "
"GROUP BY account_code ORDER BY account_code"
),
"params": [sys.argv[1], sys.argv[2]],
"row_limit": 100,
"evidence_locator": "quickstart-ledger-summary",
},
sys.stdout,
)
PY
curl -sS -D "$JACARANDA_WORK_DIR/warehouse.headers" \
-o "$JACARANDA_WORK_DIR/warehouse.json" \
-X POST "$JACARANDA_DATA_URL/v1/rollouts/$JACARANDA_ROLLOUT_ID/warehouse/query" \
-H "Authorization: Bearer $JACARANDA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @"$JACARANDA_WORK_DIR/warehouse-request.json"
python3 -m json.tool "$JACARANDA_WORK_DIR/warehouse.json"
Vendor-shaped app API
curl -sS -D "$JACARANDA_WORK_DIR/app.headers" \
-o "$JACARANDA_WORK_DIR/app.json" \
-X GET "$JACARANDA_DATA_URL/v1/rollouts/$JACARANDA_ROLLOUT_ID/apps/netsuite/general-ledger?limit=100" \
-H "Authorization: Bearer $JACARANDA_API_KEY"
python3 -m json.tool "$JACARANDA_WORK_DIR/app.json"
Files
curl -sS -D "$JACARANDA_WORK_DIR/files.headers" \
-o "$JACARANDA_WORK_DIR/files.json" \
-X GET "$JACARANDA_DATA_URL/v1/rollouts/$JACARANDA_ROLLOUT_ID/files?recursive=true&limit=100" \
-H "Authorization: Bearer $JACARANDA_API_KEY"
python3 -m json.tool "$JACARANDA_WORK_DIR/files.json"
export JACARANDA_FILE_PATH="$(python3 -c \
'import json,sys; print(json.load(open(sys.argv[1]))["items"][0]["path"])' \
"$JACARANDA_WORK_DIR/files.json")"
export JACARANDA_FILE_PATH_ENCODED="$(python3 -c \
'import sys,urllib.parse; print(urllib.parse.quote(sys.argv[1], safe="/"))' \
"$JACARANDA_FILE_PATH")"
curl -sS -D "$JACARANDA_WORK_DIR/file.headers" \
-o "$JACARANDA_WORK_DIR/file.bin" \
-X GET "$JACARANDA_DATA_URL/v1/rollouts/$JACARANDA_ROLLOUT_ID/files/$JACARANDA_FILE_PATH_ENCODED" \
-H "Authorization: Bearer $JACARANDA_API_KEY"
4. Cite the server-observed evidence
Every completed REST read returns a content-bound
Jacaranda-Trace-Event-ID. Extract the receipts from the response
headers; never invent them. For paginated operations, follow
next_cursor and collect the complete logical receipt from the final page.
export JACARANDA_WAREHOUSE_TRACE_ID="$(python3 -c '
import sys
for line in open(sys.argv[1], encoding="iso-8859-1"):
name, separator, value = line.partition(":")
if separator and name.lower() == "jacaranda-trace-event-id":
print(value.strip())
' "$JACARANDA_WORK_DIR/warehouse.headers")"
export JACARANDA_APP_TRACE_ID="$(python3 -c '
import sys
for line in open(sys.argv[1], encoding="iso-8859-1"):
name, separator, value = line.partition(":")
if separator and name.lower() == "jacaranda-trace-event-id":
print(value.strip())
' "$JACARANDA_WORK_DIR/app.headers")"
export JACARANDA_FILE_TRACE_ID="$(python3 -c '
import sys
for line in open(sys.argv[1], encoding="iso-8859-1"):
name, separator, value = line.partition(":")
if separator and name.lower() == "jacaranda-trace-event-id":
print(value.strip())
' "$JACARANDA_WORK_DIR/file.headers")"
A ceremonial citation does not earn grounding. Your cited reads must support the answer. The gateway, not the client, is trace authority.
5. Submit the answer and inspect the grade
Enter the answer as JSON in the exact shape requested by
deliverable_format: for example, a JSON number, string, or object. The
evidence claim below binds that conclusion to the three server-issued receipts.
read -r -p "Answer as JSON: " JACARANDA_ANSWER_JSON
export JACARANDA_ANSWER_JSON
python3 - "$JACARANDA_TASK_ID" \
"$JACARANDA_WAREHOUSE_TRACE_ID" \
"$JACARANDA_APP_TRACE_ID" \
"$JACARANDA_FILE_TRACE_ID" \
> "$JACARANDA_WORK_DIR/grade-request.json" <<'PY'
import json
import os
import sys
answer = json.loads(os.environ["JACARANDA_ANSWER_JSON"])
trace_ids = [value for value in sys.argv[2:] if value]
json.dump(
{
"task_id": sys.argv[1],
"answer": {
"value": answer,
"evidence_claims": [
{
"conclusion": answer,
"cited_trace_event_ids": trace_ids,
}
],
},
},
sys.stdout,
)
PY
curl -sS -D "$JACARANDA_WORK_DIR/grade.headers" \
-o "$JACARANDA_WORK_DIR/grade.json" \
-X POST "$JACARANDA_API_URL/v1/rollouts/$JACARANDA_ROLLOUT_ID/grade" \
-H "Authorization: Bearer $JACARANDA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @"$JACARANDA_WORK_DIR/grade-request.json"
python3 -m json.tool "$JACARANDA_WORK_DIR/grade.json"
The response contains score, value_ok,
grounding_ok, trap_hit, and explanation.
A correctness-clean answer with task-relevant citations returns
value_ok: true and grounding_ok: true. Eval-class responses
also expose score-query usage in the
Jacaranda-Evaluation-Budget-Limit,
-Used, and -Remaining headers.
6. Delete the exact rollout
Cleanup is explicit. A successful delete returns HTTP 204 with no response body.
curl -sS -D "$JACARANDA_WORK_DIR/delete.headers" \
-o /dev/null \
-X DELETE "$JACARANDA_API_URL/v1/rollouts/$JACARANDA_ROLLOUT_ID" \
-H "Authorization: Bearer $JACARANDA_API_KEY"
Pagination
-
App APIs and
files.listreturnnext_cursor. Repeat the same filters with?cursor=...&limit=...until it is null. -
warehouse.queryreturnsnext_cursorin JSON. Repeat the exact SQL, parameters, evidence locator, and row limit with that cursor in the JSON request body. - Page limits and warehouse row limits are at most 1,000.
- The final page carries the content-bound receipt for the complete logical read.
Errors and safe retries
JSON errors have exactly code, message, and
request_id. Preserve the request ID when asking for support. The published
contract documents HTTP 400, 401, 403, 404, 405, 409, 413, 415, 429, and 500.
A 429 can mean the rate limit or eval score-query budget is exhausted.
- Retry rollout creation only with the same body and operation ID.
- Do not change SQL, filters, or page size while following a cursor.
- After an ambiguous terminal-operation timeout, check state before retrying.
Generic MCP over HTTP
MCP wraps the same registered operations at POST /mcp. A generic MCP
client initializes, lists tools, and calls a tool. Tool arguments include REST path
parameters such as rollout_id. For tool calls, the trace receipt is
result._meta.trace_event_id, not an HTTP trace header.
Initialize
curl -sS -X POST "$JACARANDA_API_URL/mcp" \
-H "Authorization: Bearer $JACARANDA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary '{"jsonrpc":"2.0","id":"init-1","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"plain-http","version":"1"}}}'
curl -sS -X POST "$JACARANDA_API_URL/mcp" \
-H "Authorization: Bearer $JACARANDA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary '{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}'
List registered tools
curl -sS -X POST "$JACARANDA_API_URL/mcp" \
-H "Authorization: Bearer $JACARANDA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary '{"jsonrpc":"2.0","id":"list-1","method":"tools/list","params":{}}'
Call a tool
python3 - "$JACARANDA_ROLLOUT_ID" \
> "$JACARANDA_WORK_DIR/mcp-call.json" <<'PY'
import json
import sys
json.dump(
{
"jsonrpc": "2.0",
"id": "call-1",
"method": "tools/call",
"params": {
"name": "warehouse.schema",
"arguments": {"rollout_id": sys.argv[1]},
},
},
sys.stdout,
)
PY
curl -sS -X POST "$JACARANDA_API_URL/mcp" \
-H "Authorization: Bearer $JACARANDA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @"$JACARANDA_WORK_DIR/mcp-call.json"
Use the OpenAPI contract
Download /openapi.json and select operations
by operationId. Each operation declares its bearer authentication,
request and response schemas, error responses, matching x-mcp-tool,
x-pagination where applicable, and x-trace-receipt. Treat
those machine-readable fields as authoritative when this prose and the contract differ.