Skip to content
Launching soon. These docs describe TellsU as it will be at launch.

Webhooks

On the paid plan, TellsU can post each piece of feedback to a webhook as it arrives: for Zapier, Make, n8n or your own systems. Add one in your app’s Forwarding tab. Send a test from there to see a delivery with made-up content.

POST https://your-receiver.example/tellsu
Content-Type: application/json
User-Agent: TellsU-Webhooks/1
webhook-id: msg_2KWPBgLlAfxdpx2AI54pPJ85f4W
webhook-timestamp: 1800000000
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
{
"type": "submission.created",
"version": 1,
"app": { "id": "6f1c2d0e-…", "name": "Tab Shelf", "platform": "extension" },
"submission": {
"id": "0b6c9a7e-…",
"created_at": "2026-11-02T10:00:00Z",
"source": "widget",
"feedback_type": "bug",
"sentiment": "sad",
"message": "Tabs vanish after a restart.",
"reply_email": null,
"app_version": "2.4.1",
"screen": "popup",
"env": { "app_version": "2.4.1", "browser": "Chrome 130", "os": "macOS 15", "channel": "beta" },
"custom": { "sync": "on" },
"answers": [
{ "question": "Which features?", "type": "multiple_choice", "answer": ["Groups", "Sync"] },
{ "question": "Can we contact you?", "type": "yes_no", "answer": "no" }
],
"widget_version": "0.1.0"
}
}
Field What it is
type Always submission.created for now
version The payload’s version, 1
app.id, submission.id The same IDs as in your dashboard and CSV export
app.platform extension, wordpress or custom; accept values you don’t know, as more may come
source widget or link
feedback_type bug, idea, question or praise
sentiment happy, neutral, sad, or null when your user didn’t choose one (never neutral)
reply_email The address your user typed, or null
env The environment, by name; always an object, possibly empty
custom Your own environment values; always an object, possibly empty
answers Your own questions, in order, with their wording when the feedback arrived. type is short_text, long_text, choice, multiple_choice or yes_no; answer is a string, a list for multiple choice, "yes" or "no", or null when skipped
widget_version The widget’s version, or null for a link
test true on a test from the dashboard; absent on real deliveries

Every value from your user is a plain string, exactly as received. Escape it wherever you show it.

Fields may be added to version 1. Renaming, removing or changing a field would come as version: 2, sent only if you opt in.

Deliveries are signed as Standard Webhooks, so you can use its libraries for most languages. Your secret, starting whsec_, is in the Forwarding tab, where you can rotate it.

import { Webhook } from 'standardwebhooks';
const wh = new Webhook(process.env.TELLSU_WEBHOOK_SECRET);
const payload = wh.verify(rawBody, headers); // throws if it doesn't match

To check it yourself, webhook-signature is v1, followed by the base64 HMAC-SHA256 of <webhook-id>.<webhook-timestamp>.<raw body>, keyed with the base64-decoded part of the secret after whsec_. Compare in constant time, and reject timestamps more than five minutes old.

  • Respond with any 2xx within 10 seconds.
  • Anything else is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours, then given up. The Forwarding tab shows the latest result.
  • webhook-id stays the same on every retry, so you can skip repeats.
  • Only https, to public addresses. Redirects aren’t followed.
  • If you move to the free plan, your webhook is kept but nothing is sent until you upgrade again.