View as markdown
Webhooks

Delivery channels

The same subscription can deliver to an HTTPS endpoint, a Discord channel, or stay in the dashboard. Pick a channel at subscribe time with channel.

The channels

One discriminator, set once when you subscribe.

  • webhook — POST a signed webhook.fired JSON payload to your target_url. The default when you pass a target_url.
  • discord — post a formatted embed to a Discord channel via an incoming-webhook URL. No HMAC — the URL is the credential.
  • in_app — record fires in the dashboard’s deliveries timeline only. No outbound request. The default when you pass neither a target_url nor a discord_url.
  • mobile_push — push a notification to a phone signed in to the Tickerbot mobile app. Requires a device_id from POST /v2/devices/register.
  • slackreserved. Subscribing with this channel returns 501 not_implemented today.

If you omit channel, it’s inferred: webhook when target_url is set, discord when discord_url is set, otherwise in_app. The channel is fixed once the subscription exists — to switch, delete and re-subscribe.

Discord

Post embeds to a channel with two extra fields.

In Discord, open Server Settings → Integrations → Webhooks → New Webhook, pick a channel, and Copy Webhook URL. Pass it as discord_url with channel: "discord" on any subscribe endpoint:

curl -X POST "https://api.tickerbot.io/v2/scan/subscribe" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "q": "above_sma_200 AND market_cap > 1e10",
    "channel": "discord",
    "discord_url": "https://discord.com/api/webhooks/123456789012345678/aBcDeF…",
    "cadence": "1m"
  }'

Each fire posts a single embed: the subscription name, the composed query, and up to the first dozen matching tickers with price and day change, plus a “+N more” line. Discord embed limits apply — long match sets are truncated, not split.

The Discord URL is a credential

Treated like signing_secret — returned once, then masked.

Anyone with the incoming-webhook URL can post to your channel, so we store it as a posting credential and strip it from every read. The create response echoes it back once; GET /v2/webhooks/{id} and list omit it and set channel_config_present: true so tooling can still tell a channel is configured. Delivery rows mask it the same way. To rotate it, delete and re-subscribe with the new URL.

Retries & failures

Discord deliveries ride the same retry ladder, with one twist.

A 2xx (Discord returns 204) is a success. A 429 is retried, honoring Discord’s Retry-After. Other 4xx responses (e.g. a deleted webhook → 404) are permanent_failure — no retry. 5xx and network errors retry on the standard ladder (30s → 2m → 10m → 1h → 6h), and five consecutive failures auto-disable the subscription, exactly like an HTTPS webhook.

Validate it

Test fire works on every wire channel.

POST /v2/webhooks/{id}/test posts a real-shape fire to the configured channel right now — for Discord, a real embed with a [TEST] title prefix — and returns the inline outcome. It’s one-shot: failures don’t retry or count toward auto-disable.