Confirm email subscriptions
Request email subscription confirmation, wait for recipient consent, and add confirmed contacts to a contact group.
Use double opt-in to add someone to a contact group only after they confirm their email address. Your server requests a confirmation email; the recipient follows its link and chooses Confirm subscription. Opening the link alone does not subscribe them.
Request confirmation
Create a contact group for your audience and use a sender on your verified sending domain. Keep your Samva API key on your server. Apply your own form abuse controls before calling Samva.
import { createClient } from "samva";
const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });
const result = await samva.subscriptions.subscribe({
email: "ada@example.com",
contactGroupId: "cgrp_1234567890abcdef",
from: { email: "newsletter@your-domain.com", name: "Your newsletter" },
consentSource: "newsletter-signup",
});
console.log(result.success, result.expiresAt);curl -X POST https://api.samva.dev/v1/subscriptions \
-H "x-api-key: $SAMVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"ada@example.com","contactGroupId":"cgrp_1234567890abcdef","from":{"email":"newsletter@your-domain.com","name":"Your newsletter"},"consentSource":"newsletter-signup"}'A successful response accepts the confirmation request. It does not establish consent or guarantee
delivery. The response contains success: true and expiresAt; it never returns the confirmation
link. Message content and previews show a placeholder; only the recipient's email contains the
working confirmation link. See Request subscription confirmation for
request fields and errors.
consentSource records where signup happened. If you supply consentIp, derive it on your server
from the incoming request and your trusted proxy configuration. Both fields are caller-supplied
context, not proof Samva independently verified. Do not accept arbitrary browser values as trusted
consent evidence.
Wait for recipient confirmation
The confirmation link expires after seven days and can be used once. The email links to Samva's hosted confirmation page. Treat that link as private: do not put it in analytics, logs, support tickets, or shared previews. The recipient must choose Confirm subscription to complete the request.
Successful confirmation adds the contact to the requested active, static contact group and emits
contact.subscribed. Use that event to start
welcome flows. Each successfully confirmed fresh link emits an event, including when the contact
already belongs to the group. Creating a request alone does not add membership or clear an opt-out.
If you set unsubscribeGroupId, successful confirmation clears that address's opt-out for that
unsubscribe group. It does not change other unsubscribe groups or remove delivery suppressions.
A contact group selects an audience; an unsubscribe group records which mail a recipient declines.
Keep both models when sending campaigns.
Handle failures and retries
An invalid, expired, or already-used link cannot confirm a subscription. Ask the recipient to request another email when their link expires. Each accepted request creates a fresh link; retrying the signup request can send another confirmation email, so do not automatically repeat it after an uncertain response. Apply a resend delay in your own form.
If the same confirmation email is delivered again, either delivered link can confirm the request. Confirming one makes all links for that request unusable.
Requesting confirmation can create an active contact for delivery, without subscribing it to the contact group. New contacts count toward your plan's active-contact limit. If that limit is full, the signup request returns HTTP 402 without sending a confirmation email.
If a contact is deleted before confirmation, confirming the link checks capacity before recreating it. A full list leaves the link unused and makes no membership, opt-out, or webhook changes. The hosted page asks the recipient to notify the sender and retry the same link before it expires. Existing contacts can confirm without an additional capacity check.
If confirmation fails temporarily, the recipient can retry the same link. Membership changes and confirmation complete together; a failed confirmation does not establish consent. Handle duplicate webhook deliveries using the webhook delivery contract.
Customize the email
The confirmation email uses the brand and footer configured for your sender and sends from the
from address you supplied. Set templateSlug to use a published template that accepts
confirmUrl as input. The rendered HTML must contain at least one link using the complete,
unchanged value as an <a href>:
<a href={confirmUrl}>Confirm subscription</a>HTML-only templates are supported. If the template includes a text part, it must also include
the complete confirmUrl. Put the complete URL on its own line or separate it from surrounding text with
whitespace. A parenthesized URL, as in Confirm (URL), is also supported. Do not append parameters
or wrap it in another URL. Do not use confirmUrl in images,
srcset, styles, other attributes, the subject, or HTML body text. Samva rejects the subscription
request with a validation error naming the template if either required link is missing or the
template uses confirmUrl in any of those places.
Keep the request's purpose clear in the subject and body so recipients know which subscription they are confirming.
A custom template's unsubscribe-group setting does not block the confirmation email. This lets a recipient confirm a request to rejoin a group they previously opted out of. Delivery suppressions still apply.
CLI and MCP
Request confirmation from your terminal:
samva subscriptions subscribe \
--email ada@example.com \
--contact-group-id cgrp_1234567890abcdef \
--from newsletter@your-domain.com \
--from-name "Your newsletter" \
--consent-source newsletter-signup \
--jsonAn authenticated MCP agent can request the same email with contacts_subscribe. Both surfaces
start the request; the recipient completes confirmation on the hosted page.