# TheyAsked > TheyAsked (https://theyasked.me) is a hosted feedback board for software products: your end users post feature requests, vote and follow a roadmap and changelog, inside your web app (a widget), your mobile app (a WebView embed) or on a public portal. Your product team sees who asked, which group (company, family, team, class…) they belong to and what it is worth. This file tells an AI coding assistant how to integrate it correctly. Served at https://theyasked.me/llms.txt. Every guide concatenated: https://theyasked.me/llms-full.txt ## Integration decision tree 1. Web app (React, Vue, Rails, Django, plain HTML…): use the **web widget** (one script tag). Identify signed-in users with an SSO token from your backend: `TheyAsked('identify', { token })`. 2. Native or cross-platform mobile app (iOS, Android, React Native, Flutter): open the **embed URL in a WebView**: `https://theyasked.me/embed/?platform=ios|android&hideHeader=1&token=`. - Present it as a **modal sheet** (bottom sheet / full-screen modal with a close button), not a pushed screen: two back arrows (yours and the board's) confuse users. - With `hideHeader=1` your app draws the title bar; the board shows its own "← All requests" link on request pages. - Back handling: listen for the `theyasked:navigate` bridge event; while `canGoBack` is true, send the embed back (`window.TheyAskedEmbed.back()`) instead of closing; when it is false (or on `theyasked:close`), dismiss the sheet. - Refresh an expired token by injecting `window.TheyAskedEmbed.identify(newToken)` on `theyasked:token_expired`. 3. A link in an email or menu: the public portal `https://theyasked.me/?token=` (the token is stripped from the URL after sign-in). 4. Backend sync, CRM / support-tool integrations, reporting: the **REST API** `https://theyasked.me/api/public/v1` with an API key (`Authorization: Bearer ta_live_…`, created in Settings → API). OpenAPI: https://theyasked.me/api/public/v1/openapi.json 5. React to events (new request, status change, shipped): **webhooks** (HMAC-SHA256 signed), Settings → Webhooks. 6. Let an AI agent read and act on feedback: the **MCP server** at `https://theyasked.me/mcp` (OAuth or API key). ## Always send the user's group as `company` Every end user usually belongs to a group: the account, team, family, class or store that shares a subscription. Send it in the token as `company` (alias: `group`, same shape; if both are present `company` wins). TheyAsked then counts a request once per group, rolls revenue up once per group (never double-counted across members) and lets the product team segment by group. "company" is the field name for every model, B2B or B2C; the workspace owner picks the word the dashboard shows (Settings → General → Customers). | Business model | What to send as `company` | Typical `attributes.role` | | --- | --- | --- | | B2B SaaS | the customer account / organization / workspace | admin, member, viewer | | Agency / consultancy tools | the client | manager, contributor | | Marketplaces, e-commerce platforms | the store / seller / merchant | owner, staff | | Education | the school, or the class | teacher, student, parent | | Healthcare | the clinic / practice | practitioner, admin | | Consumer subscriptions (family plans) | the family / household | parent, kid, adult | | Communities, games | the club / team / clan / guild | captain, member | | Individuals only (no shared account) | omit `company` | (optional) | Group shape: `company: { id, name, plan?, mrr?, currency?, employeeCount?, attributes? }`. `id` is your stable id for the group (string or number). `attributes` is a flat map (≤ 50 keys) of strings, numbers, booleans: e.g. `members`, `kids`, `seats`, `industry`, `renewalDate` (ISO date), `health` (good / at_risk / poor or a 0–100 score), `status` (`churned` tracks lost revenue). Revenue rules: - Shared subscription (one bill for the group): put it on the group, `company.mrr`. It counts once per group, however many members vote. - Individual subscription (a person with no group pays for themselves): put `mrr` on the user and omit `company`. - Inside a group, only `company.mrr` counts: a member's personal `mrr` is ignored for revenue. If members of one group pay separately, send the group's total as `company.mrr`. - `mrr` is whole currency units per month (49 means $49/month). `plan` is a label ("Pro", "Family", "Enterprise"). Roles: send `attributes.role` on the user (parent / kid, admin / member, teacher / student). The product team can then filter insights by role ("what do parents want vs kids"). ## Token signing rules - Sign **on your server only**, with the workspace SSO secret from Settings → Single sign-on. Read it from an environment variable (`THEYASKED_SSO_SECRET`); never hard-code it, never ship it to a browser bundle or a mobile binary, never log it. - Algorithm: **HS256** JWT (`{"alg":"HS256","typ":"JWT"}`). Any JWT library works. - Claims: `id` (your stable user id, string) and/or `email` (at least one), `name`, `avatarURL` (https), `company` (or `group`), `plan`, `mrr`, `attributes`, `platform` (`web` | `ios` | `android`), `appVersion`, `locale`, `country` (ISO-3166 alpha-2), `iat`, `exp`. - Set `exp` to about an hour and mint a fresh token per page load or app session. Tokens whose `iat` is older than 24 h (workspace setting) are rejected. - Pass the token to the widget (`TheyAsked('identify', { token })`), the embed URL (`?token=`) or `POST https://theyasked.me/api/v1/w//identify` with `{ "token" }`. - Test a token without side effects in Settings → Single sign-on → "Test a token". Example payloads (add `iat` = now and `exp` = now + 3600 when you sign each with HS256): B2B SaaS: {"id":"u_981","email":"lina@bloom.co","name":"Lina","company":{"id":"acct_42","name":"Bloom Beauty","plan":"Enterprise","mrr":4200,"employeeCount":120,"attributes":{"seats":40,"industry":"retail","renewalDate":"2027-03-01","health":"good"}},"attributes":{"role":"admin"}} Family app (one shared family subscription): {"id":"u_55","name":"Maya","company":{"id":"fam_9","name":"The Rivera family","plan":"Family","mrr":12,"attributes":{"members":4,"kids":2}},"attributes":{"role":"kid","ageBand":"9-12"}} Individual consumer app (no group, personal subscription): {"id":"u_77","email":"sam@example.com","name":"Sam","plan":"Premium","mrr":9,"attributes":{"role":"subscriber"}} ## Vote lists (curated "vote or request" widgets) A Vote list is a short list of options from one board, each with a logo tile, a name, a one-line summary and a Vote button, plus an inline "Request another…" field (e.g. "Vote or request an integration"). The workspace owner builds it in Settings → Vote lists and gives it a key (`integrations`). Put it where the question comes up: - Web, button: `TheyAsked('open', { list: 'integrations' })` opens it in the widget panel (after the usual `TheyAsked('init', { workspace })` and `identify`). - Web, inline: `
` (auto-mounted, sized to its content, also when rendered after init). - Mobile: the embed URL with `list=`: `https://theyasked.me/embed/?list=integrations&platform=ios|android&hideHeader=1&token=`, presented as a modal sheet; `back` on a list emits `theyasked:close`. - Headless (your own UI, the widget's identity): after the `theyasked:loaded` window event, `await TheyAsked.list('integrations')` → `{ list, items: [{ id, title, summary, icon, iconUrl, viewerVoted, voteCount?, status? }] }`, `TheyAsked.vote(id)`, `TheyAsked.unvote(id)`, `TheyAsked.request('integrations', 'Salla')` → `{ post }` (created) or `{ matched }` (already requested: the user's vote went there). Errors carry `status` and `code` (`unauthorized` = sign-in needed). - Events: `TheyAsked('on', 'voted', fn)` (`listKey` included) and `TheyAsked('on', 'requested', fn)` (`{ listKey, postId, title, matched, pending }`); bridge events `theyasked:voted` / `theyasked:requested` in WebViews. - Logos: each request's icon is set by the product team (a website domain like `shopify.com`, an emoji or an uploaded image) in the dashboard or over MCP (`update_post` with `icon` and `summary`). Don't hot-link logos yourself; use `iconUrl` from the headless API. - Everything a list records is an ordinary vote / request with the source `vote_list`, attributed to the identified user and their group. ## Common mistakes - Signing the token in the browser or the app (the secret leaks; anyone can impersonate anyone). Sign on your backend and return the token from an authenticated endpoint. - Missing `company`: every family member, teammate or student then looks like an unrelated individual, demand is over-counted and revenue cannot be rolled up. Send the group for every user who has one. - Putting the group's shared subscription on every user (`mrr` per member): revenue is multiplied by the member count. Use `company.mrr`. - A changing or display-name group `id`: use your database id, not the name. - Sending children's emails or other personal data you don't need. For kids, send only your user id, a first name or nickname and `attributes.role: "kid"`; omit `email`, `avatarURL`, birth dates and precise ages (use a band like "9-12" if you need one). - PII in `attributes` (phone numbers, addresses, health or payment data): attributes are shown to the product team; keep them to segmentation facts. - Long-lived tokens minted at build or deploy time (rejected as `too_old`), or tokens in URLs that get logged (prefer the widget's `identify` call; the portal strips `?token=`). - A pushed navigation screen with `hideHeader=1` and no back handling in mobile apps (see the decision tree). - Calling the widget's `identify` before the user is known, or not calling `TheyAsked('logout')` on sign-out. ## Docs - [SSO: identify your users, B2B and B2C grouping, signing snippets](https://theyasked.me/docs/sso) - [Web widget](https://theyasked.me/docs/widget) - [Mobile apps: iOS, Android, React Native, Flutter](https://theyasked.me/docs/mobile) - [REST API (OpenAPI 3.1)](https://theyasked.me/api/public/v1/openapi.json) - [Claude & MCP](https://theyasked.me/docs/mcp) - [Vote lists: "vote or request an integration" widgets](https://theyasked.me/docs/vote-lists) - [Theming](https://theyasked.me/docs/theming) - [Quickstart](https://theyasked.me/docs/quickstart) ## Optional - [Full integration docs in one file](https://theyasked.me/llms-full.txt)