Skip to main content
An invocation is a request to execute a handler. You can invoke handlers over HTTP with or without waiting for a response, and with or without an idempotency key. Make sure to first register the handler you want to invoke. The UI helps you with invoking your services. Open the UI at port 9070, register your service, click on the service, open the playground, and invoke your handlers from there.
Each invocation has its own unique ID and lifecycle. Have a look at managing invocations to learn how to manage the lifecycle of an invocation.
All ingress endpoints live under the reserved /restate/ path prefix. To invoke a handler, use /restate/call/... to wait for the response or /restate/send/... to send a message without waiting:
# Request-response
POST /restate/call/{service}/{handler}
POST /restate/call/{service}/{key}/{handler}

# Send a message (no response)
POST /restate/send/{service}/{handler}
POST /restate/send/{service}/{key}/{handler}
Add the {key} segment for Virtual Objects and Workflows; omit it for basic Services.
The unversioned paths (/{service}/{handler}, /{service}/{key}/{handler}, and the /send suffix) still work for backwards compatibility, but new code should use the /restate/ paths documented here.

Request-response calls

You can invoke services over HTTP 1.1 or higher. Request/response bodies should be encoded as JSON. Invoke myHandler of MyService as follows:
curl localhost:8080/restate/call/MyService/myHandler \
  --json '{"name": "Mary", "age": 25}'
Invoke myHandler of MyVirtualObject for myObjectKey as follows:
curl localhost:8080/restate/call/MyVirtualObject/myObjectKey/myHandler \
  --json '{"name": "Mary", "age": 25}'
Call the run handler of the MyWorkflow as follows:
curl localhost:8080/restate/call/MyWorkflow/myWorkflowId/run \
  --json '{"name": "Mary", "age": 25}'
A workflow can be submitted only once. Resubmission of the same workflow will fail with “Previously accepted”. The invocation ID can be found in the request header x-restate-id. Follow the same pattern for calling the other handlers of the workflow.
Note that all invocations go first via the Restate Server. The server then forwards the request to the appropriate service. Therefore, localhost:8080 refers to ingress port of the Restate Server, not the service instance.

Sending messages

If you do not want to wait for the response, you can send a message by using /restate/send/... instead of /restate/call/...:
curl localhost:8080/restate/send/MyService/myHandler \
  --json '{"name": "Mary", "age": 25}'
Example output:
{"invocationId":"inv_1aiqX0vFEFNH1Umgre58JiCLgHfTtztYK5","status":"Accepted"}
The response contains the Invocation ID. You can use this identifier to cancel or kill the invocation.

Delayed messages

You can delay the message by adding a delay request parameter in ISO8601 notation or using humantime format:
curl "localhost:8080/restate/send/MyService/myHandler?delay=10s" \
    --json '{"name": "Mary", "age": 25}'
You cannot yet use this feature for workflows. Workflows can only be scheduled with a delay from within another Restate handler (TS/Java/Kotlin).

Using an idempotency key

You can send requests to Restate providing an idempotency key, through the Idempotency-Key header:
curl localhost:8080/restate/call/MyService/myHandler \
  -H 'idempotency-key: ad5472esg4dsg525dssdfa5loi' \
  --json '{"name": "Mary", "age": 25}'
After the invocation completes, Restate persists the response for a retention period of one day (24 hours). If you re-invoke the service with the same idempotency key within 24 hours, Restate sends back the same response and doesn’t re-execute the request to the service. Check out the service configuration docs to tune the retention time.
When the controlled-idempotent-sharding cluster feature is enabled (the default for new clusters), the ingress assigns a random idempotency key to service and virtual object calls that don’t send an Idempotency-Key header. This lets the ingress safely retry in-flight requests without duplicate execution, and means the completed invocation is retained for the idempotency retention period. It does not deduplicate across different requests, since each call gets a distinct key.
With Restate and an idempotency key, you can make any service call idempotent, without any extra code or setup. This is a very powerful feature to ensure that your system stays consistent and doesn’t perform the same operation multiple times.

Scopes

Scopes are part of the flow control feature. Scoped invocations are rejected unless the server is started with the experimental vqueues feature enabled (experimental-enable-vqueues = true).
A scope is an opaque key that assigns an invocation to scope, which Restate uses to apply flow control across invocations that share the same scope. Add a scope/{scopeKey} segment in front of the call or send verb:
POST /restate/scope/{scopeKey}/call/{service}/{handler}
POST /restate/scope/{scopeKey}/call/{service}/{key}/{handler}
POST /restate/scope/{scopeKey}/send/{service}/{handler}
POST /restate/scope/{scopeKey}/send/{service}/{key}/{handler}
For example, to call MyService/myHandler within the scope tenant-a:
curl localhost:8080/restate/scope/tenant-a/call/MyService/myHandler \
  --json '{"name": "Mary", "age": 25}'
See flow control to learn how to configure concurrency limits for a scope.

Cancel

You can cancel an invocation as follows:
curl
curl -X PATCH http://localhost:9070/invocations/inv_1gdJBtdVEcM942bjcDmb1c1khoaJe11Hbz/cancel

Attach to an invocation

Restate allows you to retrieve the result of workflows and invocations that used an idempotency key. There are two options:
  • To attach to an invocation or workflow and wait for it to finish, use attach.
  • To peek at the output of an invocation or workflow, use output. This will return:
    • {"message":"not ready"} for ongoing invocations
    • The result for finished invocations
    • {"message":"not found"} for non-existing invocations

By invocation ID

If you already have the invocation ID, attach to it or read its output with a GET request:
curl localhost:8080/restate/attach/myInvocationId
curl localhost:8080/restate/output/myInvocationId

By target

If you don’t have the invocation ID, send a POST request to /restate/attach or /restate/output with a JSON body describing the workflow or idempotency target. You can also address an invocation by its ID through the same body shape, as an alternative to the GET form above:
curl localhost:8080/restate/attach \
  --json '{"target": "workflow", "workflowName": "MyWorkflow", "workflowKey": "myWorkflowId"}'
Use the same body shape against /restate/output to peek at the result. If the target was invoked within a scope, add the optional "scope" field to the body.

Looking up the invocation ID

To resolve a workflow or idempotency target into its invocation ID, send a POST request to /restate/lookup with the same body shape as above:
curl localhost:8080/restate/lookup \
  --json '{"target": "workflow", "workflowName": "MyWorkflow", "workflowKey": "myWorkflowId"}'
The response contains the invocation ID, which you can then pass to the GET attach and output endpoints:
{"invocationId": "inv_1aiqX0vFEFNH1Umgre58JiCLgHfTtztYK5"}

OpenAPI support

Restate exposes for every service an OpenAPI 3.1 definition, to get it:
curl localhost:9070/services/MyService/openapi > MyService_openapi.json
You can use this definition with any OpenAPI 3.1 compliant tool to generate clients for your service, such as openapi-generator. Depending on the SDKs, the rich input/output JSON schemas are included as well. At the moment, rich schemas are supported for: