Tixdorm API

Power your events with Tixdorm's backend. List events, sell tickets, manage attendees, and accept payments — all through a simple REST API.

Overview

The Tixdorm Partner API lets you build ticketing, registration, and check-in flows directly into your own website or application. You handle the frontend and customer experience; Tixdorm handles the backend — events database, ticket inventory, hosted checkout, QR code generation, email delivery, and real-time attendance tracking.

Common use cases:

  • A media site publishing events and selling tickets inline
  • A booking platform offering event registration as a service
  • A community hub managing member events and check-in
  • A festival organizer running multiple events with a unified backend

Multi-tenant by design. Each integration gets its own organization, API keys, webhooks, and data isolation. Your data stays yours.

Base URL

https://api.tixdorm.com/v1

All requests go through api.tixdorm.com. Every response includes CORS headers, so you can call the API directly from the browser.

Authentication

Every request requires a secret API key sent in the Authorization header using the Bearer scheme:

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key types

Each key pair has two components:

  • Public Key (pk_live_xxx) — Identifies your organization. Can be safely exposed.
  • Secret Key (sk_live_xxx) — Authenticates all API requests. Keep this server-side.

Environments

  • sandbox
    Keys with _test_ — use for development. No real payments.
  • production
    Keys with _live_ — use for live traffic. Real payments processed.

Security best practices

  • Store secret keys in environment variables, never in code or client-side JS
  • Rotate keys periodically from the dashboard
  • If a key is compromised, revoke it immediately and generate a new one
  • Full keys are shown only once at generation time

API Endpoints

Events

GET/v1/events

List all published events.

Response

{
  "ok": true,
  "data": [
    {
      "id": "uuid",
      "title": "Tolu W. Art Exhibition",
      "slug": "tolu-w-art-exhibition",
      "description": "An evening of contemporary art...",
      "location": "Lagos, Nigeria",
      "starts_at": "2026-07-01T18:00:00Z",
      "ends_at": "2026-07-01T22:00:00Z",
      "status": "published",
      "capacity": 500,
      "event_type": "in_person",
      "cover_image_url": "https://...",
      "is_paid": true,
      "price_cents": 5000,
      "currency": "NGN",
      "created_at": "2026-06-01T10:00:00Z",
      "updated_at": "2026-06-15T12:00:00Z"
    }
  ]
}
GET/v1/events/{event_id}

Get a single event by ID, including its ticket tiers.

Response

{
  "ok": true,
  "data": {
    "id": "uuid",
    "title": "Tolu W. Art Exhibition",
    "ticket_tiers": [
      {
        "id": "uuid",
        "name": "VIP",
        "price_cents": 15000,
        "quantity": 50,
        "sold_count": 12,
        "is_active": true
      }
    ]
  }
}
POST/v1/events

Create a new event under your organization.

Request body

{
  "title": "My Event",
  "description": "Event details...",
  "venue": "Lagos, Nigeria",
  "start_date": "2026-07-01T10:00:00Z",
  "end_date": "2026-07-01T18:00:00Z",
  "capacity": 500,
  "event_type": "in_person"
}

Response

{
  "ok": true,
  "data": { "id": "uuid", "title": "My Event", ... }
}
PATCH/v1/events/{event_id}

Update one or more fields on an event you own.

Request body

{
  "title": "Updated Title",
  "venue": "New Venue, Abuja",
  "capacity": 1000,
  "event_type": "hybrid"
}

Response

{
  "ok": true,
  "data": { "id": "uuid", "title": "Updated Title", ... }
}

Tickets

GET/v1/events/{event_id}/tickets

List all ticket tiers for an event.

Response

{
  "ok": true,
  "data": [
    {
      "id": "uuid",
      "name": "General Admission",
      "description": "Standard entry",
      "price_cents": 5000,
      "quantity": 200,
      "sold_count": 45,
      "is_active": true,
      "sales_start": "2026-06-01T00:00:00Z",
      "sales_end": "2026-07-01T00:00:00Z"
    }
  ]
}
POST/v1/tickets

Create a new ticket tier for an event you own. If `price` > 0, online payments are automatically enabled for the event.

Request body

{
  "event_id": "evt_uuid",
  "name": "VIP Pass",
  "description": "Includes meet-and-greet",
  "price": 15000,
  "quantity": 100,
  "sales_start": "2026-06-01T00:00:00Z",
  "sales_end": "2026-07-01T00:00:00Z",
  "visibility": "public"
}

Response

{
  "ok": true,
  "data": { "id": "uuid", "name": "VIP Pass", ... }
}

Checkout

POST/v1/checkout

Create a checkout. For paid tiers returns a Flutterwave payment URL; for free tiers returns the ticket token directly.

Request body

{
  "event_id": "evt_uuid",
  "ticket_id": "tier_uuid",
  "quantity": 2,
  "customer_name": "John Doe",
  "customer_email": "john@example.com",
  "customer_phone": "+2348012345678"
}

Response

{
  "ok": true,
  "data": {
    "checkout_url": "https://api.flutterwave.com/...",
    "tx_ref": "tix_abc_..."
  }
}
POST/v1/verify-payment

Verify a Flutterwave payment and retrieve the ticket token after a successful checkout.

Request body

{
  "tx_ref": "tix_abc_...",
  "transaction_id": "1234567"
}

Response

{
  "ok": true,
  "data": {
    "confirmed": true,
    "ticket_token": "qr_token_here"
  }
}

Attendees

GET/v1/events/{event_id}/attendees

List all ticket purchasers for an event you own.

Response

{
  "ok": true,
  "data": [
    {
      "id": "uuid",
      "buyer_name": "John Doe",
      "buyer_email": "john@example.com",
      "buyer_phone": "+2348012345678",
      "tier_id": "uuid",
      "amount_paid_cents": 5000,
      "status": "valid",
      "purchased_at": "2026-06-20T14:30:00Z",
      "validated_at": null,
      "ticket_tiers": { "name": "General Admission" }
    }
  ]
}
POST/v1/attendees

Manually register an attendee (comp tickets, guest list).

Request body

{
  "event_id": "evt_uuid",
  "ticket_id": "tier_uuid",
  "name": "Jane Doe",
  "email": "jane@example.com",
  "phone": "+2348012345678"
}

Response

{
  "ok": true,
  "data": {
    "id": "uuid",
    "event_id": "evt_uuid",
    "buyer_name": "Jane Doe",
    "buyer_email": "jane@example.com",
    "status": "valid"
  }
}

Check-In

POST/v1/checkin

Validate a ticket and mark the attendee as checked in.

Request body

{
  "ticket_id": "tkt_uuid"
}

Response

{
  "ok": true,
  "data": {
    "status": "checked_in",
    "timestamp": "2026-06-23T12:00:00Z",
    "ticket_id": "tkt_uuid"
  }
}

QR Codes

GET/v1/tickets/{ticket_id}/qr

Retrieve QR code URL and ticket portal link for a ticket.

Response

{
  "ok": true,
  "data": {
    "qr_url": "https://supabase.co/functions/v1/scan-validate?token=abc...",
    "ticket_url": "https://tixdorm.com/t/abc...",
    "ticket_id": "tkt_uuid",
    "event_id": "evt_uuid"
  }
}

Broadcast

POST/v1/events/{event_id}/broadcast

Send an email update to all verified attendees of an event.

Request body

{
  "subject": "Venue Update",
  "message": "The venue has changed to Harbour Point. See you there!"
}

Response

{
  "ok": true,
  "data": {
    "sent": 45,
    "failed": 0,
    "total": 45
  }
}

Merch — Products

GET/v1/events/{event_id}/products

List all merch products for an event you own.

Response

{
  "ok": true,
  "data": [
    {
      "id": "uuid",
      "name": "Festival T-Shirt",
      "slug": "festival-t-shirt",
      "description": "Premium cotton tee",
      "category": "apparel",
      "cover_image_url": "https://...",
      "price_cents": 5000,
      "compare_at_price_cents": 7000,
      "status": "active",
      "inventory_quantity": 100,
      "track_inventory": true,
      "has_variants": true,
      "units_sold": 23,
      "created_at": "2026-06-01T10:00:00Z"
    }
  ]
}
POST/v1/events/{event_id}/products

Create a new merch product for an event you own.

Request body

{
  "name": "Festival T-Shirt",
  "description": "Premium cotton tee",
  "category": "apparel",
  "price_cents": 5000,
  "compare_at_price_cents": 7000,
  "status": "active",
  "inventory_quantity": 100,
  "track_inventory": true,
  "has_variants": false
}

Response

{
  "ok": true,
  "data": { "id": "uuid", "name": "Festival T-Shirt", ... }
}
GET/v1/products/{product_id}

Get a single product by ID, including variants and images.

Response

{
  "ok": true,
  "data": {
    "id": "uuid",
    "name": "Festival T-Shirt",
    "variants": [
      { "id": "uuid", "name": "Size", "value": "XL", "price_override_cents": null, "inventory_override": null }
    ],
    "images": [
      { "id": "uuid", "url": "https://...", "alt_text": "Front view", "position": 0 }
    ]
  }
}
PATCH/v1/products/{product_id}

Update one or more fields on a product you own.

Request body

{
  "name": "Updated T-Shirt",
  "price_cents": 6000,
  "status": "active"
}

Response

{
  "ok": true,
  "data": { "id": "uuid", "name": "Updated T-Shirt", ... }
}

Merch — Orders

GET/v1/events/{event_id}/orders

List all merch orders for an event you own.

Response

{
  "ok": true,
  "data": [
    {
      "id": "uuid",
      "customer_name": "John Doe",
      "customer_email": "john@example.com",
      "customer_phone": "+2348012345678",
      "subtotal_cents": 10000,
      "delivery_fee_cents": 1500,
      "total_cents": 11500,
      "currency": "NGN",
      "payment_status": "paid",
      "fulfilment_status": "unfulfilled",
      "flw_tx_ref": "tix_xxx",
      "created_at": "2026-06-20T14:30:00Z"
    }
  ]
}
GET/v1/orders/{order_id}

Get a single merch order by ID, including items.

Response

{
  "ok": true,
  "data": {
    "id": "uuid",
    "customer_name": "John Doe",
    "total_cents": 11500,
    "payment_status": "paid",
    "fulfilment_status": "unfulfilled",
    "items": [
      {
        "id": "uuid",
        "product_name": "Festival T-Shirt",
        "variant_name": "Size",
        "variant_value": "XL",
        "quantity": 2,
        "unit_price_cents": 5000,
        "total_price_cents": 10000,
        "fulfilment_method": "delivery"
      }
    ]
  }
}

Applications

GET/v1/events/{event_id}/applications

List all application configs for an event (volunteer, exhibitor, vendor, sponsor, speaker, media).

Response

{
  "ok": true,
  "data": [
    {
      "id": "uuid",
      "application_type": "exhibitor",
      "name": "Exhibitor Applications",
      "description": "Apply to showcase at the event",
      "is_active": true,
      "deadline": "2026-07-15T23:59:59Z",
      "max_slots": 50,
      "allow_file_uploads": true,
      "enable_auto_approval": false,
      "created_at": "2026-06-01T10:00:00Z"
    }
  ]
}
POST/v1/events/{event_id}/applications

Create an application config for an event you own.

Request body

{
  "application_type": "exhibitor",
  "name": "Exhibitor Applications",
  "description": "Apply to showcase at the event",
  "deadline": "2026-07-15T23:59:59Z",
  "max_slots": 50,
  "allow_file_uploads": true,
  "enable_auto_approval": false,
  "form_fields": [...],
  "is_active": true
}

Response

{
  "ok": true,
  "data": { "id": "uuid", "application_type": "exhibitor", ... }
}
GET/v1/events/{event_id}/applications/{type}

Get an application config by type (volunteer, exhibitor, vendor, sponsor, speaker, media, custom).

Response

{
  "ok": true,
  "data": {
    "id": "uuid",
    "application_type": "exhibitor",
    "name": "Exhibitor Applications",
    "description": "Apply to showcase",
    "form_fields": [...],
    "is_active": true,
    "deadline": "2026-07-15T23:59:59Z",
    "max_slots": 50,
    "allow_file_uploads": true,
    "enable_auto_approval": false
  }
}
PATCH/v1/events/{event_id}/applications/{type}

Update an application config for an event you own.

Request body

{
  "name": "Updated Exhibitor Apps",
  "max_slots": 75,
  "is_active": true
}

Response

{
  "ok": true,
  "data": { "id": "uuid", "application_type": "exhibitor", ... }
}
GET/v1/events/{event_id}/applications/{type}/submissions

List all submissions for a given application type.

Response

{
  "ok": true,
  "data": [
    {
      "id": "uuid",
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "jane@example.com",
      "phone": "+2348012345678",
      "status": "pending",
      "assigned_role": null,
      "answers": { "business_name": "Art House", ... },
      "created_at": "2026-06-20T14:30:00Z"
    }
  ]
}
GET/v1/events/{event_id}/applications/{type}/submissions/{submission_id}

Get a single submission with all details.

Response

{
  "ok": true,
  "data": {
    "id": "uuid",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "status": "pending",
    "answers": { ... },
    "files": [...],
    "notes": null
  }
}
PATCH/v1/events/{event_id}/applications/{type}/submissions/{submission_id}

Update a submission's status (approve, reject, waitlist) or add notes.

Request body

{
  "status": "approved",
  "assigned_role": "Exhibitor - Art Section",
  "notes": "Approved via API"
}

Response

{
  "ok": true,
  "data": { "id": "uuid", "status": "approved", ... }
}

Hosted Checkout

The POST /v1/checkout endpoint handles the full purchase flow so you don't need to build a checkout UI.

  1. Create a checkout — Call POST /v1/checkout with the event, ticket tier, and customer info.
  2. Redirect the buyer — For paid tiers, send the customer to the checkout_url (a Flutterwave-hosted payment page that supports card, USSD, bank transfer, and mobile money). For free tiers, the ticket_token and ticket_id are returned directly.
  3. The buyer completes payment — On Flutterwave's page, the buyer pays and is redirected back to your site.
  4. Ticket email is sent — As soon as payment is confirmed, the buyer receives a beautifully designed email with their QR code entry pass and event details.
  5. Verify payment — Use POST /v1/verify-payment with the tx_ref and transaction_id to confirm payment was successful and get the ticket token.

Webhooks

Supported events

event.created
An event was created
event.updated
An event was updated
ticket.created
A ticket tier was created
attendee.created
An attendee was manually registered
checkin.completed
An attendee was checked in
product.created
A merch product was created
product.updated
A merch product was updated
application.created
An application config was created
application.updated
An application config was updated
application.status_changed
A submission status was changed

Delivery format

Webhooks are delivered as HTTP POST requests to your configured endpoint URL.

{
  "event": "attendee.created",
  "timestamp": "2026-06-23T12:00:00Z",
  "data": {
    "attendee_id": "uuid",
    "event_id": "uuid",
    "attendee_name": "John Doe",
    "attendee_email": "john@example.com"
  }
}

Headers

Content-Type: application/json

X-Tixdorm-Signature: sha256=abc...

X-Tixdorm-Event: attendee.created

X-Tixdorm-Delivery-Id: uuid

Signature verification

Every webhook includes an HMAC SHA256 signature. Verify it using your webhook secret to confirm the payload came from Tixdorm:

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Retry schedule

If your endpoint doesn't respond with a 2xx status within 5 seconds, Tixdorm retries up to 5 times with exponential backoff: 1 minute → 5 minutes → 30 minutes → 6 hours → 24 hours.

Managing webhooks

Configure webhooks from your Partner API dashboard. You can add multiple endpoints, each with its own signing secret. View delivery logs including status, HTTP response code, and response body for debugging.

Code Examples

Quickstart snippets in popular languages.

# List all events
curl -H "Authorization: Bearer sk_live_xxx" \
  https://api.tixdorm.com/v1/events

# Create an event
curl -X POST \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"title":"My Event","start_date":"2026-07-01T10:00:00Z","venue":"Lagos"}' \
  https://api.tixdorm.com/v1/events

# Create a ticket tier
curl -X POST \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"event_id":"evt_uuid","name":"VIP","price":15000,"quantity":100}' \
  https://api.tixdorm.com/v1/tickets

# Check in an attendee
curl -X POST \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"ticket_id":"tkt_uuid"}' \
  https://api.tixdorm.com/v1/checkin

# List merch products
curl -H "Authorization: Bearer sk_live_xxx" \
  https://api.tixdorm.com/v1/events/{event_id}/products

# List applications
curl -H "Authorization: Bearer sk_live_xxx" \
  https://api.tixdorm.com/v1/events/{event_id}/applications

# List submissions for an application type
curl -H "Authorization: Bearer sk_live_xxx" \
  https://api.tixdorm.com/v1/events/{event_id}/applications/exhibitor/submissions

Errors

All errors follow a consistent format:

{
  "ok": false,
  "error": "A human-readable description of the problem"
}

HTTP status codes

200
Success
201
Created
400
Bad request — missing or invalid fields
401
Unauthorized — missing or invalid API key
404
Not found
405
Method not allowed
429
Rate limit exceeded
500
Internal server error

Rate Limits

The current rate limit is 100 requests per minute per API key. Exceeding this limit returns a 429 Too Many Requests response.

If your integration requires higher limits, contact support at support@tixdorm.com.

Pricing

Free for all partners

The Partner API is completely free. There are no tiered plans, no monthly fees, and no hidden costs. You only pay the standard 5% platform fee on paid ticket transactions (free events incur no fees).

  • ✓ Unlimited events
  • ✓ Unlimited tickets
  • ✓ Hosted checkout
  • ✓ Webhook support
  • ✓ Email notifications + QR codes
  • ✓ All API endpoints

FAQ

How do I get API access?

Go to your dashboard → Partners → Request Access. An admin will review and approve your request. Once approved, you can generate API keys immediately.

Can I use the API without a hosted checkout page?

Yes. The checkout endpoint is optional. You can create tickets and attendees programmatically using the POST /v1/attendees endpoint.

What happens if my webhook endpoint is down?

Tixdorm retries delivery up to 5 times over 24 hours (1min → 5min → 30min → 6h → 24h). After all attempts fail, the delivery is marked as failed.

Can I have multiple API keys?

Yes. You can generate multiple key pairs for different environments (sandbox vs production) or different applications. Each key pair is independently revocable.

Is my data isolated from other partners?

Yes. Every API key belongs to a single organization. All database queries are scoped to your organization. No cross-tenant data access is possible.

What languages can I use?

Any language that can make HTTP requests. The API is RESTful with JSON request/response bodies.

Support

Need help with the API? Here's how to reach us: