Documentation Index
Fetch the complete documentation index at: https://docs.fanfare.io/llms.txt
Use this file to discover all available pages before exploring further.
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
| Template | Description |
|---|
OTP_LOGIN | One-time password for passwordless login |
PERSONAL_ACCESS_CODE | Unique access codes for experiences |
Appointment Templates
| Template | Description |
|---|
APPOINTMENT_CONFIRMATION | Confirms booking with all details |
APPOINTMENT_REMINDER | Reminds of upcoming appointment |
APPOINTMENT_CANCELLED | Notifies of cancellation |
APPOINTMENT_RESCHEDULED | Notifies of date/time change |
Experience Outcome Templates
| Template | Description |
|---|
AUCTION_WON | Notifies winner with checkout link |
AUCTION_LOST | Notifies non-winners |
DRAW_WON | Notifies draw winner with checkout link |
DRAW_ENTERED | Confirms draw entry |
DRAW_NOT_SELECTED | Notifies non-selection |
QUEUE_ADMITTED | Notifies queue admission with checkout link |
Waitlist Templates
| Template | Description |
|---|
WAITLIST_CONFIRMATION | Confirms waitlist signup |
WAITLIST_NOTIFIED | Notifies of product/experience availability |
Email Branding
Brand Customization
Each email includes organization branding:
| Element | Source |
|---|
| Organization Name | Organization settings |
| Organization Logo | Brand settings or header media asset |
| Primary Color | Brand theme settings |
| Support Email | Messaging settings |
Email Sender Settings
Organizations can customize sender information in Settings > Organization:
| Field | Description |
|---|
| From Email | Email address shown as sender |
| From Name | Display name for sender |
| Reply-To Email | Where replies are directed |
| Reply-To Name | Display 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 │
└─────────────┘
- An event triggers an email (e.g., consumer wins draw)
- Email is queued via SNS/SQS
- Lambda processor renders template and sends via Resend
- Delivery status tracked via Svix webhooks
Delivery Status Events
Resend sends webhook events for email delivery:
| Event Type | Description |
|---|
email.sent | Email accepted for delivery |
email.delivered | Email delivered to recipient server |
email.bounced | Email bounced (hard/soft) |
email.complained | Recipient marked as spam |
email.clicked | Link in email clicked |
email.opened | Email was opened |
email.delivery_delayed | Delivery is being retried |
Delivery Event Mapping
Resend events are mapped to Fanfare’s delivery event types:
| Resend Event | Fanfare Event |
|---|
email.sent | SENT |
email.delivered | DELIVERED |
email.bounced | BOUNCED |
email.complained | COMPLAINED |
email.clicked | CLICKED |
email.opened | OPENED |
email.delivery_delayed | DELIVERY_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,
});
| Header | Description |
|---|
svix-id | Unique webhook event ID |
svix-timestamp | Unix timestamp of event |
svix-signature | HMAC 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:
| Limit | Window | Scope |
|---|
| 10 requests | 60 seconds | Per 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 messages include metadata:
isTest: true
requestedBy: <userId>
ts: <timestamp>
Email Rendering
Template Architecture
Emails are rendered using React Email components:
- Template data is validated against schema
- Brand data is fetched from organization settings
- React components render HTML
- 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
| Limitation | Description |
|---|
| HTML only | Plain text fallback not included |
| Single recipient | Batch sending not supported |
| English templates | Templates are in English only |
| Domain verification | Custom domains require setup |