Leads and callbacks
A lead is a person who left their details. HelpPuff turns conversations into leads in three ways, keeps them in the dashboard, and can send them anywhere else.
Where leads come from
- The lead form before the chat (on by default): name, email, an optional phone, and their question, which becomes their first message. Add your own fields (suburb, company, budget…) in Settings → Lead form, and mark which are required. Every answer is kept on the lead and given to the assistant, so it knows who it is talking to and never asks again.
- Typed in the chat: an email address or phone number a visitor writes.
- The assistant: when a visitor asks for a person, a quote or a booking, or it cannot help, it offers a callback. It reuses the details it already has and shows a short form only for what is missing (a phone or an email). The lead is marked as a callback request.
A dashboard summary of a conversation can also add contact details, but only ones that literally appear in the transcript; a model cannot invent a lead.
One lead per person
Leads are keyed by email (in any case). A visitor who comes back, or gives their email in a second chat, gets the new chat added to the lead they already have; new details only fill gaps, never overwrite. A lead with only a phone number is merged into the person as soon as their email turns up.
Contact tags, attributes and notes
Give a contact several tags to describe the person or your relationship with them, such as VIP, Wholesale or Repeat customer. Create, rename, recolour and delete tags in Settings → Contact tags. Add or remove them on the Contacts list or a contact's page, and filter Contacts by a tag or by Untagged. Tags on contacts are separate from the labels on individual conversations. The old contact status is no longer edited in the dashboard; jobs track the progress of requests and work. Existing non-default contact statuses become tags named Previously marked … so their meaning is not lost. The old API status field remains available for integrations. Moving a job to Won no longer changes a contact's old status field.
Over the API, PATCH /leads/:id accepts tags as the complete list of tag ids; an empty list removes them all. A contact can have up to 20 tags.
Besides what the forms and chats collect, each contact has a company and an address, and custom attributes: any key-value pairs you want, like plan: pro or customerId: 4021 (up to 50; keys up to 64 letters, digits, spaces, _ - .). Edit them on the contact's page, or over the API:
Settings → Custom fields lists the attribute keys already used on contacts and lets an admin add, rename or remove them. Contact tags are for categories; attributes hold values such as a customer ID.
curl -X PATCH "$BASE/leads/$ID" -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"company":"Acme","attributes":{"plan":"pro","trial":null}}'null removes an attribute; keys you leave out stay. The team's notes (POST /leads/:id/notes) are dated and signed; GET /leads/:id returns them as teamNotes, with every conversation and callback. Conversations have attributes and notes of their own too (PATCH /conversations/:id).
In the dashboard
Contacts lists people by when their record was updated, with:
- Tags: several per person, editable inline and filterable.
- Notes, and their form answers. Open a contact for their page: details, attributes, the team's notes, every chat and their history.
- Chats: how many, with a link to the latest transcript.
- Export CSV for a spreadsheet or CRM, including tags. The old status column remains for existing imports. Cells that start with
=,+,-or@are escaped, so a lead cannot plant a formula in your spreadsheet.
Callbacks
A visitor asking to be called back is a task, not just a lead. Each request becomes a callback (the assistant requested it with the details it had, or the visitor sent the callback form) with how to reach them, why, and the conversation it came from.
- Callbacks in the dashboard lists the waiting ones, oldest first, with the count on the menu. Done (with a note of what happened, e.g. "Booked a measure for Tuesday") or Dismiss closes one; Reopen brings it back.
- The contact (Leads) and the conversation (Conversations, and its Callback waiting filter) are labelled Callback requested while one waits.
- A conversation has at most one waiting request: asking again updates it. A request after one was closed is a new task. A person can have several over time, from different chats.
- Webhooks:
callback.requestedwhen one is made,callback.updatedwhen it is closed, reopened or its note changes. - In the terminal:
helppuff callbackslists them;helppuff callbacks done <id> --note "…"closes one.
Sending leads elsewhere
Webhooks (Settings → Webhooks): every event as signed JSON, including
lead.captured,callback.requestedandlead.updated. The way to connect Zapier, Make, n8n, a CRM or Slack.leads.webhookinhelppuff.json: a simpler, older option that POSTs each lead to one URL:json"leads": { "webhook": "https://hooks.zapier.com/hooks/catch/123/abc" }
Because one person can produce several lead.captured events (the form, then a phone number typed later), update the contact by email in your CRM rather than always creating a new one.
The form, in helppuff.json
"widget": {
"leadForm": {
"enabled": true,
"title": "Before we start",
"fields": [
{ "name": "name", "label": "Name", "type": "text", "required": true },
{ "name": "email", "label": "Email", "type": "email", "required": true },
{ "name": "phone", "label": "Phone (optional)", "type": "tel" },
{ "name": "service", "label": "What do you need?", "type": "select", "options": ["Hot water", "Drains", "Other"] },
{ "name": "message", "label": "How can we help?", "type": "textarea", "required": true }
],
"privacy": { "text": "We only use this to reply to you.", "url": "https://acme.com.au/privacy" }
}
}name, email, phone and message mean something to the assistant (a message field opens the chat); any other field is kept as is. Set "enabled": false to let visitors chat straight away; the assistant then asks for details only when arranging a callback.
Privacy
Leads and transcripts are stored in the D1 database on your Cloudflare account, nowhere else. HelpPuff stores no IP addresses (only the country), and its logs never contain message text or contact details. To delete everything: helppuff destroy --yes.