Runtime API
Discover and invoke Xenodia marketplace capabilities from an authenticated agent or backend.
Capability runtime calls use the same base URL and authentication model as the rest of the Xenodia API.
export XENODIA_API_KEY="sk_xeno_..."
export XENODIA_BASE_URL="https://api.xenodia.xyz"Authentication
Every /v1/capabilities/* endpoint requires:
Authorization: Bearer $XENODIA_API_KEYIf an agent wallet has not received a bearer token yet, the 401 recovery payload can point the agent to the wallet challenge and verify flow. Owner bootstrap should still happen through the normal owner login or API key flow.
List Capabilities
curl "$XENODIA_BASE_URL/v1/capabilities?mode=sync&q=intelligence" \
-H "Authorization: Bearer $XENODIA_API_KEY"Query parameters:
| Name | Meaning |
|---|---|
q | Optional case-insensitive search across slug, name, type, category, description, provider name, and tags. |
mode | Optional sync or async filter. |
Response shape:
{
"object": "list",
"count": 1,
"data": [
{
"slug": "unicatcher-query",
"name": "UniCatcher",
"type": "api",
"category": "intelligence",
"short_description": "High-quality intelligence retrieval...",
"provider_name": "UniCatcher Agent Intelligence Gateway",
"status": "active",
"visibility": "consumer_listed",
"default_version": "v1",
"tags": ["info"],
"supports_sync": true,
"supports_async": false,
"funding_modes": ["owner_only", "self_only", "self_then_owner"],
"invoke_path": "/v1/capabilities/unicatcher-query/invoke",
"agent_doc_what": "Use UniCatcher when...",
"agent_doc_how": "For the 24-hour hot tweets use case...",
"default_operation_slug": "query",
"operations": [
{
"slug": "status",
"name": "Status",
"method": "GET",
"path": "/v1/capabilities/unicatcher-query/operations/status",
"read_only": true,
"flow_step": 1,
"pricing": {
"billing_kind": "credit",
"mode": "fixed",
"unit_price_micro_usdc": 0,
"currency": "USDC"
},
"supports_sync": true
},
{
"slug": "monitors",
"name": "List Monitors",
"method": "GET",
"path": "/v1/capabilities/unicatcher-query/operations/monitors",
"read_only": true,
"flow_step": 2,
"pricing": {
"billing_kind": "credit",
"mode": "fixed",
"unit_price_micro_usdc": 0,
"currency": "USDC"
},
"supports_sync": true
},
{
"slug": "query",
"name": "Query Intelligence",
"method": "POST",
"path": "/v1/capabilities/unicatcher-query/invoke",
"read_only": true,
"flow_step": 3,
"pricing": {
"billing_kind": "credit",
"mode": "fixed",
"unit_price_micro_usdc": 10000,
"currency": "USDC"
},
"idempotency_key_required": true,
"supports_sync": true
}
],
"availability": {
"effective_status": "active",
"retryable": false,
"list_visible": true,
"detail_visible": true,
"invoke_allowed": true
}
}
]
}When a capability has multiple operations, root-level pricing can be omitted from list responses. Read each operation's pricing before invoking.
Get Capability Detail
curl "$XENODIA_BASE_URL/v1/capabilities/unicatcher-query" \
-H "Authorization: Bearer $XENODIA_API_KEY"The detail endpoint returns the descriptor in a wrapper:
{
"object": "capability",
"data": {
"slug": "unicatcher-query",
"operations": []
}
}Invoke responses are returned directly, not inside the descriptor wrapper.
Descriptor fields agents should inspect:
| Field | Use |
|---|---|
slug | Stable capability identifier used in routes and logs. |
default_version | Published contract version for the current runtime behavior. |
supports_sync, supports_async | Whether sync invoke, async task invoke, or both are available. |
funding_modes | Billing relationships allowed for this capability. |
agent_doc_what | When to choose the capability. |
agent_doc_how | Safe operation sequence and special handling. |
operations | Operation contracts, input fields, examples, prices, trust signals, and availability. |
availability.invoke_allowed | Whether an invoke can currently proceed. |
health_summary | Runtime health signal when provider health checks are configured. |
Invoke The Default Operation
curl "$XENODIA_BASE_URL/v1/capabilities/unicatcher-query/invoke" \
-H "Authorization: Bearer $XENODIA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unicatcher-query-2026-05-04T10-00-00Z" \
-d '{
"query": "Find recent high-signal developments",
"filters": {
"sourceTypes": ["twitter", "reddit"],
"screeningStatus": ["qualified", "review"],
"timeRangeHours": 24,
"limit": 20,
"sort": "publishedAt:desc"
},
"responseMode": "evidence_only"
}'You may also use an envelope when a capability supports multiple execution modes:
{
"mode": "sync",
"input": {
"query": "Find recent high-signal developments"
}
}When the envelope form is used, only mode and input are allowed at the top level.
Invoke A Named Operation
Read-style operations may use GET with query parameters:
curl "$XENODIA_BASE_URL/v1/capabilities/unicatcher-query/operations/monitors?status=active&platform=twitter&limit=20" \
-H "Authorization: Bearer $XENODIA_API_KEY"Operations may also use POST with JSON:
curl "$XENODIA_BASE_URL/v1/capabilities/unicatcher-query/operations/query" \
-H "Authorization: Bearer $XENODIA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unicatcher-query-2026-05-04T10-05-00Z" \
-d '{
"query": "What happened around the monitored topic in the last 24 hours?",
"responseMode": "evidence_only"
}'Success Response
Synchronous capability responses use:
{
"success": true,
"request_id": "capability-request-id",
"capability": "unicatcher-query",
"operation": "query",
"capability_version": "v1",
"mode": "sync",
"billing": {
"billing_session_id": 987,
"billing_mode": "self_then_owner",
"billing_scope": "self",
"status": "committed",
"unit_price_micro_usdc": 10000,
"reserve_amount_micro_usdc": 10000,
"actual_amount_micro_usdc": 10000,
"released_amount_micro_usdc": 0,
"actor": {
"account_id": 123,
"account_type": "agent"
},
"payer": {
"account_id": 45,
"account_type": "owner"
}
},
"data": {}
}Async capability responses return task instead of data and should be polled through the normal task resource.
Idempotency
Send Idempotency-Key for:
- Any operation with
idempotency_key_required: true. - Any paid operation.
- Any async operation.
Reusing the same key with the same payload can replay the stored result. Reusing the same key with a different payload returns 409 idempotency_conflict.
Billing And 402
If the selected billing account has insufficient credit, the endpoint returns 402 insufficient_balance with payment headers and a payment object. The object includes topup_endpoint, required_amount_micro, currency, payment_kind, and capability context. Top up, then retry the same invoke with the same Idempotency-Key.
Common Errors
| Status | Error | Meaning |
|---|---|---|
400 | missing_idempotency_key | Paid, async, or policy-protected invoke was sent without an Idempotency-Key. |
400 | capability_mode_unsupported | Requested mode is not supported by that operation. |
401 | unauthorized | Bearer token or API key is missing or invalid. |
402 | insufficient_balance | Billing account needs credit before the invoke can continue. |
404 | not_found | Capability or operation is not visible to the authenticated account. |
409 | idempotency_conflict | The same idempotency key was reused with a different payload. |
409 | request_in_progress | A matching idempotent request is still running. |
429 | capability_invoke_failed | Upstream rate limit or request limit was reached. |
502 | capability_invoke_failed | Upstream HTTP, contract, or gateway execution failed. |
503 | capability_unavailable | Runtime, contract, or health state blocks new traffic; check reason and retryable. |
504 | capability_invoke_failed | Upstream transport timed out. |