HunchwireDocs hunchwire.com Sign in

Guides

People

Everyone who signed up: where they came from, what they answered, and the emails you send them.

View as Markdown

Use your agent. Paste this into it:

Read hunchwire.com/docs/people and tell me who signed up this week.
On this page People Email

People

A person is anyone who signed up to a project. List them, save views of them, export them, and change their place or state.

GET /projects/:id/people Needs emails

List everyone who submitted a form, one row per person, newest first.

Show 9 details
  • Takes filters and days, like Analytics. Without days, it lists the last 30 days. days=all lists everyone.
  • A person is listed when they submitted in the period. With filters, only submissions from the browsers the filters pick count.
  • page=2 returns the second 50. The founder's screen shows 50 a page. Without page, you get everyone.
  • ?q=ada keeps only emails containing ada. A number matches however it's typed: ?q=416 555 finds +14165550123.
  • It lists everyone except removed people, like the founder's All view. To narrow it like their segment switch, send one of these:
    • state=waiting, state=invited or state=removed.
    • segment=top_referrers: people who brought at least one friend, most friends first.
    • segment=<id>: a saved segment (see Segments). It applies its conditions when you send none of your own.
  • ids[]= lists only those people.
  • filter[answer][]=<question key>:<answer> (such as q_0qjfp5jp:Notion) picks people by what they answered after signing up. exclude[answer][]= leaves them out. It works on Analytics too, where it picks visitors from the browsers they signed up in. GET /projects/:id/follow_up lists the question keys.
  • Returns one row per person:
    • id: their first submission ever. It's the same in every period. Use it to open their profile.
    • email: the address they first signed up with, exactly. phone: their mobile number, for someone who signed up by number. The other is null.
    • forms: the forms they submitted.
    • signed_up_at: the time of their first submission in the period. signed_up_on: its page. page_url: its full URL.
    • state: waiting, invited or removed. invited means an invite exists for the exact email they signed up with. removed means the founder or an agent took them off the list. Removed people keep their data and still count in Analytics.
    • removed_at: when they were removed, or null.
    • language: their browser's language when they signed up, such as en or fr-CA.
    • city: where they signed up, from Cloudflare. language and city are null when not known. Hunchwire never keeps the IP.
    • channel, source and campaign: where they first came from. campaign is the campaign link, or null when untagged.
    • visitor_ids: the browsers they signed up from. Open one with GET /projects/:id/analytics/visitors/:visitor_id to see what they read and clicked before signing up.
    • clicked: the tracked clicks from their browser, in order. Use it before an interview, to see which plan they wanted.
    • place: their place in the beta list. 1 is first. It's null once they're removed, and everyone behind them moves up.
    • moved: places they were moved by hand. Positive is up. Most people have 0.
    • friends: how many friends count for them: people who joined through their link, or were let in by it while waiting, once both have confirmed.
    • referred_by: the email or number of whoever brought them, or null.
    • unlocked: true once they've brought enough friends to get access. It applies only when sharers get access.
    • answers: what they answered after signing up (see Questions after sign-up). Each has key, question (its wording when they answered), answer and answered_at. It's empty when they answered nothing.
    • invite: their newest invite into the founder's product (see Let people in), or null.
    • confirmed_at: when they confirmed their email, or null. It's the earliest across their submissions.
    • consent_text, consent_version and consent_sender: proof of consent (CASL). They hold the exact wording shown, its version, and who it named. They come from whichever of the person's submissions showed a consent line, and are null when none did.
    • first_name: the first name a sign-up sent, or null.
    • list: the list they joined, or null.
    • via: how they first signed up: embed (the form) or api.
    • joined_product_at: when the founder's product reported they joined it (see API), or null.
  • A person is an email with any +tag dropped, and for Gmail, its dots too. So ada+1@gmail.com shares a place with ada@gmail.com.
GET /projects/:id/people
curl https://app.hunchwire.com/projects/:id/people \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

Segments

A segment is a saved People view, such as "Said Notion" or "From Reddit". The founder or you can pick the same people again to export, invite or email them. A segment saves who, never when: it keeps no period.

GET /projects/:id/segments Needs analytics

List every saved segment, by name.

Details
  • Each has id, name, query, created_at and updated_at.
  • query: its conditions, from state, segment, q, filter and exclude.
GET /projects/:id/segments
curl https://app.hunchwire.com/projects/:id/segments \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

POST /projects/:id/segments Needs manage

Save a segment.

Details
  • A name is 1 to 40 characters, and unique in the project.
  • Returns 422 for a blank or used name, a query with no condition, an unknown state or filter, or an email address or phone number anywhere in it.
POST /projects/:id/segments
curl -X POST https://app.hunchwire.com/projects/:id/segments \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Said Notion", "query": {"filter": {"answer": ["q_0qjfp5jp:Notion"]}}}'

PATCH /projects/:id/segments/:segment_id Needs manage

with name, query or both: rename a segment, or save new conditions into it.

PATCH /projects/:id/segments/:segment_id
curl -X PATCH https://app.hunchwire.com/projects/:id/segments/:segment_id \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

DELETE /projects/:id/segments/:segment_id Needs manage

Delete a segment. The people in it stay.

DELETE /projects/:id/segments/:segment_id
curl -X DELETE https://app.hunchwire.com/projects/:id/segments/:segment_id \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

GET /projects/:id/people.csv Needs emails

Export the same list as a CSV file.

Details
  • It has the same columns, except id. It adds invited_at, clicked_at and wave: their newest invite, and the wave it came in. ad_platform and ad name the ad they first came through, or are blank. phone and first_name follow email; a person by number has a blank email. It adds one column per question asked now, headed with its wording.
  • Takes everything the list does: ?q=, days, filters, state, segment and ids[]. It's never paged.
  • Export works on every plan.
GET /projects/:id/people.csv
curl https://app.hunchwire.com/projects/:id/people.csv \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

GET /projects/:id/people/:person_id Needs emails

Get one person's profile.

Show 8 details
  • Any of their submission ids works. Returns 404 for anyone not in the project.
  • Returns everything in their row, their newest invite, and history, newest first.
  • Each history entry has at, kind, text and by.
  • awaiting_confirmation: true when they signed up again after being deleted and haven't confirmed. Until they do, only the confirmation is emailed.
  • rejoining: true when they were removed, signed up again by email, and haven't clicked the confirmation yet. Clicking it puts them back on the list.
  • kind: joined, invited, clicked (the invite), joined_product (the founder's product reported they joined), friend (a friend who counts joined through their link, or their link let someone waiting in), removed, restored, rejoined (they signed up again and confirmed, so they're back), moved, reward_given, referral_approved or referral_rejected.
  • text: the entry as the founder's screen says it. When a friend's link let someone in, their invited entry names whose link it was: "Let in through ana@example.com's link". Older ones read "Let in through a friend's link".
  • by: who made the change. It's an agent's name, a founder's email, or null for what happened on its own. "you" never appears here.
GET /projects/:id/people/:person_id
curl https://app.hunchwire.com/projects/:id/people/:person_id \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

PATCH /projects/:id/people Needs manage and emails

Remove many people at once, or send "waiting" to restore them. Only do this when the founder asks.

Details
  • Instead of ids, pick a whole view by its conditions: segment, q, filter, exclude and in. in is the state the view lists, since state is the one to set. Add days (30 by default), or all=1 for everyone in the period.
  • Returns state and changed, how many people changed.
  • Returns 422 when you pick no one.
PATCH /projects/:id/people
curl -X PATCH https://app.hunchwire.com/projects/:id/people \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state": "removed", "ids": [12, 15]}'

PATCH /projects/:id/people/:person_id Needs manage and emails

Move someone in line, here to place 5. Only do this when the founder asks.

Details
  • Hunchwire stores how many places that is (moved). Later friends and sign-ups can still shift them a place or two.
  • Their History shows each move. It never changes anyone's friends.
  • Returns 422 for a place outside 1 to the number of people in line, or for someone removed.
PATCH /projects/:id/people/:person_id
curl -X PATCH https://app.hunchwire.com/projects/:id/people/:person_id \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"place": 5}'

PATCH /projects/:id/people/:person_id Needs manage and emails

or {"state": "waiting"}: remove someone from the list, or restore them. Only do this when the founder asks.

Details
  • Removed people keep their data and leave the line (place is null). Waves don't invite them. They come back if they sign up again and confirm (see Confirm sign-ups).
  • Returns the profile row. Returns 422 for any other state.
PATCH /projects/:id/people/:person_id
curl -X PATCH https://app.hunchwire.com/projects/:id/people/:person_id \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state": "removed"}'

Each read of emails shows on the founder's Agents page, once an hour per screen and project. That covers People, its CSV, Blocked, and Analytics' top_referrers.

POST /projects/:id/purge_requests Needs manage and emails

in the body, or {"phone": "+14165550123"} for someone who signed up by number: delete that person from the project. Only do this when the founder or the owner asks.

Show 7 details
  • It also deletes the same person's other spellings: +tags, Gmail dots and googlemail.com.
  • It deletes their submissions, blocked sign-ups and invites, and the visits and clicks from their browser. Visits and clicks from a browser that someone else still uses to sign up stay.
  • This can't be undone. A person who unsubscribes from an email is deleted the same way.
  • A record of the request stays, as a keyed hash, never the email or number. The studio never emails that address again, unless it signs up to this project again and confirms through the link Hunchwire emails.
  • Returns 201 with {"status": "completed", "purged": {"submissions": 2, "visits": 5, "clicks": 1, "blocked_signups": 0, "answers": 1, "invites": 0, "people": 0, "reward_marks": 0, "referral_reviews": 0, "webhook_deliveries": 0}}.
  • status: completed, not_found or failed.
  • purged: how many rows were removed of each kind: submissions, visits, clicks, blocked_signups, answers, invites, people (a removal or move recorded for them), reward_marks (rewards marked given), referral_reviews (decisions on flagged referrals) and webhook_deliveries (webhook events about them).
POST /projects/:id/purge_requests
curl -X POST https://app.hunchwire.com/projects/:id/purge_requests \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "…"}'
Status Body Meaning
201 "status": "completed" The person was deleted.
404 "status": "not_found" No one in the project has that email. Hunchwire still records the request.
500 "status": "failed" The purge failed and nothing was removed. Try again.

GET /projects/:id/blocked?days=30 Needs emails

List the sign-ups Hunchwire refused, newest first. They never count as people.

Details
  • days is 7, 14 or 30 (the default). Hunchwire keeps them 30 days.
  • Each has email or phone (the other is null), form, reason, page_url and created_at.
  • reason: bot (filled the hidden field), disposable (a throwaway email domain) or no_mail (the domain can't receive mail).
  • For disposable and no_mail, the visitor saw an error, so they could fix a typo. Bots saw the usual success.
GET /projects/:id/blocked
curl https://app.hunchwire.com/projects/:id/blocked?days=30 \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

Email

Hunchwire emails a project's people only from the founder's own verified domain, never from Hunchwire's. Hunchwire's own project sends from hunchwire.com.

Each email names who's asking (sender) and the founder's mailing address, and has a one-click unsubscribe, as Canada's anti-spam law requires. Unsubscribing deletes that person from the project. Hunchwire never again emails anyone who asked to be deleted, unsubscribed, bounced or complained.

A deleted or unsubscribed person can sign up to the same project again. They get the confirmation email and nothing else. Clicking its link confirms it's them, and then that project emails them as normal. Other projects still never email them.

Every send returns sent and skipped. They are counts, with skipped broken down by reason (plan, suppressed, unconfirmed, phone for numbers…). They never include addresses. unconfirmed counts people who signed up again after being deleted and haven't confirmed yet.

Set up email

  1. Add the domain and its email records (see Your domain).
  2. Call PATCH /projects/:id with mail_from and mailing_address.
    • mail_from: an address at that domain, like hello@tryloop.app. Email comes from it, and replies go to it.
    • mailing_address: one line. A PO box or virtual mailbox is fine.
  3. Read email.blocker in GET /projects/:id/domain. It names the first thing missing, in the order below. Tell the founder the next step.
email.blocker What's missing
off Hunchwire hasn't turned on email yet.
plan A paid plan.
inactive The account needs a plan again.
no_domain A domain.
unverified Verified records: some are still waiting.
paused Sending is paused.
no_mail_from mail_from.
no_sender Who's asking, or the mailing address.

Send by hand

A founder can skip email setup and send invite links themselves. Hunchwire then stops asking them to set up email, and its screens lead with copying links and exporting addresses.

PATCH /projects/:id Needs manage

Send by hand.

Show 5 details
  • Send false to have Hunchwire ask about email setup again.
  • Adding a domain turns it off.
  • Invites and waves still make every link. Give the founder each url, or the wave's CSV.
  • To write to people, give the founder the addresses from GET /projects/:id/people/emails.csv.
  • Sign-ups aren't confirmed by email.
PATCH /projects/:id
curl -X PATCH https://app.hunchwire.com/projects/:id \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"project": {"email_by_hand": true}}'

Confirm sign-ups

Once a project can email its people (email.ready), each new sign-up gets a confirmation link from the founder's domain, once per person. The wording is fixed: "Confirm you want to hear about …". The form's confirmation then tells them to check their inbox instead of naming the address.

Clicking the link on the project's host (/confirm/<token>, good for 30 days) confirms them. On the free month, sign-ups are collected, not confirmed.

A number never gets a confirmation. Your product confirms it by sending confirmed (see Sign people up and look them up).

Someone already on the list who signs up again through a friend's link gets one more confirmation, even if they confirmed before. Clicking it can let them in (see Let friends straight in). It goes at most once every 10 minutes per person.

A removed person who signs up again comes back once they prove the contact. An email gets one more confirmation link, even if they confirmed before. Clicking it puts them back on the list, as Restore does. A number comes back on a sign-up with confirmed. Until then, and while the project can't email its people, they stay removed.

POST /projects/:id/confirmations Needs manage and emails

Send the confirmation to everyone who missed it.

Details
  • It goes once to each person who signed up in the last 30 days and never got one: before the domain was verified, or on the free month.
  • Removed people are left out.
  • Only do this when the founder asks.
  • Returns sent and skipped.
POST /projects/:id/confirmations
curl -X POST https://app.hunchwire.com/projects/:id/confirmations \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

Email people

People › Emails writes to everyone in a segment, a People view, or people picked by id. An email reaches Waiting and Invited people only, never removed ones. Hunchwire works out who when it sends.

Emails are plain text, with links made clickable. Hunchwire adds the footer and unsubscribe link. Write the email with the founder, and send it only when they say so.

GET /projects/:id/people/emails Needs analytics

List sent and held emails, newest first.

Show 10 details
  • id, subject and body.
  • to: who it was for: segment, query with days, or ids.
  • to_label: who it was for, as the screen says it.
  • state: sent, or held until it can send. A held email waits for the plan to allow email, then for the domain to be verified and email to be set up.
  • sent: how many people it went to.
  • skipped: counts by reason.
  • delivered, and bounced (bounced or complained).
  • sent_at, created_at and by.
  • It never says who got the email. It has no clicks or opens, because Hunchwire doesn't track them.
  • For a founder who sends by hand, add .csv and pick people as in POST below. It returns email and state for each person an email would reach, never a number. It needs emails.
GET /projects/:id/people/emails
curl https://app.hunchwire.com/projects/:id/people/emails \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN"

POST /projects/:id/people/emails Needs manage and emails

Send an email.

Show 6 details
  • segment is a saved segment, or top_referrers. Instead of segment, pick a view with in (waiting or invited), q, filter, exclude and days, or pick people with ids (person ids). days is all time unless you set it.
  • The subject is 1 to 150 characters. The body is 1 to 10,000.
  • Returns the email, as above, with 201.
  • On a plan without email, Hunchwire answers 402 plan_required (see Plans and gates). The email is held. It sends by itself once the founder upgrades and email is set up (see Set up email), within a few minutes of the domain being verified.
  • Any other blocker (see email.blocker) answers 422 with its reason. So does picking no one.
  • Add "test": true to send one copy to the founder instead. A test is free on every plan, but it still needs the domain. It returns {"test": "sent", "to": "…"} and isn't saved. Send a test first, and ask the founder to check it.
POST /projects/:id/people/emails
curl -X POST https://app.hunchwire.com/projects/:id/people/emails \
  -H "Authorization: Bearer $HUNCHWIRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"subject": "Can we talk for 15 minutes?", "body": "Hi,\n\n…", "segment": <id>}'

/unsubscribe/<token> and /confirm/<token> on the project's own host are for the people who get the email, not for agents.

Made from skill.md, the file agents read. Add .md to any page's address for its Markdown.