Documentation

Support

Triggers

Webhooks

Learn how webhook actions send event payloads to an external URL when a trigger fires.
Read time 6 minutesLast updated 3 hours ago

You can configure a trigger to send an HTTP request to an external URL when an event is fired. This is called a webhook action. Use webhooks to integrate UGS events with your own backend, third-party APIs, or notification services (for example Slack or Discord) without running Cloud Code. When the trigger fires, the Triggers service sends an HTTP request to the URL you configure, using the method, headers, and body you specify. Use a payload template to shape the request body from the event data. Failed deliveries are stored in the dead letter queue, where you can inspect and replay them.

When to use webhooks

Use a webhook action when you want to:
  • Notify an external system when a UGS event occurs (for example, player signed up, score submitted, or a scheduled time).
  • Forward event data to your own server or a third-party API in a custom format.
  • Post notifications to a messaging service (for example Slack or Discord) when players perform key actions.
  • Avoid running Cloud Code for simple HTTP callouts.
Use a Cloud Code action when you need to run game logic, call other UGS APIs with a service token, or perform multi-step logic before calling an external URL.

Webhook configuration

When you create a trigger with
actionType: webhook
, you must provide a
webhook
object with the following fields:

Field

Required

Description

url
YesThe destination URL. Must be a valid HTTP or HTTPS endpoint that resolves to a public IP address. Maximum length 2,048 characters.
method
NoThe HTTP method. Supported values:
GET
,
POST
,
PUT
,
DELETE
,
PATCH
,
HEAD
,
OPTIONS
. Defaults to
POST
when omitted.
headers
NoHTTP headers as key-value pairs. Maximum 10 entries. Each header name must be ASCII and at most 256 characters. Each header value must not be empty and must be at most 8,192 characters. If
Content-Type
is not set, it defaults to
application/json
.
payloadTemplate
ConditionalA template that builds the request body from the event payload. Required when
Content-Type
is not
application/json
. Optional for JSON — when omitted, the full event payload is forwarded as-is. Maximum 100,000 characters.
The trigger also requires an
actionUrn
that identifies the webhook. Use
urn:ugs:webhook
. The URN is used for logging and dead letter queue management when delivery fails.
Note
The webhook URL must resolve to a public IP address. The Triggers service rejects URLs that point to localhost, private IP ranges, or link-local addresses at the time the trigger is created.

Content types

The following content types are supported for webhook payloads. Set the content type by including a
Content-Type
header in the
headers
field, or by selecting it in the Unity Dashboard.

Content type

Payload format

application/json
(default)
Valid JSON. Payload is optional — when omitted, the full event payload is forwarded as-is.
application/xml
XML body.
text/plain
Raw text body.
text/html
HTML body.
application/x-www-form-urlencoded
URL-encoded key-value pairs separated by
&
(for example
a=1&b=2
, with keys and values percent-encoded).
multipart/form-data
Multipart body with boundary lines and
Content-Disposition: form-data
headers for each field.
For all content types other than
application/json
, the
payloadTemplate
field is required.

Auto-injected headers

The Triggers service automatically adds the following headers to every outbound webhook request. You cannot override the
User-Agent
header. The
Content-Type
and
Accept
headers are only added if you have not already set them in your trigger configuration.

Header

Value

Notes

Content-Type
application/json
Added as default only if not already present in your headers.
Accept
application/json
Added as default only if not already present in your headers.
User-Agent
Unity-Triggers/1.0
Always set; cannot be overridden.
X-Request-ID
Request identifierA UUID set per-request for tracing purposes.
X-Unity-Event-ID
Event IDThe unique ID of the event that fired the trigger.
traceparent
W3C trace contextIncluded to support distributed tracing on your end, if needed.

Template syntax

URL, headers, and
payloadTemplate
support template expressions so you can inject event data and secrets. Wrap expressions in double curly braces
{{ }}
.
Templates are evaluated at request time. If a referenced event field does not exist, it renders as an empty string rather than causing an error.

Event payload

In all three (URL, headers,
payloadTemplate
), the current event payload is available as the root object. Use
{{.}}
to output the entire payload as JSON, or
{{.fieldName}}
to output a single field (for example
{{.playerId}}
,
{{.score}}
). Field names match the event payload structure for the given event type. Refer to Supported UGS events for payload shapes per event type.
Note
Template field access (for example
{{.playerId}}
) requires the event payload to be a JSON object. The payload from all UGS events is a JSON object, so this is satisfied automatically for standard event triggers.

Event fields in headers

You can use event payload fields in header values, for example
X-Player-ID: {{.playerId}}
or
X-Score: {{.score}}
.

Using secrets in templates

You can reference secrets stored in Secret Manager inside templates to handle authentication, signature verification, or to inject other sensitive values. The Triggers service resolves secrets at request time, so the raw value is never stored in the trigger configuration. Store each secret in Secret Manager and use its key as
SECRET_NAME
in the template expression. The following functions are available:

Function

Description

Example

{{ hmac_sha256 "SECRET_NAME" }}
HMAC-SHA256 signature of the final request body, hex-encoded. Uses the named secret as the shared key. Your backend recomputes the signature using the same shared secret and compares it to verify the request came from Triggers. Computed after the payload template is rendered.
X-Signature-256: {{ hmac_sha256 "WEBHOOK_SECRET" }}
{{ hmac_sha512 "SECRET_NAME" }}
HMAC-SHA512 signature of the final request body, hex-encoded. Uses the named secret as the shared key. Your backend recomputes the signature using the same shared secret and compares it to verify the request came from Triggers. Computed after the payload template is rendered.
X-Signature-512: {{ hmac_sha512 "WEBHOOK_SECRET" }}
{{ secret "SECRET_NAME" }}
Raw secret value. Use for API keys or Basic auth credentials.
Authorization: Basic {{ secret "API_KEY" }}
{{ jwt }}
Short-lived JWT minted by the Triggers service for the request. Contains
projectId
and
environmentId
claims. Use for Bearer auth to confirm the request originates from your Triggers project.
Authorization: Bearer {{ jwt }}
Your backend can verify an HMAC signature by independently computing the same HMAC over the received request body using the same shared secret, and comparing the result to the signature header value. The shared secret is stored in Secret Manager and is known only to the Triggers service and your backend. To verify a JWT, your backend validates the token's signature and checks that the
projectId
and
environmentId
claims match the expected values for your project.

Quoting and escaping template expressions

Template expressions use double quotes for function argument names:
{{ secret "SECRET_NAME" }}{{ hmac_sha256 "SECRET_NAME" }}
In the Unity Dashboard, enter template expressions exactly as shown above. The Dashboard handles JSON serialization automatically when it submits the form. When configuring via the API or CLI, the template is sent as a JSON string value. Every
"
in the template, including those inside template function argument names, must be escaped as
\"
. For example, a header value:
"X-Signature-256": "{{ hmac_sha256 \"WEBHOOK_SECRET\" }}"
For example, a
payloadTemplate
with a secret inside a JSON string value:
"payloadTemplate": "{\"token\": \"{{ secret \"VERIFY_TOKEN\" }}\"}"

URL

Use template expressions to inject secrets or event data into the webhook URL.

Expression

Description

Example

{{ secret "SECRET_NAME" }}
Insert the secret value into the URL path or query string.
https://mywebsite.com/12345/{{ secret "PATH_TOKEN" }}
{{.fieldName}}
Insert an event payload field into the URL.
https://api.example.com/users/{{.playerId}}/events

Payload template

Use template expressions to build the request body from the event payload.

Expression

Description

Example

{{.}}
Entire event payload as JSON.
{"wrapped": {{.}}}
{{.fieldName}}
Single field from the event payload.
{"score": {{.score}}}
{{ secret "SECRET_NAME" }}
Insert a secret value into the body.
{"token": "{{ secret "VERIFY_TOKEN" }}"}
Wrap the event and add a shared secret for verification (API/CLI format):
"payloadTemplate": "{\"event\": \"score-submitted\", \"data\": {{.}}, \"token\": \"{{ secret \"VERIFY_TOKEN\" }}\"}"

Example webhook trigger

The following example shows how to create a webhook trigger using the API. It sends a POST request when a leaderboard score is submitted, with a JSON body built from the event and an HMAC signature header:
{ "name": "notify-score-webhook", "eventType": "com.unity.services.leaderboards.score-submitted.v1", "actionType": "webhook", "actionUrn": "urn:ugs:webhook", "webhook": { "url": "https://example.com/events", "method": "POST", "headers": { "Content-Type": "application/json", "X-Signature-256": "{{ hmac_sha256 \"WEBHOOK_SECRET\" }}" }, "payloadTemplate": "{\"event\": \"score-submitted\", \"data\": {{.}}}" }}
Ensure the secret
WEBHOOK_SECRET
exists in Secret Manager and that the Triggers service has access to it.

Filters

You can add a filter to a webhook trigger so the HTTP request is only sent when the filter condition is true. For example, only send when a specific leaderboard is used or when a score is above a threshold.

Retries and failed delivery

The Triggers service retries webhook delivery on server errors, timeouts, and rate-limiting responses. It makes up to 3 application-level retries using exponential backoff. After retries are exhausted, the event is stored in the dead letter queue, where you can replay or discard it. Client errors (4xx, except 429) are not retried and are not added to the queue. For the full retry behavior including which status codes are retried and how
Retry-After
is handled, refer to Failure handling. For delivery rate limits and DLQ capacity, refer to Limits.

Additional resources