DocumentationSecrets

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 }
})
local api_token = require("secret:api-token")
local http = require("http")

local resp, err = http.get("https://api.example.com/data", {
  headers = { Authorization = "Bearer " .. api_token }
})
if err then error(err) end

How it works

  1. 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.
  2. Store — create a Secret service connection at my.webhookrelay.com/service-connections holding the credential value.
  3. 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.
  4. 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.

The account agent directs missing aliases to this secure Connections flow. It never asks you to paste a secret into chat; create or rotate the value only in the write-only Service Connections dialog.

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 pending or error status.

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:

MethodPathDescription
GET/v1/functions/{id}/connectionsList 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")
ScopeAccount-wide, reusable across functionsPer function
Readable after savingNo — write-onlyYes
Missing valueExecution blocked before user code runsReturns empty value at runtime
RedactionExact values redacted from errors and logsNot redacted
Best forAPI tokens, signing secrets, passwordsNon-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

Did this page help you?