Skip to content

Conventions

  • HTTPS and JSON. A request with a body must send Content-Type: application/json and exactly one JSON object.
  • Unknown fields are rejected (400 COMMON.INVALID_INPUT), so a misspelled field is never silently ignored.
  • Request bodies are limited to 64 KiB.
  • Services generates X-Request-ID for every response and ignores a client-supplied one. Quote it when reporting a problem.
  • Every /v1 response sets Cache-Control: no-store.

Success:

{ "code": 0, "message": "success", "data": { "execution": { }, "result": { } } }

Error:

{
"code": 409,
"error_code": "EXECUTION.DUPLICATE_INVOCATION",
"message": "This invocation was already executed.",
"request_id": "req_5f0c...",
"execution": { }
}

Branch on error_code. message is static, caller-safe text and never contains provider responses, URLs or internal errors. See Errors for the full list.

Every capability call carries your invocation_id (1–128 characters of A-Z a-z 0-9 . _ : -). Services records one execution per (caller, invocation_id, operation), written before the provider is called:

  • if the record cannot be written, the provider is not called and the response is 503 SERVICES.RECORD_UNAVAILABLE;
  • if you repeat an invocation_id for the same operation, the provider is not called again and the response is 409 EXECUTION.DUPLICATE_INVOCATION with the existing execution. Services does not store results and cannot replay them.

Requests rejected before an execution exists (authentication, scope, validation, unknown or disabled provider, local concurrency limit, body size) carry no execution and started no provider work.

{
"id": "exe_0192f6...",
"invocation_id": "order-10086-1",
"capability": "public_holiday",
"operation": "public_holiday.query",
"provider": "holiday-cn",
"outcome": "succeeded",
"error_category": null,
"error_code": null,
"usage": { "provider_requests": 0, "units": [{ "name": "days", "value": 8, "source": "measured" }] },
"request_id": "req_5f0c...",
"started_at": "2026-10-11T09:00:00Z",
"finished_at": "2026-10-11T09:00:01Z"
}
outcome Meaning Caller handling
succeeded Result delivered Bill by your product rules
failed Definitely no usable result Apply failure rules
unknown The provider received the request; its effect is undetermined Never retry automatically; reconcile via the call log
accepted Asynchronous task created, not terminal Look up later
expired The provider reported the asynchronous result expired Apply failure rules
in_progress Reconciliation only: still inside its deadline Query again later

An execution still unfinished after its deadline (for example after a crash) is reported as unknown.

  • provider_requests: requests actually sent upstream; 0 for local data such as holiday-cn.
  • units[]: the capability’s own units, such as days for holidays or works for scholarly search. source is provider (reported upstream) or measured (counted by Services). Unavailable quantities are omitted, never estimated.
  • Usage never contains money; pricing is yours.
Situation Retry? Which invocation_id
Errors without execution: 429 COMMON.RATE_LIMITED, 503 SERVICES.RECORD_UNAVAILABLE, 503 SERVICES.PROVIDER_DISABLED Yes, later The same id
Request errors: 400, 413, 415, 422 COMMON.VALIDATION_FAILED After fixing the request The same id
outcome failed, for example PROVIDER.UNAVAILABLE, PROVIDER.RATE_LIMITED, COMMON.TIMEOUT Yes, honoring Retry-After A new id (the old one returns 409)
outcome unknown (502 EXECUTION.OUTCOME_UNKNOWN) Not automatically Reconcile in the call log first, then decide
409 EXECUTION.DUPLICATE_INVOCATION No need Read the attached execution for the first result

Providers time out after 30 seconds by default; some take longer (world-bank allows 60 seconds; see timeout_seconds in the reference). Use a client read timeout of at least 90 seconds so you never disconnect before the execution is recorded.

Endpoint Auth Meaning
GET /health/live None The process is alive
GET /health/ready None Configuration and database are available; never calls a paid provider