API Reference
Build powerful integrations with the TicketWave REST API. Manage events, orders, tickets, and affiliates programmatically.
Authentication
All API requests require a JWT Bearer token in the Authorization header.
Request Header
Authorization: Bearer YOUR_JWT_TOKEN
How to get your API key
- Create an account at ticketwavehq.com/signup
- Log in via
POST /api/auth/loginwith your email and password - The response includes a JWT token valid for 7 days
- Include this token in the
Authorization: Bearerheader
Base URL
https://www.ticketwavehq.com
Rate Limits
API requests are rate limited to ensure fair usage and platform stability.
| Endpoint Type | Limit |
|---|---|
| Admin endpoints | 60 requests / minute |
| Scanner endpoints | 120 requests / minute |
| Public endpoints | 30 requests / minute |
| Checkout | 10 requests / minute |
Rate-limited responses return 429 Too Many Requests. All responses include X-RateLimit-Remaining headers.
Endpoints
All endpoints return JSON. Successful responses use 200 or 201. Errors return an {"error": "message"} body.
Events
/api/admin/eventsList all events for your account/api/admin/eventsCreate a new event with ticket tiers and add-ons/api/admin/events/:idGet event details including tiers and sales data/api/admin/events/:idUpdate event details, status, or tiers/api/admin/events/:idDelete a draft event/api/admin/events/:id/cancelCancel event and auto-refund all orders/api/admin/events/:id/duplicateClone an event with new dates/api/admin/events/:id/liveReal-time check-in stats for live eventsOrders
/api/admin/ordersList orders with filters (date, status, event)/api/admin/orders/:idFull order details with tickets and add-ons/api/admin/orders/:id/refundRefund an order (full or partial)/api/admin/orders/:id/resendResend confirmation email and ticketsTickets
/api/scanScan a QR code and check in a ticket/api/admin/tickets/transferTransfer a ticket to a new holderCustomers
/api/admin/customersList all customers with order history/api/admin/customers/exportExport customer list as CSVAffiliates
/api/admin/affiliatesList all affiliates with earnings/api/admin/affiliatesRegister a new affiliate/api/admin/affiliates/:id/linksGet affiliate tracking linksWebhooks
/api/admin/webhooks/configGet current webhook configuration/api/admin/webhooks/configSet webhook URL and subscribed eventsCode Examples
curl
# List your events
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://www.ticketwavehq.com/api/admin/events
# Create an event
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Summer Pool Party",
"venueId": "venue-uuid",
"date": "2026-07-15",
"startTime": "14:00",
"totalCapacity": 500,
"tiers": [
{ "name": "General", "price": 25, "quantity": 400 },
{ "name": "VIP", "price": 75, "quantity": 100 }
]
}' \
https://www.ticketwavehq.com/api/admin/eventsJavaScript / Node.js
const API_URL = "https://www.ticketwavehq.com";
const TOKEN = "YOUR_TOKEN";
// List events
const events = await fetch(`${API_URL}/api/admin/events`, {
headers: { Authorization: `Bearer ${TOKEN}` },
}).then(r => r.json());
console.log(events);
// Refund an order
const refund = await fetch(
`${API_URL}/api/admin/orders/${orderId}/refund`,
{
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ reason: "customer_request" }),
}
).then(r => r.json());Python
import requests
API_URL = "https://www.ticketwavehq.com"
TOKEN = "YOUR_TOKEN"
headers = {"Authorization": f"Bearer {TOKEN}"}
# List events
events = requests.get(f"{API_URL}/api/admin/events", headers=headers).json()
# Create an event
new_event = requests.post(
f"{API_URL}/api/admin/events",
headers=headers,
json={
"title": "Summer Pool Party",
"venueId": "venue-uuid",
"date": "2026-07-15",
"startTime": "14:00",
"totalCapacity": 500,
"tiers": [
{"name": "General", "price": 25, "quantity": 400},
{"name": "VIP", "price": 75, "quantity": 100},
],
},
).json()
print(new_event)Webhook Events
Configure your webhook endpoint via the API or Settings page. Each event sends a POST request with a JSON body signed with HMAC-SHA256.
Webhook Headers
X-TicketWave-Signature: <HMAC-SHA256 of request body> X-TicketWave-Event: order.created Content-Type: application/json
Verifying Signatures (Node.js)
const crypto = require("crypto");
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}| Event | Description |
|---|---|
| order.created | Fired when a new order is paid. Includes order details, customer info, and tickets. |
| order.refunded | Fired when an order is fully or partially refunded. Includes refund amount and reason. |
| event.published | Fired when an event status changes to published (goes live for ticket sales). |
| event.cancelled | Fired when an event is cancelled. All orders are auto-refunded. |
| checkin.completed | Fired each time a ticket is scanned at the door. Includes ticket and gate info. |
| webhook.ping | Sent when you first configure your webhook URL to verify the endpoint works. |
Webhook Payload Examples
Each webhook delivers a JSON payload via HTTP POST. All payloads include an event type, timestamp, and a data object. Verify authenticity using the HMAC-SHA256 signature in the X-TicketWave-Signature header.
order.createdFired when a new order is paid
{
"event": "order.created",
"timestamp": "2026-04-02T15:30:00.000Z",
"data": {
"orderId": "ord_a1b2c3d4",
"orderNumber": "TW-2026-A1B2C3",
"status": "paid",
"customerName": "Jane Smith",
"customerEmail": "jane@example.com",
"phone": "+34600123456",
"eventId": "evt_x9y8z7",
"eventTitle": "Summer Pool Party",
"eventDate": "2026-07-15",
"subtotal": "75.00",
"discount": "0.00",
"total": "75.00",
"currency": "EUR",
"tickets": [
{
"ticketId": "tkt_abc123",
"tierName": "VIP",
"holderName": "Jane Smith",
"qrCode": "TW-VIP-ABC123"
}
],
"addOns": [
{
"name": "Drink Package",
"quantity": 1,
"unitPrice": "15.00"
}
],
"promoCode": null,
"affiliateCode": null
}
}order.refundedFired when an order is fully or partially refunded
{
"event": "order.refunded",
"timestamp": "2026-04-03T10:15:00.000Z",
"data": {
"orderId": "ord_a1b2c3d4",
"orderNumber": "TW-2026-A1B2C3",
"customerName": "Jane Smith",
"customerEmail": "jane@example.com",
"eventTitle": "Summer Pool Party",
"refundAmount": "75.00",
"currency": "EUR",
"reason": "customer_request",
"isFullRefund": true,
"stripeRefundId": "re_1234567890"
}
}event.publishedFired when an event goes live for ticket sales
{
"event": "event.published",
"timestamp": "2026-04-01T09:00:00.000Z",
"data": {
"eventId": "evt_x9y8z7",
"title": "Summer Pool Party",
"slug": "summer-pool-party-2026",
"date": "2026-07-15",
"startTime": "14:00",
"endTime": "22:00",
"venue": "Example Venue",
"totalCapacity": 500,
"tiers": [
{ "name": "General", "price": "25.00", "quantity": 400 },
{ "name": "VIP", "price": "75.00", "quantity": 100 }
],
"url": "https://www.ticketwavehq.com/events/summer-pool-party-2026"
}
}event.cancelledFired when an event is cancelled (all orders auto-refunded)
{
"event": "event.cancelled",
"timestamp": "2026-04-10T08:00:00.000Z",
"data": {
"eventId": "evt_x9y8z7",
"title": "Summer Pool Party",
"date": "2026-07-15",
"reason": "weather",
"totalOrdersRefunded": 142,
"totalRefundAmount": "8750.00",
"currency": "EUR"
}
}checkin.completedFired each time a ticket is scanned at the door
{
"event": "checkin.completed",
"timestamp": "2026-07-15T22:15:30.000Z",
"data": {
"ticketId": "tkt_abc123",
"orderId": "ord_a1b2c3d4",
"orderNumber": "TW-2026-A1B2C3",
"holderName": "Jane Smith",
"tierName": "VIP",
"eventId": "evt_x9y8z7",
"eventTitle": "Summer Pool Party",
"gate": "Main Entrance",
"scannedBy": "usr_door01",
"checkedInAt": "2026-07-15T22:15:30.000Z"
}
}Signature Verification
Every webhook includes an X-TicketWave-Signature header. Always verify this signature to ensure the request is genuinely from TicketWave and has not been tampered with.
Node.js
const crypto = require("crypto");
function verifyWebhook(rawBody, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post("/webhook", (req, res) => {
const sig = req.headers["x-ticketwave-signature"];
if (!verifyWebhook(req.rawBody, sig, WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
const { event, data } = req.body;
// Handle the event...
res.status(200).send("OK");
});Python
import hmac
import hashlib
def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# In your Flask handler:
@app.route("/webhook", methods=["POST"])
def handle_webhook():
sig = request.headers.get("X-TicketWave-Signature", "")
if not verify_webhook(request.data, sig, WEBHOOK_SECRET):
return "Invalid signature", 401
payload = request.json
# Handle payload["event"] and payload["data"]...
return "OK", 200Response Format
Success (200)
{
"id": "evt_abc123",
"title": "Summer Pool Party",
"status": "published",
"date": "2026-07-15"
}Error (400/401/404)
{
"error": "Missing required fields"
}