Generate a forward signing secret
Generate a new signing secret for a forward action of a route. It is shown once; every forward POST is then signed with it so your endpoint can verify the sender.
Creates a fresh whsec_… secret for one forward action of the route and returns it once. It is stored sealed and never shown again — route responses only say has_secret: true. From the next delivery on, every forward POST carries Apifon-Signature and X-Apifon-Signature: the hex HMAC-SHA256 of the raw request body computed with this secret. Verify it before trusting the payload, exactly as you would a webhook signature.
POST /v3/routes/{id}/secret
Use this call to rotate a secret you may have leaked, or to add one to a forward action created without secret. The previous secret stops being used immediately, so update your endpoint first if it verifies strictly. To set a secret of your own choosing, pass secret on Create or Update an inbound route instead; secret: null on update removes it. Requires a `full_access` key. Limit: 30 calls per minute per key.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | uuid | Required | The route ID. |
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Optional | The forward URL whose secret to generate. Required when the route has several forward actions; may be omitted when it has one. |
Responses
| Status | Description |
|---|---|
201 | Created. { route_id, url, secret } — store secret now, it is never returned again. |
400 | validation_error — the route has several forward actions and url is missing, or url is not one of them. |
401 | Missing or invalid API key. |
403 | insufficient_scope — requires a full_access key. |
404 | No such route on your workspace. |
409 | no_forward_action — the route has no forward action to secure. |
429 | Rate limit exceeded (30 calls per minute). |
Code examples
# One forward action on the route: no body needed
curl -X POST https://api.wemail.io/v3/routes/0b7e4c2d-9a1f-4e6b-8c3d-5f2a1b9e7d40/secret \
-H "Authorization: Bearer afn_live_…" \
-H "Content-Type: application/json" \
-d '{"url": "https://app.example.com/inbound"}'
# 201 {"route_id":"0b7e4c2d-9a1f-4e6b-8c3d-5f2a1b9e7d40","url":"https://app.example.com/inbound","secret":"whsec_…"}const res = await fetch("https://api.wemail.io/v3/routes/0b7e4c2d-9a1f-4e6b-8c3d-5f2a1b9e7d40/secret", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.WEMAIL_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://app.example.com/inbound" }),
});
const { secret } = await res.json();
// Store it now — it is never returned again. Verify forwards with:
// crypto.createHmac("sha256", secret).update(rawBody).digest("hex") === req.headers["apifon-signature"]import os, requests
r = requests.post(
"https://api.wemail.io/v3/routes/0b7e4c2d-9a1f-4e6b-8c3d-5f2a1b9e7d40/secret",
headers={"Authorization": f"Bearer {os.environ['WEMAIL_API_KEY']}"},
json={"url": "https://app.example.com/inbound"},
)
secret = r.json()["secret"] # store it now — never returned again
# verify a forward: hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() == request.headers["Apifon-Signature"]client, _ := wemail.NewClient(os.Getenv("WEMAIL_API_KEY"))
ctx := context.WithValue(context.Background(), wemail.ContextAccessToken, os.Getenv("WEMAIL_API_KEY"))
out, _, err := client.API.RoutesAPI.RotateInboundRouteSecret(ctx, "0b7e4c2d-9a1f-4e6b-8c3d-5f2a1b9e7d40").Execute() // one forward action: no body
fmt.Println(out.Url, out.Secret) // store the secret now — never returned again{
"route_id": "0b7e4c2d-9a1f-4e6b-8c3d-5f2a1b9e7d40",
"url": "https://app.example.com/inbound",
"secret": "whsec_4f2a9c1e7b3d5a8e6c0f1b2d3e4a5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
}