Tutorial Logged In Support - knowtific/helppuff GitHub Wiki
Tutorial: logged-in customer support
A software company's billing assistant, for customers signed in to the app. It knows who they are without asking, has their plan and invoices before the first answer, and sends refund requests to the billing team.
[Signed in as Ada · Pro plan]
Visitor Why was I charged twice this month?
Assistant I can see two charges of $49.00: invoice INV-2041 on 1 October (your Pro
renewal) and INV-2042 on 1 October too, which looks like a duplicate. Shall I
ask the billing team to refund INV-2042?
Visitor Yes please
Assistant Done: the request is R-3317. The billing team usually replies within two
business days, by email to [email protected].
What it teaches: signed-in visitors, tools that
use the verified {{user.id}}, and a request your team decides on rather
than an action the assistant takes.
Template: logged-in-support (import it).
You need: sign-in on your site, and two endpoints in your app (step 2).
How it works
Your page ─token─▶ chat starts ─▶ account (before, by {{user.id}}) ─▶ first answer knows the plan and invoices
request_refund (during) ─▶ your billing team's queue
Both tools use {{user.id}}, so they run only for a verified visitor.
Without a valid token, account is skipped, and the prompt tells the
assistant to ask the visitor to sign in, never to look someone up by an
email they typed.
1. Sign the visitor in
Follow Signed-in visitors: show the secret, sign
{ sub: user.id, email, name } on your server, and on every page of the app:
HelpPuff.identify({ name: user.name, email: user.email, token });
2. Your endpoints
GET /api/helppuff/accounts/:id returns what the assistant may tell the
customer about their own account:
{
"plan": "Pro",
"status": "active",
"renews_at": "2026-11-01",
"invoices": [
{ "id": "INV-2042", "date": "2026-10-01", "amount": "$49.00", "description": "Pro, monthly", "status": "paid" },
{ "id": "INV-2041", "date": "2026-10-01", "amount": "$49.00", "description": "Pro, monthly", "status": "paid" }
]
}
Send amounts already formatted, with the currency: the assistant repeats them as they are. Leave out what it must never say (card numbers, internal notes).
POST /api/helppuff/refund-requests with { user, invoice, reason, conversation }
puts a request in front of your billing team and answers
{ "requested": true, "reference": "R-3317" }. Check on your side that the
invoice belongs to user: the assistant is honest, but your API is the
guard.
3. The tools
helppuff tools add account --before \
--url 'https://app.example.com/api/helppuff/accounts/{{user.id}}' \
--header 'Authorization: Bearer ${APP_API_KEY}' \
--pick plan,status,renews_at,invoices \
--description 'The signed-in customer’s plan, status, renewal date and recent invoices.'
helppuff tools add request_refund --method POST \
--url https://app.example.com/api/helppuff/refund-requests \
--header 'Authorization: Bearer ${APP_API_KEY}' \
--body '{"user": "{{user.id}}", "invoice": "{{args.invoice_id}}", "reason": "{{args.reason}}", "conversation": "{{conversation.id}}"}' \
--param invoice_id='The id of the invoice to refund, from the account’s invoices.' \
--param reason='Why, in a few words (e.g. charged twice).' \
--description 'Ask the billing team to refund an invoice. Only after the customer agreed. Returns a reference.'
{{user.id}} is filled from the token, never from what the assistant or
the visitor says. The refund request includes {{conversation.id}} so your
team can open the chat from the request.
4. The prompt
## Billing and account questions
The visitor is signed in as {{user.name}}. Their plan: {{account.plan}} ({{account.status}}), renewing on {{account.renews_at}}. Their recent invoices: {{account.invoices}}
- Answer questions about their plan, invoices and renewal from the account above. Give amounts and dates exactly as shown.
- "I was charged twice", or a charge they don't recognise: find the invoices in question and say what each one was for. If two look like duplicates, say so and offer to ask the billing team for a refund. When they say yes, send it with {{request_refund}} and give them the reference.
- Never promise a refund: the billing team decides, usually within two business days.
- If their account is "(not known yet)", they are not signed in: ask them to sign in to their account on the website and open the chat again. Never ask for an account number or an email address to look them up.
- The account is in the prompt from the first answer: no "let me check" for the common questions.
- "Offer, then wait for yes" before
request_refund, and "never promise": the assistant asks; people decide. - The last line closes the gap a typed email would open.
Try it
From your own server, the API takes the user directly, which is the quickest test:
curl https://<your worker>/api/v1/conversations -H "Authorization: Bearer $HELPPUFF_KEY" \
-H 'Content-Type: application/json' \
-d '{"message": "Why was I charged twice?", "user": {"id": "u_8812", "name": "Ada", "email": "[email protected]"}}'
Then sign in on your app and open the chat. The conversation in the dashboard says Signed in as [email protected].
Next: Testing and monitoring, to keep a setup like this working as you change it.