Skip to main content

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.

Authentication

Fanfare uses different authentication methods depending on the API and use case.

API Keys

Every organization has two types of API keys:

Publishable Key

  • Format: pk_live_xxxxxxxxxxxx or pk_test_xxxxxxxxxxxx
  • Usage: Client-side code (browsers, mobile apps)
  • Permissions: Read-only access to public resources, consumer session creation
  • Security: Safe to expose in client-side code
// Browser SDK initialization
import { Fanfare } from "@fanfare/sdk-react";

const fanfare = new Fanfare({
  publishableKey: "pk_live_xxxxxxxxxxxx",
});

Secret Key

  • Format: sk_live_xxxxxxxxxxxx or sk_test_xxxxxxxxxxxx
  • Usage: Server-side code only
  • Permissions: Full API access including write operations
  • Security: Must be kept confidential, never expose in client-side code
# Server-side API call
curl -X POST https://admin.fanfare.io/api/v1/experiences \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"name": "Holiday Sale"}'

Authentication Methods

Consumer API - Browser (Publishable Key)

For browser-based consumer interactions, use the publishable key in the X-Publishable-Key header:
GET /api/v1/experiences/exp_01HXYZ123456789 HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx

Consumer API - Authenticated Consumer

After a consumer authenticates (via OTP, external auth, etc.), use the access token:
POST /api/v1/queues/queue_01HXYZ123456789/enter HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx
Authorization: Bearer eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...

Consumer API - Server-Side (Secret Key)

For server-to-server calls to the Consumer API, use the secret key:
POST /api/v1/auth/external/authorize HTTP/1.1
Host: consumer.fanfare.io
Authorization: Bearer sk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "provider": "shopify",
  "issuer": "https://your-store.myshopify.com",
  "subject": "customer_123456"
}

Admin API (Secret Key Required)

All Admin API calls require the secret key:
POST /api/v1/experiences HTTP/1.1
Host: admin.fanfare.io
Authorization: Bearer sk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "name": "Holiday Sale Queue",
  "openAt": "2024-12-01T09:00:00Z"
}

Consumer Authentication Flows

Guest Session

Create an anonymous session for tracking purposes:
POST /api/v1/auth/guest HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx
Response:
{
  "session": {
    "type": "guest",
    "consumerId": "guest_01HXYZ123456789",
    "guestId": "guest_01HXYZ123456789",
    "expiresAt": "2024-12-01T10:00:00Z"
  },
  "accessToken": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
}

OTP Authentication (Email)

Request a one-time password:
POST /api/v1/auth/otp/request HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "email": "[email protected]"
}
Verify the OTP:
POST /api/v1/auth/otp/verify HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "email": "[email protected]",
  "code": "123456"
}

OTP Authentication (Phone)

Request an SMS code:
POST /api/v1/auth/otp/request HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "phone": "+12025551234",
  "defaultCountry": "US"
}
Verify the code:
POST /api/v1/auth/otp/verify HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "phone": "+12025551234",
  "code": "123456",
  "defaultCountry": "US"
}

External Authentication (Server-Side)

For integrating with your existing authentication system: Step 1: Create exchange code (server-side)
POST /api/v1/auth/external/authorize HTTP/1.1
Host: consumer.fanfare.io
Authorization: Bearer sk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "provider": "your-platform",
  "issuer": "https://your-domain.com",
  "subject": "user_123456",
  "claims": {
    "email": "[email protected]",
    "name": "John Doe"
  }
}
Response:
{
  "exchangeCode": "exc_01HXYZ123456789",
  "expiresAt": "2024-12-01T09:01:00Z"
}
Step 2: Exchange code for session (client-side)
POST /api/v1/auth/external/exchange HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "exchangeCode": "exc_01HXYZ123456789"
}

Token Refresh

Refresh an expired access token:
POST /api/v1/auth/refresh HTTP/1.1
Host: consumer.fanfare.io
X-Publishable-Key: pk_live_xxxxxxxxxxxx
Content-Type: application/json

{
  "refreshToken": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
}
Response:
{
  "accessToken": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
}

Logout

Invalidate the current session:
POST /api/v1/auth/logout HTTP/1.1
Host: consumer.fanfare.io
Authorization: Bearer eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...

Token Structure

Access tokens are JWTs containing:
{
  "consumerId": "cons_01HXYZ123456789",
  "organizationId": "org_01HXYZ123456789",
  "sessionId": "sess_01HXYZ123456789",
  "iat": 1701424800,
  "exp": 1701428400
}

Token Lifetimes

Token TypeDefault LifetimeConfigurable
Access Token1 hourYes
Refresh Token30 daysYes
Exchange Code60 secondsNo

Security Best Practices

  1. Never expose secret keys in client-side code, version control, or logs
  2. Rotate keys regularly using the Admin dashboard
  3. Use environment variables for storing keys in server-side applications
  4. Implement token refresh to maintain sessions without re-authentication
  5. Use HTTPS for all API communications (enforced by Fanfare)

Error Responses

Invalid Credentials

{
  "error": "Authentication required"
}

Expired Token

{
  "error": "otp_expired",
  "message": "Your verification code has expired. Please request a new one."
}

Invalid OTP

{
  "error": "otp_invalid",
  "message": "Invalid verification code. Please try again."
}

Secret Key Required

{
  "error": "Secret key required"
}