Skip to main content

Overview

The Resend integration enables Fanfare to send transactional emails to consumers. Resend provides reliable email delivery with detailed analytics and is used for all email communications including:
  • Appointment confirmations and reminders
  • Draw and auction outcome notifications
  • Queue admission alerts
  • Waitlist updates
  • OTP codes for authentication

Prerequisites

The Resend integration is pre-configured for the Fanfare platform at the infrastructure level. Individual organizations can customize their email sender settings.
Note: Fanfare uses a shared Resend account for email delivery. Organizations can customize the “From” name and reply-to address in their messaging settings.

Email Templates

Authentication Templates

TemplateDescription
OTP_LOGINOne-time password for passwordless login
PERSONAL_ACCESS_CODEUnique access codes for experiences

Appointment Templates

TemplateDescription
APPOINTMENT_CONFIRMATIONConfirms booking with all details
APPOINTMENT_REMINDERReminds of upcoming appointment
APPOINTMENT_CANCELLEDNotifies of cancellation
APPOINTMENT_RESCHEDULEDNotifies of date/time change

Experience Outcome Templates

TemplateDescription
AUCTION_WONNotifies winner with checkout link
AUCTION_LOSTNotifies non-winners
DRAW_WONNotifies draw winner with checkout link
DRAW_ENTEREDConfirms draw entry
DRAW_NOT_SELECTEDNotifies non-selection
QUEUE_ADMITTEDNotifies queue admission with checkout link

Waitlist Templates

TemplateDescription
WAITLIST_CONFIRMATIONConfirms waitlist signup
WAITLIST_NOTIFIEDNotifies of product/experience availability

Email Branding

Brand Customization

Each email includes organization branding:
ElementSource
Organization NameOrganization settings
Organization LogoBrand settings or header media asset
Primary ColorBrand theme settings
Support EmailMessaging settings

Email Sender Settings

Organizations can customize sender information in Settings > Organization:
FieldDescription
From EmailEmail address shown as sender
From NameDisplay name for sender
Reply-To EmailWhere replies are directed
Reply-To NameDisplay name for reply-to
Domain Verification: Custom “From” email addresses require domain verification. Contact support to configure a custom sending domain.

Message Delivery

How Emails Are Sent

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Fanfare   │────▶│    SNS      │────▶│    SQS      │────▶│   Lambda    │
│   Event     │     │   Topic     │     │   Queue     │     │  Processor  │
└─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘



                                                            ┌─────────────┐
                                                            │   Resend    │
                                                            │    API      │
                                                            └─────────────┘
  1. An event triggers an email (e.g., consumer wins draw)
  2. Email is queued via SNS/SQS
  3. Lambda processor renders template and sends via Resend
  4. Delivery status tracked via Svix webhooks

Delivery Status Events

Resend sends webhook events for email delivery:
Event TypeDescription
email.sentEmail accepted for delivery
email.deliveredEmail delivered to recipient server
email.bouncedEmail bounced (hard/soft)
email.complainedRecipient marked as spam
email.clickedLink in email clicked
email.openedEmail was opened
email.delivery_delayedDelivery is being retried

Delivery Event Mapping

Resend events are mapped to Fanfare’s delivery event types:
Resend EventFanfare Event
email.sentSENT
email.deliveredDELIVERED
email.bouncedBOUNCED
email.complainedCOMPLAINED
email.clickedCLICKED
email.openedOPENED
email.delivery_delayedDELIVERY_DELAYED

Webhook Events

Webhook Security

Resend uses Svix for webhook delivery, providing:
  • Cryptographic signature verification
  • Automatic retries on failure
  • Timestamp validation
// Svix webhook verification
const wh = new SvixWebhook(secret);
wh.verify(raw, {
  "svix-id": svixId,
  "svix-timestamp": svixTimestamp,
  "svix-signature": svixSignature,
});

Webhook Headers

HeaderDescription
svix-idUnique webhook event ID
svix-timestampUnix timestamp of event
svix-signatureHMAC signature for verification

Idempotency

Webhook events are processed idempotently:
  • Duplicate events (same svix-id) are ignored
  • Events are stored with provider event ID
  • Multiple status updates for same email are recorded

API Reference

Queue Email Message

Send a transactional email.
POST /api/messaging/send-sample
Content-Type: application/json

{
  "channel": "EMAIL",
  "template": "DRAW_WON",
  "toEmail": "[email protected]",
  "templateData": {
    "template": "DRAW_WON",
    "userName": "John Doe",
    "productName": "Limited Edition Sneakers",
    "productImage": "https://example.com/sneakers.jpg",
    "checkoutUrl": "https://fanfare.io/checkout/abc123",
    "expiresAt": "2024-06-25T23:59:59Z"
  }
}
Response:
{
  "status": "queued",
  "id": "msg_abc123"
}

Template Data Schemas

Each template requires specific data plus common branding fields: Common Branding Fields (auto-populated):
{
  "organizationName": "My Store",
  "organizationLogo": "https://example.com/logo.png",
  "supportEmail": "[email protected]",
  "theme": {
    "primaryColor": "#3B82F6"
  }
}
DRAW_WON:
{
  "template": "DRAW_WON",
  "userName": "John Doe",
  "productName": "Limited Edition Sneakers",
  "productImage": "https://example.com/product.jpg",
  "checkoutUrl": "https://fanfare.io/checkout/abc123",
  "expiresAt": "2024-06-25T23:59:59Z"
}
APPOINTMENT_CONFIRMATION:
{
  "template": "APPOINTMENT_CONFIRMATION",
  "userName": "Jane Smith",
  "productName": "Exclusive Preview",
  "productImage": "https://example.com/preview.jpg",
  "appointmentDate": "2024-06-25T14:00:00Z",
  "timeZone": "America/New_York",
  "location": "Fifth Avenue Store"
}
OTP_LOGIN:
{
  "template": "OTP_LOGIN",
  "userName": "Customer",
  "otpCode": "123456"
}

Rate Limiting

API Rate Limits

The messaging endpoint is rate-limited:
LimitWindowScope
10 requests60 secondsPer user per organization

Resend Rate Limits

Resend has the following limits:
  • 100 emails/second for verified domains
  • 3,000 emails/day on free tier
  • Higher limits available on paid plans

Testing

Sending Test Emails

Use the messaging endpoint to send test emails:
POST /api/messaging/send-sample
Content-Type: application/json

{
  "channel": "EMAIL",
  "template": "QUEUE_ADMITTED",
  "toEmail": "[email protected]"
}
If templateData is omitted, sample data is generated using:
  • Organization branding from settings
  • Placeholder product/user information
  • Mock URLs and dates

Test Metadata

Test messages include metadata:
  • isTest: true
  • requestedBy: <userId>
  • ts: <timestamp>

Email Rendering

Template Architecture

Emails are rendered using React Email components:
  1. Template data is validated against schema
  2. Brand data is fetched from organization settings
  3. React components render HTML
  4. Rendered HTML is sent via Resend

Caching

Brand data is cached for performance:
  • Organization branding data
  • Experience-specific branding overrides
  • Cache invalidated on settings update
// Invalidate cache when branding changes
invalidateExperienceBrandingCache(organizationId, experienceId);

Troubleshooting

Common Issues

Email not delivered
  • Verify email address is valid
  • Check spam/junk folders
  • Review Resend delivery logs
Webhook not received
  • Verify Svix signature headers present
  • Check webhook secret configuration
  • Review Resend webhook logs
Missing organization branding
  • Ensure organization settings are configured
  • Upload organization logo
  • Set support email in messaging settings
Template rendering error
  • Verify all required fields are provided
  • Check field types match schema
  • Review Lambda processor logs

Checking Delivery Status

Query transactional messages:
SELECT
  id,
  status,
  provider_message_id,
  template_name,
  created_at,
  sent_at
FROM transactional_messages
WHERE organization_id = 'org_123'
  AND channel_type = 'EMAIL'
ORDER BY created_at DESC;

Delivery Event Logs

View detailed delivery events:
SELECT
  event_type,
  event_time,
  recipient_identifier,
  raw_webhook_data
FROM message_delivery_events
WHERE transactional_message_id = 'msg_123'
ORDER BY event_time;

Security

Email Content

  • Links use HTTPS
  • Checkout links include secure tokens
  • OTP codes expire after short window

Data Privacy

  • Email addresses encrypted at rest
  • Webhook payloads contain minimal PII
  • Logs redact sensitive information

Webhook Authentication

  • All webhooks verified via Svix signature
  • Invalid signatures rejected with 401
  • Events deduplicated by provider ID

Limitations

LimitationDescription
HTML onlyPlain text fallback not included
Single recipientBatch sending not supported
English templatesTemplates are in English only
Domain verificationCustom domains require setup