Sending Projects & Tracking Submissions
Once a project is built and active and at least one integration is connected, you can send its fill link to people and watch every request move from pending to submitted.
What a "send" is
A send creates one request with a single-use fill link, then delivers that link over one or more channels (email, WhatsApp, SMS) to one or more recipients. Everyone reached by the same request shares the same link — the first person to submit completes the request and dead-ends the link for the others. Send separate requests when each person should answer individually.
Sends happen through the Secure Link Loop API (POST /api/external/loop/send-secure-link), authenticated with an API key. To hand a link over yourself, use Create fill link on the Responses page: it mints a new single-use request (no message goes out) and copies its link. Each such link serves one person; create another for the next. Its response is tracked like any other, with channel link and no recipient attached.
Message templates
Templates exist at two levels:
Account defaults — one per channel, edited in Settings → Templates. Every channel ships with a system default message; replace it with your own wording once and every project inherits it.
Project templates — each channel in the project's Templates tab picks one of three sources: Account default (inherit, the default), System default (always send the stock message, even if an account default is set), or Custom (a message just for this project).
Per channel the message carries:
Email — subject + body.
WhatsApp — body only.
Text (SMS) — body only.
Templates support placeholders, replaced at send time:
| Placeholder | Replaced with |
|---|---|
{project} | The project's name |
{link} | The fill link — always include this one |
{name} | Your (the sender's) name |
{company} | Your brand name (falls back to your name) |
{anything_else} | A custom variable supplied in the send request (max 20 per send) |
Built-in placeholders always win over custom variables with the same name. Unknown placeholders are left as-is.
When a send doesn't specify a template, the message resolves in this order: the project's template (a custom message overrides everything; a pinned system default sends the stock message), then the account default from Settings → Templates, then the stock message — a full greeting that opens with Dear {username}, (supply username in the send request's variables; unfilled placeholders go out as-is), names your {company} and {project}, and closes with the {link} and your signature.
Improve — rewrites the template body with better tone/structure (uses the AI backend, like the project builder).
Test send — delivers the current draft to a test recipient through your real integration, so you can check formatting on an actual phone/inbox. You can save test values for your custom placeholders alongside the template.
Request lifecycle
| Status | Meaning |
|---|---|
pending | The link was sent (at least one channel delivered) and nobody has submitted yet |
submitted | Someone opened the link and submitted — the data is stored |
failed | Every delivery attempt failed; the link is dead |
expired | The link's expiry window passed with no submission |
Notes on the mechanics:
Expiry is set per project (Link expiry; empty = never, which is the default). It's evaluated when the link is opened or when statuses are read, counting from the most recent send.
Resend — from the Responses page (or via a new send) you can resend a pending request's link; this restarts the expiry window. Every delivery is appended to the request's send history.
Channel — a fill link is plain
/fill/<id>; a submission records the channel the request was delivered on (orlinkfor a link created on the Responses page). Links sent before 2026-09-09 carried a channel suffix and keep working.
The Responses page
The project's Responses page lists every request and submission (newest first, up to 200 rows), with status badges, channel, recipient, and timestamps. Click a row to see:
Submitted data — every field value the recipient entered.
Delivery history — each send: channel, recipient, the rendered subject/body, and when it went out.
Analytics — captured server-side and from the fill page: IP address, timezone, screen size, and time-to-submit.
Pending rows show their live fill link so you can copy or resend it.
WhatsApp conversations land here too: a question asked through the WhatsApp Reply Loop API or the Playground's WhatsApp mode opens a row the moment its first question goes out (channel whatsapp; its id is the submission_id the API returns), and every later question of the conversation and every answer is captured under that same row — the Data column shows how many are answered so far, the Details panel the whole conversation, question by question with its reply. The row is submitted once the last answer is in, failed when a question could not be delivered, and expired once the reply window of the question it is waiting on has passed. Such a row is never a fill link and cannot be resent. The Billing page's Credits used table links each WhatsApp charge to its row here.
Reacting to submissions
Two push/pull options, usable together:
Webhook — set the account webhook (Settings → Webhooks) and every submission across your projects is POSTed to it as it happens, answers and analytics included.
Status polling —
GET /api/external/loop/{request_id}returns the request's status and, once submitted, the response data with its capture analytics.