Webhooks
Webhooks are a way to interact with Orvanta using standard web technologies.
Some use cases include triggering scripts and flows from Slack or Emails.
Webhooks for scripts & flows
Section titled “Webhooks for scripts & flows”Each script and flow created in Orvanta gets autogenerated webhooks. The webhooks depend on how they are triggered, and what their return values are.
Addresses
Section titled “Addresses”Webhook links can be found on the Detail page of each Script and Flow, on the Details and Triggers tab.
Each webhook has two URLs, one with the path to the script, i.e. /p/u/<your_user>/<your_script_name>, which will always trigger the latest version of the Script/Flow and the other one with just a hash, i.e. /h/<hash>, hiding potentially sensitive information and always corresponding to that version of the script, even with overwrites.
Version-pinned webhooks (flows)
Section titled “Version-pinned webhooks (flows)”Flows additionally expose version-pinned webhook endpoints that target a specific flow version by its numeric version ID instead of the latest deployment. They use the fv/<version> path segment and are available in the Triggers tab of the flow:
# async/api/w/<workspace>/jobs/run/fv/<version># sync/api/w/<workspace>/jobs/run_wait_result/fv/<version># SSE stream/api/w/<workspace>/jobs/run_and_stream/fv/<version>Unlike the script /h/<hash> endpoint, the flow-by-version URL is stable across redeploys and guarantees that integrations keep calling the exact flow version they were tested against, even after new versions are published. Callers still need a token with permission to run the flow.
Asynchronous
Section titled “Asynchronous”Jobs can be triggered in asynchronous mode, meaning that the webhook is triggered, and the returning value is the uuid of the job assigned to execute the underlying code.
These links are available in the “UUID/Async” tab.
Synchronous
Section titled “Synchronous”The second type of autogenerated endpoint is the synchronous webhook. This webhook triggers the execution, automatically extracts the underlying code’s return value and returns it as the response.
Every script exposes an endpoint that triggers the Script but waits for its full execution before returning.
The endpoint has the following format:
https://app.orvanta.cloud/api/w/$WORKSPACE_ID/jobs/run_wait_result/$SCRIPT_PATHwhere $SCRIPT_PATH is the path of the Script in the workspace, including the prefix u/ or f/.
These links are available in the “Result/Sync” tab.
For scripts, there is an additional synchronous webhook available that accepts a GET request. The payload must be passed as the query arg payload and encoded in JSON first, then in a URL safe base64, e.g: encodeURIComponent(btoa(JSON.stringify({a: 2}))). This endpoint has the same URL as the Result/Sync POST Path URLs.
Custom timeout for sync endpoints
Section titled “Custom timeout for sync endpoints”You can set a max timeout for sync endpoints at the instance level.
Asynchronous vs. synchronous
Section titled “Asynchronous vs. synchronous”It’s always better to use asynchronous mode as it allows your client not to wait for the response and it avoids Orvanta having to maintain a connection to your client while the job is running. However, for short-running jobs where it’s easier in your code to block until you get a response, then use the synchronous mode.
When using the synchronous mode, the webhook returns the result of the script directly. If the script returns an error, the default behavior is to return a 200 status code with the error as a JSON object. You can customize the HTTP status code if needed.
When using the asynchronous mode, the webhook returns a uuid and you can poll the get job API call to fetch the status and results once it is completed.
Content types
Section titled “Content types”Webhooks accept any content type, not just application/json. When the body is not JSON, the raw body string is available via a raw_string argument. Orvanta still attempts to parse the body as JSON regardless of the content type, falling back gracefully for non-JSON payloads (XML, plain text, form-urlencoded, etc.).
User token
Section titled “User token”To interact with Orvanta you always need to use Bearer token authentication.
You can generate tokens for your own account in the Account Settings menu in the app. Open it by clicking your username on the side menu, then select “Account settings”.
Labels are only used to allow users to easily distinguish keys. Tokens can also be created with granular scopes to restrict access to specific resources and actions.
You can only see the token once, when it’s created. Make sure to store it securely!
When SMTP is configured, token owners automatically receive an email notification 7 days before a token expires, and again when the token is deleted after expiry. The tokens table in user settings also shows color-coded expiration badges for tokens expiring within 30 days.
Webhook specific tokens
Section titled “Webhook specific tokens”Webhook specific tokens allow sharing tokens publicly without fear since the token will only be able to trigger a specific script/flow and not impersonate you for any other operations.
It also avoids the hassle of having to create an anonymous user and check their permissions. If you can run the script yourself, then the webhook specific token will still inherit your own permissions.
Triggering
Section titled “Triggering”Once you have a webhook URL and a user token, issue a request to the endpoint and you will get the appropriate return as response.
The bearer token must be passed as either an Authorization: Bearer <TOKEN> header, or as a token query parameter: https://<instance>/<route>?token=<TOKEN>
Due to security reasons, it is highly recommended to pass the token in the header. If it’s not possible, then the URL that contains the token should be treated as a secret.
Examples using cURL for POST requests:
## Request with Headercurl -X POST \ --data '{}' \ -H "Content-Type: application/json" \ -H "Authorization: Bearer supersecret" \ ".../w/demo/jobs/run_wait_result/p/u/bot/hello_world_deno"
## Query parametercurl -X POST \ --data '{}' \ -H "Content-Type: application/json" \ ".../w/demo/jobs/run_wait_result/p/u/bot/hello_world_deno?token=supersecret"Examples using cURL for synchronous GET requests:
## Request with Headercurl -X GET \ -H "Content-Type: application/json" \ -H "Authorization: Bearer supersecret" \ ".../w/demo/jobs/run_wait_result/p/u/bot/hello_world_deno?payload=<URL_SAFE_BASE64_ENCODED_JSON>"You can find an example using only standard Deno libraries on the Orvanta Hub.
You can also verify that the job has been triggered and run (or investigate any encountered issues), by checking the Runs menu on the app.
The webhook endpoints accept a JSON object or url encoded form data as the body, where each key corresponds to an argument of the script/flow.
Non object payload / body
Section titled “Non object payload / body”If the payload is not an object, it will be wrapped in an object with the key body and the value will be the payload/body itself. e.g:
[1,2,3] => {"body": [1,2,3]}and your script can process it as:
def main(body: List[int]): print(body)Wrapping body, handling arbitrary payload
Section titled “Wrapping body, handling arbitrary payload”You can also force the payload to be wrapped in an object at the key body by passing the query arg wrap_body=true. This is useful when the payload is not known in advance and you want to handle it in your script. e.g:
Python:
def main(body: Any): print(body)TypeScript:
export async function main(body: any) { console.log(body);}Raw payload / body
Section titled “Raw payload / body”Similarly to request headers, if the query args contain raw=true, then an additional argument will be added: raw_string which contains the entire json payload as a string (without any parsing). This is useful to verify the signature of the payload for example (Discord requires the endpoints to verify the signature for instance).
Handling form data (file uploads)
Section titled “Handling form data (file uploads)”The webhook endpoints also accept multipart/form-data, useful for file uploads. The payload should be a FormData object, where each key corresponds to an argument of the script/flow.
For file fields, the value will be an array containing S3 objects with the path to the uploaded files in the workspace object storage (e.g., S3).
Here’s an example script for handling form data with a file field:
TypeScript:
import { S3Object } from 'orvanta-client';export async function main(mytextfield: string, myfilefield: S3Object[]) { return myfilefield;}Python:
import orvantafrom typing import List
def main(mytextfield: str, myfilefield: List[orvanta.S3Object]): return myfilefieldA workspace object storage must be configured to accept form data payloads.
Request headers
Section titled “Request headers”It is possible for jobs to take request headers as arguments. To do so, either specify in the query args the headers to process at include_header, separated with ,. e.g:
/api/w/workspace/jobs/run_wait_result/p/u/user/new_script?include_header=X-Sign,fooor use the env variable: INCLUDE_HEADERS with the same format so that all requests to any job will include the headers.
Query args
Section titled “Query args”It is possible to pass query args to the job. To do so, either specify in the query args the headers to process at include_query, separated with ,. e.g for a sync get request (works for all endpoints):
/api/w/workspace/jobs/run_wait_result/p/u/user/new_script?include_query=a,b,c&a=foo&b=bar&c=foobarto have a: “foo”, b: “bar”, c: “foobar”, passed as args.
Custom response code
Section titled “Custom response code”For all sync run jobs endpoints, if the response contains a key wm_status_code (or its longer alias orvanta_status_code) with a number value, that value will be used as the status code. For example, if a script or flow returns:
{ "wm_status_code": 201, "result": { "Hello": "World" }}the synchronous endpoint will return:
{ "Hello": "World"}with a status code 201.
Note that if the status code is invalid (w.r.t RFC9110), the endpoint will return an error.
Custom response content type
Section titled “Custom response content type”Similarly to the above, for all sync run jobs endpoints, if the response contains a key wm_content_type (or its longer alias orvanta_content_type), the associated value will be used as the content type header of the response. For example, if a script or flow returns:
{ "wm_content_type": "text/csv", "result": "Hello;World"}the synchronous endpoint will return:
"Hello;World"with the response header: “Content-Type: text/csv”.
Custom response headers
Section titled “Custom response headers”Similar to the above, for all sync run jobs endpoints, if the response contains a key wm_headers (or its longer alias orvanta_headers), the headers will be added to the response. For example, if a script or flow returns:
{ "wm_headers": { "X-Custom-Header": "foo" }, "result": { "Hello": "World" }}the synchronous endpoint will return the result with the header X-Custom-Header: foo (in addition to Content-Type: application/json).
It’s better to use wm_content_type to override the content type, as the output will be correctly formatted.
Return early for flows
Section titled “Return early for flows”It is possible to define a node at which the flow will return for sync endpoints. The rest of the flow will continue asynchronously.
Useful when some webhooks need to return extremely fast but not just the uuid (define first step as early return) or when the expected return from the webhook doesn’t need the full flow being computed.
Exposing a webhook URL
Section titled “Exposing a webhook URL”A single port proxy can be leveraged to expose a webhook with a custom URL. In its docker-compose, Orvanta uses Caddy but the logic can be adapted for others.
In the Caddyfile, the handle_path and rewrite directive can be used:
{$BASE_URL} { bind {$ADDRESS} handle_path /mywebhook { rewrite * /api/w/demo/jobs/run_wait_result/p/u/bot/hello_world_deno" ## You can optionally inject the token in Caddy to have the endpoint exposed publicly ## request_header Authorization "Bearer <ORVANTA_GENERATED_TOKEN>" } ... reverse_proxy /* http://orvanta_server:8000}The job can then be triggered with:
curl -X POST \ --data '{}' \ -H "Content-Type: application/json" \ ".../mywebhook?payload=<URL_SAFE_BASE64_ENCODED_JSON>"Cloud events 1.0
Section titled “Cloud events 1.0”Orvanta’s webhooks aim to be compatible with the Cloud Events 1.0 specification. The envelope metadata will be parsed into a special argument WEBHOOK__METADATA__ for scripts and flows.
Nothing extra needs to be done on Orvanta’s side; if a request has the cloudevent content header it will automatically be handled according to the specification. When using webhook producers that allow it, you can select to use the cloud events schema. For example with Azure Event Grid.
Orvanta does not support batching cloud events yet. This means that requests with the content type set to 'application/cloudevents-batch+json' will return an error response.
Delete after use
Section titled “Delete after use”For a script, delete logs, arguments and results after use.
This setting ONLY applies to synchronous webhooks. If used individually, this script must be triggered using a synchronous endpoint to have the desired effect.
The logs, arguments and results of the job will be completely deleted from Orvanta once it is complete and the result has been returned.
The deletion is irreversible.
SSE stream webhooks
Section titled “SSE stream webhooks”In addition to classical webhooks, runnables are associated with SSE Stream Webhooks. These are only useful when the runnable returns a stream. They trigger the job and then return an SSE stream.
The endpoints follow the same convention as classical webhooks, but use the base path /api/w/workspace/jobs/run_and_stream/. You can find the SSE Stream Webhook URL on the Detail page of each Script and Flow, under the Details and Triggers tab. They support both GET and POST requests.
To get the stream updates of an existing job with SSE, use /api/w/:workspace/job_u/getupdate_sse/:id (pass query arg ?fast=true for a new job to get fast polling at first).
For flows, a stream will be returned if the last step is a script that returns a stream.
The SSE stream returns JSON objects with the detailed shape available. For the stream endpoint, you will mainly get the following events with different available fields:
// update event with new result stream data{ "type": "update", "new_result_stream": "string", // string: new result stream data since last update "stream_offset": 456 // integer: current result stream offset}
// update event with result once job is complete{ "type": "update", "completed": true, // boolean: whether the job is completed "only_result": ..., // String of the complete stream or JSON object with a `wm_stream` field containing the complete stream "new_result_stream": "string", // optionally, the last part of the stream}The first event is sent one or more times as the stream progresses with new data. The second event is sent when the job is complete, containing the result of the job in the only_result field. The result will be a string containing the complete stream or a JSON object with the complete stream in the wm_stream field if there is already a result.
Export webhook definitions to OpenAPI
Section titled “Export webhook definitions to OpenAPI”Orvanta supports generating an OpenAPI 3.1 specification that includes both HTTP routes and webhook triggers.
Webhook endpoints included in the spec:
- Are matched using filters you define
- Include
summaryanddescriptionif available - Are automatically mapped to use JWT Bearer authentication in the spec
You can generate this from the Custom HTTP routes page.
Workspace webhook
Section titled “Workspace webhook”Connect your Orvanta workspace to an external service to sync or get notified about any change.
From workspace settings, go to the “Webhooks” tab and fill in a URL under “URL to send requests to”.
The following event types are sent to the workspace webhook:
| Event type | Description |
|---|---|
CreateScript, UpdateScript, DeleteScript, DeleteScriptPath | Script lifecycle events |
CreateFlow, UpdateFlow, ArchiveFlow, DeleteFlow | Flow lifecycle events |
CreateApp, UpdateApp, DeleteApp | App lifecycle events |
CreateResource, UpdateResource, DeleteResource | Resource lifecycle events |
CreateResourceType, UpdateResourceType, DeleteResourceType | Resource type lifecycle events |
CreateVariable, UpdateVariable, DeleteVariable | Variable lifecycle events |
CreateFolder, UpdateFolder, DeleteFolder | Folder lifecycle events |
TokenExpiringSoon | An API token is expiring within 7 days |
TokenExpired | An API token has expired and been deleted |
Instance events webhook
Section titled “Instance events webhook”For instance-level events (user added, OAuth signup, user invited or joined a workspace), configure the instance events webhook from instance settings. This is separate from the workspace webhook above and only available on Enterprise Edition.