Skip to content
KismetKismetDevelopers
Beta accessllms.txt

Invite a guest to save a card

View .md

Preview access required. Card invitations are available only to explicitly enabled installations. Rehearse the complete flow in TEST before requesting LIVE access.

Use a card invitation to bring an existing verified guest back to their account on your website, open Kismet’s hosted card form, and receive a signed completion event. Saving a card does not make a payment, enroll a membership, or grant marketing consent. A saved card or completion event never authorizes a charge.

Use a server credential with guest_wallet_requests.write and guest_auth.write. Keep it in your server secret store. An authorized collection administrator or developer must register the exact callback URL as well as the partner origin. A registered origin alone does not authorize an authentication callback.

For events, separately grant events.read, webhooks.read, webhooks.write, and guest_wallet_requests.events.read. Add payment_methods.events.read only if you also need new-payment-method notifications. See event destinations and signature verification.

Kismet derives the collection, application, installation and TEST/LIVE environment from the credential. There are no request-body overrides. The recipient must be an existing, verified guest visible to the collection. TEST additionally requires an explicitly registered test identity and always uses Stripe TEST mode; no LIVE wallet row is written.

import { createKismetGuestAuthServerClient } from '@kismet-tech/sdk/server';
const guest = createKismetGuestAuthServerClient({
serverKey: process.env.KISMET_SERVER_KEY!,
baseUrl: 'https://api.ksmt.app/v1',
origin: 'https://stays.example',
});
const invitation = await guest.createWalletRequest({
guestProfileId: verifiedGuestProfileId,
returnUrl: 'https://stays.example/account',
delivery: 'kismet_email',
reference: 'account-card-123',
}, { idempotencyKey: 'account-card-123' });

The REST equivalent is POST /v1/developer/guest/wallet/requests with the same JSON body and an Idempotency-Key header. Repeating the same key and input returns the original request without sending another email. Reusing the key with different input fails.

kismet_email sends a one-use sign-in proof directly to the guest’s verified email. Your server receives status, never the proof or credential-bearing email URL. deliveryState: sent means accepted for delivery, not that the guest opened it. The proof expires after 15 minutes; the request expires after 24 hours.

Use delivery: 'partner_link' when your application will distribute the navigation link. Its startUrl carries a request ID only. Signed-out guests must independently authenticate. Do not describe that link as a magic login link.

getWalletRequest(id) reads status. revokeWalletRequest(id) stops unfinished requests. resendWalletRequest(id) sends a fresh Kismet email and invalidates the older proof and login grant. Resends are limited to five total sends, at least 60 seconds apart. An actual completed provider save remains recorded even if the request expired or was revoked afterward.

The Kismet invitation page verifies proof after an explicit user action and keeps its short-lived login grant in a Kismet-origin HttpOnly cookie. It sends the browser to the registered partner return page with kismet_wallet_request in the fragment. Clear that fragment before application analytics run and retain only the non-secret request context in your UI.

For a Kismet-delivered invitation, configure the existing SDK handlers:

import { createKismetGuestAuthNextHandlers } from '@kismet-tech/sdk/next';
const handlers = createKismetGuestAuthNextHandlers({
client: guest,
sessionSecret: process.env.GUEST_SESSION_SECRET!,
allowedOrigins: ['https://stays.example'],
walletReturnPath: '/account/card-return',
});
// Mount POST handlers behind your same-origin account API:
// handlers.walletAuthorizationStart: accepts { requestId }
// handlers.walletAuthorizationComplete: accepts { code, state }
// handlers.walletCapture: accepts { walletRequestId }

The browser auth client (createKismetGuestAuthBrowserClient) provides startWalletAuthorization(requestId) and completeWalletAuthorization({ code, state }), including CSRF handling. Mount its /wallet/start and /wallet/complete paths beneath the configured auth base path; use the existing SDK CSRF endpoint and proof header for direct POSTs. walletAuthorizationStart adopts the existing _kid_sid, creates state and S256 PKCE, and returns an authorizationUrl on kismet.travel. Navigate there. Kismet uses its private invitation cookie to return a single-use code to the exact registered walletReturnPath.

On the return page, read kismet_wallet_code and state from the fragment, clear the URL, and POST them as { code, state } to walletAuthorizationComplete. The SDK checks state, browser identity and expiration, redeems the code from the server, and stores the resulting guest session in an encrypted HttpOnly cookie. Session tokens never enter the browser response. The response includes requestId and returnUrl so the account UI can reopen the card panel.

With partner_link, use your existing Google/email guest login and preserve the request ID across that flow. A request ID cannot replace verification. If a different guest signs in, capture is denied without disclosing the invitation recipient.

Call guestBrowser.wallet.capture({ walletRequestId: invitation.id }) using createKismetGuestBrowserClient from @kismet-tech/sdk/react, or POST { walletRequestId: invitation.id } to handlers.walletCapture. The handler derives parentOrigin from its own request; the Developer API verifies the authenticated guest, request, installation, collection and environment before preparing capture. Mount the returned captureUrl with mountKismetGuestWalletCapture. Card fields, provider secrets and payment credentials stay in the Kismet-hosted frame.

The frame’s completion message is a prompt to refresh the account, not proof of a committed save. The authoritative guest.wallet_request.completed event is produced after the provider confirms success and Kismet commits the wallet/request and event together. Its data includes request_id, optional opaque reference, payment_method_id and outcome (added or already_present). A newly associated card can also produce payment_method.added.

Verify the signature over the exact raw body. Validate event version, type, installation, collection and environment. Persist the event ID atomically with your consumer action before returning 2xx. Retries and replay may deliver the same fact more than once. Events contain scoped guest references, not email addresses, global guest IDs, card numbers, provider IDs or authentication tokens.

Use an approved test identity and a hosted partner test page, receive the actual Kismet invitation, save a Stripe TEST card through the hosted form, and verify both the request status and signed delivery at your HTTPS receiver. Confirm a duplicate callback or replay performs one consumer action, and that the event cannot be read using another installation or LIVE credential.

Also test expired/revoked invitations, resend invalidation, callback changes, wrong-user login and a blocked receiver. Local provider simulations and loopback deliveries are useful integration tests; they do not establish hosted provider acceptance or LIVE readiness.