Skip to content
KismetKismetDevelopers
Beta accessllms.txt

TEST offer emails

View .md

A TEST welcome offer can award a configured perk and send one real email with [STAGING] at the start of its normal subject. This is an early-access operation: use a matching API deployment and immutable SDK release that includes these helpers. Source tests alone do not establish deployed availability or inbox delivery.

The collection must have a canonical welcome perk with authored email copy and an immediate lead.captured → DIRECT_ISSUE award rule. DRAFT perks can be rehearsed in TEST without enabling a production offer. The award-email renderer consumes an already-issued code, its expiry, approved redemption URL and terms. It does not invent a booking, join a membership, or issue another code while rendering.

With Kismet-tracked offer links enabled by your API deployment, the email’s Use your offer button goes through an HTTPS Kismet redirect. Your application continues to use server.offers.capture; it does not construct tracking links, send coupons to a tracking vendor, or record clicks itself. No additional SDK method or permission is needed.

In the offer’s private email configuration, set redemptionUrl to the approved destination for that environment. If the destination accepts a coupon in its query string, set redemptionCodeParameter to that parameter’s name—for example, coupon. Kismet inserts the actual issued code with URL-safe encoding and replaces any existing value for that parameter. Leave it unset for destinations where guests enter their code manually. Other query parameters remain intact.

Use a TEST provider destination for TEST offers, not a production checkout or a sample coupon. A provider page that drops the coupon during navigation still needs to be corrected by that provider; a redirect cannot preserve parameters across subsequent provider navigation.

Tracked links expire at the earlier of the code’s expiry and 24 hours in TEST or 30 days in LIVE. For other application or email links, see Track link engagement. Invalid or expired links do not redirect. A temporary verification failure asks the guest to retry. Link visits do not sign in a guest or change consent. Repeated visits count once per offer email, and security scanners may count as visits: a click is not proof of a human visit, booking, payment, or redemption.

This behavior applies to newly sent offer emails. Authentication and unsubscribe links retain their separate behavior. Already-sent provider tracking links are not rewritten retroactively.

The installation needs offers.read and offers.write, a TEST server key, the exact registered collection-owned STAGING origin, and registered TEST recipients. Publishable browser keys and LIVE credentials cannot call these operations. Keep the server key in the server environment; the browser uses your same-origin BFF. Never add a provider key to application code or use a private capture API.

import { createKismetClient } from '@kismet-tech/sdk/server';
import { createKismetGuestAuthNextHandlers } from '@kismet-tech/sdk/next';
const server = createKismetClient({
apiKey: process.env.KISMET_SERVER_KEY,
collection: 'your-collection',
baseUrl: 'https://api.ksmt.app/v1',
});
const offerId = process.env.KISMET_OFFER_ID!; // configured canonical perk UUID
const handlers = createKismetGuestAuthNextHandlers({
...yourExistingGuestHandlerConfig,
offers: { client: server.offers, offerIds: [offerId] },
});

Map GET /api/kismet/guest/offers/[offerId] to handlers.offer(request, offerId) and POST /api/kismet/guest/offers/[offerId]/captures to handlers.captureOffer(request, offerId). The existing auth CSRF route remains required. The handlers enforce configured offer IDs and exact site origins, validate CSRF on POST, and derive origin from the authorized request URL. Caller-supplied origin, environment, code and extra fields are rejected.

For direct server integrations, use server.offers.get(offerId, { origin }) and server.offers.capture(offerId, { ...input, origin }). Both operations send the exact Origin header; capture also sends the matching body origin.

import { createKismetGuestBrowserClient } from '@kismet-tech/sdk/react';
const guest = createKismetGuestBrowserClient();
const offer = await guest.offers.get(offerId);
// Render offer.headline, offer.promise, offer.terms and offer.disclosure.text.
// Only the explicit submit handler below may capture the offer.
const result = await guest.offers.capture(offerId, {
email,
idempotencyKey: stableSubmissionKey,
consent: { accepted: true, disclosureHash: offer.disclosure.hash },
});

Typing an email or signing in with Google does not submit the offer. The canonical TEST disclosure explains that this sends one real staging email without LIVE marketing enrollment or membership. Render that exact disclosure and send its hash only after the guest chooses the submit action. A changed disclosure must be displayed again before a fresh explicit submission.

Keep the same 16–200 character alphanumeric, hyphen or underscore idempotency key and identical payload for retries, including after a timeout. Do not generate a new key just because the response is uncertain. The API also deduplicates by recipient, offer and installation, so changing keys cannot produce another send.

email.status: 'accepted' means the provider accepted the email. It does not prove inbox delivery or redemption. not_sent, pending, unknown and failed are separate outcomes; never present them as sent. Preserve the submission key when checking again. The response includes replayed and the durable captureId.

The API records the canonical award event and capture/send state. Engagement clicks and Google login are not award, delivery, redemption or marketing-consent proof. Do not infer dashboard fulfillment counts from those events.

See read the offer and capture the offer for the REST contract.