HangHut API
The HangHut API lets you integrate event ticketing directly into your website or mobile app. List your events, sell tickets through hosted checkout, and verify tickets at the door — all with simple REST calls.
Base URL
https://api.hanghut.com/v1
Available Endpoints
Authentication
Authenticate every request by including your API key in the Authorization header as a Bearer token.
API keys are generated from your Organizer Dashboard. All keys begin with hh_live_ and are scoped to your organization.
Header
Authorization: Bearer hh_live_3dd28059a859bddb...
Example · curl
curl https://api.hanghut.com/v1/events \
-H "Authorization: Bearer hh_live_your_key"Example · JavaScript
const res = await fetch( 'https://api.hanghut.com/v1/events', { headers: { 'Authorization': `Bearer ${API_KEY}` } } ); const { data } = await res.json();
Example · Python
import requests response = requests.get( "https://api.hanghut.com/v1/events", headers={"Authorization": f"Bearer {api_key}"} ) events = response.json()["data"]
Rate Limits
API requests are rate limited per API key using a sliding window. Exceeding the limit returns a 429 response.
429 Response
{
"error": {
"message": "Rate limit exceeded. Max 100 requests per minute.",
"status": 429
}
}Wait for the window to reset (60 seconds) before retrying.
Errors
All errors return a consistent JSON structure with an HTTP status code.
| Code | Description |
|---|---|
| 400 | Bad request — invalid parameters |
| 401 | Unauthorized — bad or missing API key |
| 404 | Not found |
| 409 | Conflict — sold out or unavailable |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Error format
{
"error": {
"message": "Event not found",
"status": 404
}
}/eventsReturns a paginated list of events for your organization. Includes ticket tiers and real-time sold counts.
Query Parameters
| page | integer | Page number Default: 1 |
| per_page | integer | Results per page (max 50) Default: 20 |
| status | string | Filter: active, draft, cancelled Default: active |
Request
curl "https://api.hanghut.com/v1/events?page=1&per_page=10" \ -H "Authorization: Bearer hh_live_your_key"
Response · 200
{
"data": {
"events": [
{
"id": "8db0f243-2e64-...",
"title": "S10MAIC",
"status": "active",
"start_datetime": "2026-03-27T19:00:00+00:00",
"venue_name": "Mow's",
"capacity": 100,
"tickets_sold": 100,
"ticket_tiers": [
{
"name": "General Admission",
"price": 1000,
"quantity_total": 100,
"quantity_sold": 100
}
]
}
],
"meta": {
"page": 1,
"per_page": 10,
"total": 7,
"total_pages": 1,
"has_more": false
}
}
}/events/:idReturns full event details including description, venue, images, and ticket tiers with real-time available counts per tier.
Path Parameters
| id | uuid | Event ID REQUIRED |
Each ticket tier includes an available field calculated as quantity_total - quantity_sold. Use this to show availability on your site.
Request
curl "https://api.hanghut.com/v1/events/8db0f243-..." \ -H "Authorization: Bearer hh_live_your_key"
Example · JavaScript integration
// Display event on your website const res = await fetch( `https://api.hanghut.com/v1/events/${eventId}`, { headers: { Authorization: `Bearer ${API_KEY}` } } ); const { data: event } = await res.json(); // Show each tier event.ticket_tiers.forEach(tier => { console.log( `${tier.name}: ₱${tier.price} — ${tier.available} left` ); });
/checkoutsCreates a hosted checkout session. Redirect your customer to the returned URL to complete payment via GCash, Maya, bank transfer, or card.
Request Body
| event_id | uuid | Event to buy tickets forREQUIRED |
| tier_id | uuid | Ticket tier (default if omitted) |
| quantity | integer | Number of tickets (min 1)REQUIRED |
| customer.name | string | Customer full nameREQUIRED |
| customer.email | string | Email for ticket deliveryREQUIRED |
| customer.phone | string | Phone number |
| success_url | string | Redirect after paymentREQUIRED |
| cancel_url | string | Redirect if cancelled |
Request · curl
curl -X POST "https://api.hanghut.com/v1/checkouts" \ -H "Authorization: Bearer hh_live_your_key" \ -H "Content-Type: application/json" \ -d '{ "event_id": "8db0f243-2e64-...", "tier_id": "66a5cdd3-d097-...", "quantity": 2, "customer": { "name": "Juan Dela Cruz", "email": "juan@example.com" }, "success_url": "https://your-site.com/success", "cancel_url": "https://your-site.com/cancel" }'
Response · 201
{
"data": {
"checkout_id": "pi_abc123def456",
"checkout_url": "https://checkout.xendit.co/web/...",
"expires_at": "2026-03-22T00:00:00Z"
}
}Full example · Node.js Express
// Server-side: create checkout and redirect app.post('/buy-ticket', async (req, res) => { const response = await fetch( 'https://api.hanghut.com/v1/checkouts', { method: 'POST', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ event_id: req.body.event_id, tier_id: req.body.tier_id, quantity: req.body.quantity, customer: { name: req.body.name, email: req.body.email }, success_url: 'https://your-site.com/thank-you', cancel_url: 'https://your-site.com/events' }) } ); const { data } = await response.json(); res.redirect(data.checkout_url); });
/tickets/:idVerify a ticket's current status, check-in state, and associated event/customer details. Useful for door scanning or customer support.
Path Parameters
| id | uuid | Ticket ID REQUIRED |
Ticket Statuses
sold | Valid, ready for check-in |
checked_in | Already scanned |
refunded | Refunded |
cancelled | Cancelled |
Request
curl "https://api.hanghut.com/v1/tickets/a1b2c3d4-..." \ -H "Authorization: Bearer hh_live_your_key"
Response · 200
{
"data": {
"id": "a1b2c3d4-...",
"status": "sold",
"checked_in_at": null,
"purchased_at": "2026-03-21T10:30:00Z",
"event": {
"id": "8db0f243-...",
"title": "S10MAIC",
"start_datetime": "2026-03-27T19:00:00+00:00",
"venue_name": "Mow's"
},
"tier": {
"name": "General Admission",
"price": 1000
},
"customer": {
"name": "Juan Dela Cruz",
"email": "juan@example.com"
}
}
}Example · Door check-in (Python)
import requests def verify_ticket(ticket_id): r = requests.get( f"https://api.hanghut.com/v1/tickets/{ticket_id}", headers={"Authorization": f"Bearer {API_KEY}"} ) ticket = r.json()["data"] if ticket["status"] == "sold": print(f"✅ VALID — {ticket['customer']['name']}") elif ticket["status"] == "checked_in": print(f"⚠️ ALREADY USED at {ticket['checked_in_at']}") else: print(f"❌ INVALID — status: {ticket['status']}")
/eventsCreate a new event. Events are created in draft status by default.
Request Body
| title | string | Event nameREQUIRED |
| start_datetime | ISO 8601 | Start date/timeREQUIRED |
| end_datetime | ISO 8601 | End date/time |
| venue_name | string | Venue name |
| city | string | City |
| capacity | integer | Max attendees |
| ticket_price | number | Base price in PHP |
Request
curl -X POST "https://api.hanghut.com/v1/events" \
-H "Authorization: Bearer hh_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"title": "Friday Night Comedy",
"start_datetime": "2026-04-10T20:00:00+08:00",
"venue_name": "Comedy Bar Manila",
"city": "Manila",
"capacity": 150,
"ticket_price": 800
}'Response · 201
{
"data": {
"id": "f47ac10b-58cc-...",
"title": "Friday Night Comedy",
"status": "draft",
"start_datetime": "2026-04-10T20:00:00+08:00",
"venue_name": "Comedy Bar Manila",
"capacity": 150,
"ticket_price": 800
}
}/events/:idUpdate an event's details. Only include the fields you want to change. Set status to active to publish.
curl -X PUT "https://api.hanghut.com/v1/events/f47ac10b-..." \
-H "Authorization: Bearer hh_live_your_key" \
-H "Content-Type: application/json" \
-d '{"status": "active", "capacity": 200}'/events/:id/attendeesReturns a paginated list of attendees for an event. Filter by ticket status to manage guest lists or export check-in data.
Query Parameters
| page | integer | Page number (default: 1) |
| per_page | integer | Results per page (max 100) |
| status | string | Filter: sold, checked_in, refunded |
curl "https://api.hanghut.com/v1/events/8db0f243-.../attendees?status=sold" \ -H "Authorization: Bearer hh_live_your_key"
Response · 200
{
"data": {
"event": { "id": "8db0f243-...", "title": "S10MAIC" },
"attendees": [
{
"ticket_id": "a1b2c3d4-...",
"ticket_number": "TK-00042",
"status": "sold",
"checked_in_at": null,
"customer": {
"name": "Juan Dela Cruz",
"email": "juan@example.com"
},
"tier": { "name": "General Admission", "price": 1000 }
}
],
"meta": { "page": 1, "total": 85, "has_more": true }
}
}/tickets/:id/check-inMark a ticket as checked in. Returns 409 if already used, refunded, or cancelled.
curl -X POST "https://api.hanghut.com/v1/tickets/a1b2c3d4-.../check-in" \ -H "Authorization: Bearer hh_live_your_key"
Response · 200
{
"data": {
"id": "a1b2c3d4-...",
"status": "used",
"checked_in_at": "2026-03-27T19:15:00Z",
"event": { "id": "8db0f243-...", "title": "S10MAIC" },
"customer": { "name": "Juan Dela Cruz" }
}
}/tickets/:id/refundMark a ticket as refunded. This updates the ticket status and decrements the tier sold count.
curl -X POST "https://api.hanghut.com/v1/tickets/a1b2c3d4-.../refund" \ -H "Authorization: Bearer hh_live_your_key"
Response · 200
{
"data": {
"id": "a1b2c3d4-...",
"status": "refunded",
"event": { "id": "8db0f243-...", "title": "S10MAIC" },
"tier": { "name": "General Admission", "price": 1000 }
}
}/ordersReturns paginated purchase orders across all your events. Filter by specific event with event_id.
Query Parameters
| page | integer | Page number (default: 1) |
| per_page | integer | Results per page (max 50) |
| event_id | uuid | Filter by event |
curl "https://api.hanghut.com/v1/orders?event_id=8db0f243-..." \ -H "Authorization: Bearer hh_live_your_key"
Response · 200
{
"data": {
"orders": [
{
"id": "pi_abc123-...",
"event": { "id": "8db0f243-...", "title": "S10MAIC" },
"customer": { "name": "Juan Dela Cruz", "email": "juan@example.com" },
"quantity": 2,
"total_amount": 2000,
"status": "completed",
"payment_method": "gcash",
"paid_at": "2026-03-21T10:30:00Z"
}
],
"meta": { "page": 1, "total": 42, "has_more": true }
}
}Webhooks
Receive real-time notifications when events happen. Register an HTTPS endpoint and we'll POST signed payloads to it.
Available Events
| ticket.purchased | A ticket was purchased |
| ticket.refunded | A ticket was refunded |
| ticket.checked_in | A ticket was scanned |
| event.updated | Event details changed |
Each delivery includes an X-HangHut-Signature header (HMAC-SHA256 of the body using your webhook secret) for verification.
Payload format
{
"id": "evt_abc123...",
"type": "ticket.purchased",
"created_at": "2026-03-21T10:30:00Z",
"data": {
"ticket_id": "a1b2c3d4-...",
"event_id": "8db0f243-...",
"customer": { "name": "Juan Dela Cruz" },
"amount": 1000
}
}Verify signature (Node.js)
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return signature === expected;
}/webhooksRegister a new webhook endpoint. The response includes a secret for signature verification — save it, it's only shown once.
Request Body
| url | string | HTTPS endpoint URL REQUIRED |
| events | string[] | Event types to subscribe to REQUIRED |
curl -X POST "https://api.hanghut.com/v1/webhooks" \
-H "Authorization: Bearer hh_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-site.com/webhook",
"events": ["ticket.purchased", "ticket.refunded"]
}'Response · 201
{
"data": {
"id": "wh_abc123...",
"url": "https://your-site.com/webhook",
"events": ["ticket.purchased", "ticket.refunded"],
"secret": "whsec_a1b2c3d4e5f6...",
"is_active": true
}
}/analytics/salesRevenue analytics with per-event breakdown. Optionally filter by event and date range.
Query Parameters
| event_id | uuid | Filter to specific event |
| from | ISO 8601 | Start of date range |
| to | ISO 8601 | End of date range |
curl "https://api.hanghut.com/v1/analytics/sales" \ -H "Authorization: Bearer hh_live_your_key"
Response · 200
{
"data": {
"total_revenue": 150000,
"total_tickets_sold": 212,
"total_orders": 189,
"total_discounts": 5000,
"events": [
{
"id": "8db0f243-...",
"title": "S10MAIC",
"revenue": 100000,
"tickets_sold": 100,
"orders": 95
}
]
}
}/promo-codesCreate a promo code for an event. Supports percentage or fixed amount discounts with optional usage limits and expiry.
Request Body
| event_id | uuid | Target eventREQUIRED |
| code | string | Promo code (min 3 chars)REQUIRED |
| discount_type | string | "percentage" or "fixed_amount"REQUIRED |
| discount_amount | number | Discount valueREQUIRED |
| usage_limit | integer | Max uses (unlimited if omitted) |
| expires_at | ISO 8601 | Expiry date |
curl -X POST "https://api.hanghut.com/v1/promo-codes" \
-H "Authorization: Bearer hh_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"event_id": "8db0f243-...",
"code": "EARLYBIRD",
"discount_type": "percentage",
"discount_amount": 20,
"usage_limit": 50,
"expires_at": "2026-04-01T00:00:00Z"
}'Response · 201
{
"data": {
"id": "pc_abc123...",
"code": "EARLYBIRD",
"discount_type": "percentage",
"discount_amount": 20,
"usage_limit": 50,
"usage_count": 0,
"is_active": true
}
}Need help integrating? Contact support@hanghut.com
© 2026 HangHut. All rights reserved.