Create an inbound route
Create an inbound route from an expression and actions, or with the one-line convenience body { address, url, secret } that stores and forwards.
Two body shapes are accepted — exactly one of them per request:
- Full form —
{ "expression", "actions", "priority"?, "enabled"? }: any expression of the grammar and one to five ordered actions. - Convenience form —
{ "address", "url", "secret"?, "priority"?, "enabled"? }: the server buildsmatch_recipient("<address>")(a literal, case-insensitive match on that one address) with the actions[{"type":"store"},{"type":"forward","url":"<url>","secret":"<secret>"}]— the message is kept for the poll API and POSTed to your endpoint.
POST /v3/routes
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
expression | string | Optional | Full form. match_recipient("…"), match_header("name", "…") or catch_all() — up to 1 000 characters, patterns up to 256. |
actions | object[] | Optional | Full form. 1–5 of {"type":"store"}, {"type":"forward","url":"https://…","secret":"…"}, {"type":"stop"}, run in order. |
address | string | Optional | Convenience form. A single e-mail address to match literally. |
url | string (URL) | Optional | Convenience form. Public HTTPS URL that receives the signed POST. |
secret | string | Optional | Convenience form, optional. 8–128 characters; enables the Apifon-Signature HMAC-SHA256 header. Stored encrypted, never returned. |
priority | integer | Optional | Evaluation priority, 0–1 000 000 — lower runs first. Default 0. |
enabled | boolean | Optional | Disabled routes are never evaluated. Default true. |
Requires a full_access key. Changes apply to the next message received (routes are cached for up to 30 seconds on the receiver).
Responses
| Status | Description |
|---|---|
201 | Created. The route with its public actions (has_secret instead of the secret). |
400 | validation_error — body shape (both forms at once, neither form), or a forward url that is not a public HTTPS address. |
401 | Missing or invalid API key. |
403 | insufficient_scope — route writes need a full_access key. |
422 | invalid_expression — the grammar rejected the expression (position in message); invalid_actions — empty list, unknown type, forward without an https:// URL, more than five actions. |
Code examples
cURL
# Convenience form: store + forward everything sent to one address
curl -X POST https://api.wemail.io/v3/routes \
-H "Authorization: Bearer afn_live_…" \
-H "Content-Type: application/json" \
-d '{
"address": "kostas@leads.example.com",
"url": "https://app.example.com/inbound",
"secret": "whsec_replace_me_1234"
}'
# Full form: drop auto-replies before anything else
curl -X POST https://api.wemail.io/v3/routes \
-H "Authorization: Bearer afn_live_…" \
-H "Content-Type: application/json" \
-d '{
"expression": "match_header(\"auto-submitted\", \"auto-replied\")",
"actions": [{ "type": "stop" }],
"priority": 0
}'Node.js
const res = await fetch("https://api.wemail.io/v3/routes", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WEMAIL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
expression: 'match_recipient(".*@leads\\\\.example\\\\.com")',
actions: [
{ type: "store" },
{ type: "forward", url: "https://app.example.com/inbound", secret: "whsec_replace_me_1234" },
],
priority: 10,
}),
});
const route = await res.json(); // 201 — actions[1].has_secret === truePython
import os, requests
r = requests.post(
"https://api.wemail.io/v3/routes",
headers={"Authorization": f"Bearer {os.environ['WEMAIL_API_KEY']}"},
json={
"address": "kostas@leads.example.com",
"url": "https://app.example.com/inbound",
"secret": "whsec_replace_me_1234",
},
)
route = r.json() # 201 — match_recipient("kostas@leads.example.com") + [store, forward]Go
client, _ := wemail.NewClient(os.Getenv("WEMAIL_API_KEY"))
ctx := context.WithValue(context.Background(), wemail.ContextAccessToken, os.Getenv("WEMAIL_API_KEY"))
req := wemail.CreateInboundRouteRequest{}
req.SetAddress("kostas@leads.example.com")
req.SetUrl("https://app.example.com/inbound")
req.SetSecret("whsec_replace_me_1234")
route, _, err := client.API.RoutesAPI.CreateInboundRoute(ctx).CreateInboundRouteRequest(req).Execute()ResponseExample response
{
"id": "3d9a1f6e-2b7c-4c8d-9e0f-7a1b2c3d4e5f",
"account_id": "acc_01HBYD3M…",
"expression": "match_recipient(\"kostas@leads.example.com\")",
"actions": [
{ "type": "store" },
{ "type": "forward", "url": "https://app.example.com/inbound", "has_secret": true }
],
"priority": 0,
"enabled": true,
"created_at": "2026-11-03T07:59:30.000Z"
}