Secrets
Store API tokens, signing secrets and passwords as encrypted, write-only secret service connections and import them into Webhook Relay functions with require("secret:alias").
Secret service connections store API tokens, signing secrets and passwords for your Functions. They are encrypted at rest and write-only — once saved, the value can be used by your functions but never read back through the API or the dashboard.
Instead of pasting credentials into function source code, functions import a secret by alias:
const apiToken = require("secret:api-token")
const resp = http.get("https://api.example.com/data", {
headers: { Authorization: "Bearer " + apiToken }
})
How it works
- Declare — your function imports
require("secret:<alias>"). Secret imports are detected statically when the function is created or updated, so the platform always knows which secrets a function needs. - Store — create a Secret service connection at my.webhookrelay.com/service-connections holding the credential value.
- Bind — on the function's Connections tab, bind each alias to one of your secret connections. The same connection can be reused across many functions.
- Run — before your code executes, every imported alias is preflighted. If an alias is not bound, execution stops with a clear error before any user code runs. Resolved values are injected only into the execution runtime.
Alias names must start with a letter and contain only letters, numbers, underscores or hyphens (64 characters max) — for example api-token, stripe_signing_secret.
Binding secrets in the dashboard
Open a function and switch to the Connections tab. It lists every secret: import found in the source, together with its binding status:
- missing — the alias is not bound yet. Use the deep-linked setup flow to create a new secret (or pick an existing one) and bind it; you'll be returned to the function afterwards.
- connected — the alias is bound to a healthy secret connection and the function is ready to run. A bound alias can also show the underlying connection's
pendingorerrorstatus.
When you remove a require("secret:...") import from the source, its stale binding is pruned automatically on save. Restoring an older function version re-checks the imports of that version.
Managing secrets via the API
Secret connections use the standard service connections API with service_type: secret. Function bindings have their own endpoints:
| Method | Path | Description |
|---|---|---|
GET | /v1/functions/{id}/connections | List connection requirements (alias, status, bound connection) |
PUT | /v1/functions/{id}/connections/{alias} | Bind an alias to a secret connection ({"service_connection_id": "..."}) |
DELETE | /v1/functions/{id}/connections/{alias} | Unbind an alias |
Function reads also return a requirements field so automation (including the MCP server) can detect unbound secrets. All endpoints are covered by audit logs.
Secrets vs function config (cfg)
Functions also have a per-function config store read with cfg.get("key"). When should you use which?
require("secret:alias") | cfg.get("key") | |
|---|---|---|
| Scope | Account-wide, reusable across functions | Per function |
| Readable after saving | No — write-only | Yes |
| Missing value | Execution blocked before user code runs | Returns empty value at runtime |
| Redaction | Exact values redacted from errors and logs | Not redacted |
| Best for | API tokens, signing secrets, passwords | Non-sensitive tunables, flags, endpoints |
For anything you'd call a credential, prefer secret connections.
Security
- Encryption at rest — secret values are encrypted with AES-256-GCM, like all service connection credentials.
- Write-only — API responses and the dashboard never return the stored value.
- Redaction — exact secret values are redacted from function runtime errors and console/log output.
- Preflight — secrets resolve before user code runs; an unbound alias fails fast instead of executing with a missing credential.
- Deletion protection — a secret connection still bound to a function cannot be deleted (the API returns
409 Conflict) until it is unbound or the import is removed. - Account isolation — secrets can only be bound to functions in the same account.
Secret values are limited to 64 KiB.
Next steps
- Functions overview — what functions can do and how to write them.
- Helper libraries — curated modules you can
require()alongside secrets. - Make HTTP requests — call external APIs using your stored tokens.
