Using the Hi.Events REST API
The Hi.Events API is the same API the web app uses. Integrations sign in with an API key and can read and change events, products, orders, attendees, check-ins and more, with the same access as the person who created the key. This page covers what you need to get started. The full list of endpoints is in the API reference inside Hi.Events.
The API Reference
Open Settings → API keys → API reference in Hi.Events. It lists every endpoint an API key can call, with request and response schemas, and lets you send test requests. It already uses the right base URL for your Hi.Events install, so it’s the easiest place to copy URLs from.
Creating an API Key
Open My Profile from the user menu, click API keys and create a key. You choose:
- Access: Read and write, to call every endpoint you can, or Read-only, for
GETendpoints and exports only. Members with the Viewer role can only create read-only keys - Expiration: 7, 30, 60, 90 or 180 days, 1 year, or No expiration. Keys that never expire stay valid until they’re revoked, so only use them on servers you control
The full key, starting hie_, is shown once, when you create it. Hi.Events only stores a hash of it, so copy it
somewhere safe straight away. For keys that last longer than two weeks, you’ll get an email a week before the key
expires.
A key belongs to you and to the one account you created it in. It has your role, permissions and event access, never more, and changes to your role apply to it straight away. Your email address must be confirmed before you can create one, you confirm your password (or sign in again with single sign-on) as you create it, and you can have up to 25 active keys per account.
A key stops working when you or an account admin revoke it, when it expires, when you’re deactivated on the account, and when your single sign-on changes. Resetting your password through Forgot password, or disconnecting a Google or Microsoft sign-in, deletes your keys in every account you belong to.
Base URL
| Where you use Hi.Events | Base URL |
|---|---|
| Hi.Events Cloud | https://api.hi.events |
| Self-hosted, all-in-one Docker image | Your app’s URL plus /api, for example https://tickets.example.com/api |
| Self-hosted, separate backend image or manual install | Your backend’s URL, for example https://api.tickets.example.com |
On a self-hosted install, the base URL is whatever VITE_API_URL_CLIENT is set to (see
Deploying).
Authentication
Send the key as a bearer token with every request, and ask for JSON:
curl https://api.hi.events/events \
-H "Authorization: Bearer hie_your_key" \
-H "Accept: application/json"That lists the events in the key’s account. To list an event’s attendees:
curl "https://api.hi.events/events/123/attendees?per_page=50" \
-H "Authorization: Bearer hie_your_key" \
-H "Accept: application/json"Endpoints under /public/* (event pages, checkout, ticket lookup) need no key and are marked (public) in the
reference.
Some endpoints can’t be used with a key, even a read-and-write one: signing in, your profile and sign-in security, the
team, API keys, payouts, card readers, VAT settings and account settings. They need you signed in to Hi.Events, and return 403 with
error_code: API_KEY_NOT_ALLOWED if you call them with a key.
Pagination, Sorting and Filtering
List endpoints are paginated and take these query parameters:
| Parameter | What it does | Default |
|---|---|---|
page | Page number | 1 |
per_page | Results per page, up to 100 | 25 |
sort_by | Field to sort by. The fields you can use are listed in the response’s meta.allowed_sorts | Varies |
sort_direction | asc or desc | Varies |
query | Search term | |
filter_fields[field][operator] | Filter on a field. The fields you can use are listed in meta.allowed_filter_fields |
Filter operators are eq, ne, lt, lte, gt, gte, like, ilike and in (with comma-separated values). Use
the value null with eq or ne to match empty fields. For example, to list only active attendees:
curl -G "https://api.hi.events/events/123/attendees" \
--data-urlencode "filter_fields[status][eq]=ACTIVE" \
-H "Authorization: Bearer hie_your_key" \
-H "Accept: application/json"Results come back in data, with links to the next and previous pages, and meta holding current_page,
last_page, per_page and total.
Errors
Errors return JSON with a message. Validation errors (422) also include an errors object keyed by field. Access
errors include an error_code. The ones you’re most likely to see with a key:
| Status | error_code | Meaning |
|---|---|---|
401 | The key is missing, unknown, expired or revoked | |
403 | API_KEY_READ_ONLY | A read-only key tried to make a change |
403 | API_KEY_NOT_ALLOWED | The endpoint can’t be used with an API key |
403 | READ_ONLY_ROLE | The key’s owner has view-only access to the account |
403 | PERMISSION_REQUIRED | The owner’s role lacks a permission the endpoint needs, such as refunds or financial data |
403 | ACCESS_RESTRICTED | The owner only has access to some organizers or events, and this isn’t one of them |
403 | TWO_FACTOR_SETUP_REQUIRED | The account requires two-factor authentication and the owner hasn’t set it up |
429 | Too many requests. Wait for the number of seconds in the Retry-After header |
The API reference lists the rest.
Rate Limits
By default, each person can make 180 requests a minute, shared between the web app and all of their API keys. Past
that, requests return 429. Self-hosted installs can change the limit with APP_API_RATE_LIMIT_PER_MINUTE.
Webhooks
Rather than polling, you can have Hi.Events send a POST request to your URL when something happens, such as a new
order, a cancelled attendee or a check-in. Webhooks are set up per event or per organizer, in Hi.Events (see
Webhooks) or through the API. Each request body looks like
this:
{
"event_type": "order.created",
"event_sent_at": "2026-08-07T10:00:00+00:00",
"payload": { }
}payload has the same shape as the matching resource in the API reference: an order for order.* events, an attendee
for attendee.*, and so on.
Every request carries a Signature header: a hex HMAC-SHA256 of the raw request body, using your webhook’s signing
secret as the key. Check it before trusting a payload. In Node.js:
import crypto from 'node:crypto';
const isValid = (rawBody, signature, secret) => {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return signature?.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
};Compute the signature from the body exactly as it arrived, before parsing it. Re-encoding parsed JSON can change it.
Respond quickly with a 2xx status: Hi.Events waits 3 seconds for a response before treating the delivery as failed.
MCP Server for AI Assistants
Hi.Events runs an MCP server, so Claude, ChatGPT and other AI assistants can work with an account through tools: list events, look up attendees, resend tickets, run reports, set up tickets and so on. Organizers connect it from My Profile → API keys → Connected apps, which shows the URL; the help center has the steps for Claude and ChatGPT.
| Where you use Hi.Events | MCP URL |
|---|---|
| Hi.Events Cloud | https://api.hi.events/mcp |
| Self-hosted | Your API base URL plus /mcp, for example https://tickets.example.com/api/mcp |
If your client asks which transport to use, choose HTTP (sometimes called Streamable HTTP), not SSE or stdio.
Signing In
Claude, ChatGPT, Claude Code and most other MCP clients handle sign-in themselves. Give them the URL and they open a Hi.Events page in the browser, where the person picks Read and write or Read only and confirms their password. Hi.Events then emails them to say an app was connected.
If you’re building your own client, sign-in is standard OAuth 2.1. Clients register themselves (dynamic client
registration) and have no client secret, and PKCE is required, with the S256 method only. Calling /mcp without a
token returns 401, with a WWW-Authenticate header that points to /.well-known/oauth-protected-resource. That
document lists the other endpoints.
Access tokens last an hour and work like API keys (they start hie_ too). Each time a client refreshes, it gets a new
refresh token and the old one stops working. A refresh token expires after 90 days without use. If an old refresh
token is used again, Hi.Events disconnects the app, because that usually means the token was copied. Clients can
revoke their own tokens through the standard revocation endpoint (RFC 7009). A connection is also deleted whenever the
person’s API keys would be: when their password is reset, when they’re deactivated, or when their single sign-on
changes.
Clients that can’t sign in this way can send an API key instead:
claude mcp add --transport http hi-events https://api.hi.events/mcp \
--header "Authorization: Bearer hie_your_key"Leave the header off and Claude Code signs in through the browser instead. In Cursor or VS Code, add a server with this
URL in their MCP settings, and add the same Authorization header there if you’re using a key.
Tools
There are 52 tools. Each one either only reads or makes changes, never both, and says which, so clients can treat changes differently, for example by asking you before running one.
| Area | Tools |
|---|---|
| Organizers and events | list_organizers, create_organizer, list_events, get_event, create_event, update_event, set_event_cover_image, set_event_venue, list_venues, update_event_settings, update_event_page_theme, publish_event, unpublish_event |
| Dates | list_event_dates, add_event_date, generate_event_dates, get_date_generation_status |
| Tickets | list_tickets, create_ticket, update_ticket, create_addon, list_ticket_categories, create_ticket_category, list_shared_capacities, create_shared_capacity, update_ticket_design |
| Promo codes and questions | list_promo_codes, create_promo_code, update_promo_code, list_questions, create_question, update_question, delete_question |
| Lineup | get_lineup, list_performer_profiles, add_lineup_performer, add_lineup_space, add_schedule_item |
| Attendees and orders | list_attendees, get_attendee, add_attendee, check_in_attendee, resend_ticket, list_orders, get_order, resend_order_confirmation |
| Sales | get_event_stats, get_organizer_stats, get_event_report, get_organizer_report |
| Website | list_widgets, create_widget |
Each tool works by calling the same REST endpoint you would, as the person who connected it. So it has their permissions and event access, can’t see sales figures if they can’t, and goes through the same validation and spam checks. Tools that make changes don’t appear at all for read-only connections, read-only keys, or people who can’t edit.
A few conventions the tools share:
- Dates you send are local times in the event’s timezone (
YYYY-MM-DD HH:MM). Dates returned are ISO 8601, with the event’s UTC offset get_event_statsandget_organizer_statscount days in UTC, because daily sales figures are stored by UTC date. The report tools count days in the event’s or organizer’s own timezone, as the dashboard does- Organizer money totals cover one currency at a time and list the others in
other_currencies - Reports return at most 500 rows and say when rows were left out
As with the REST API, new tools can be added at any time. Renaming or removing a tool, or changing what it takes or returns, is avoided and always called out in the release notes.
What the Tools Leave Out
There are no tools for refunds, cancelling orders, marking orders as paid, payouts, payment or invoicing settings, or messaging attendees. No tool can change an attendee’s or buyer’s email address, so a misled assistant can’t send a ticket somewhere new.
resend_ticket and resend_order_confirmation only email the address already on record, at most once per attendee or
order every 10 minutes. Separately, one email address gets at most 5 emails from the tools every 10 minutes, counting
add_attendee too.
Rate Limits
You can make 120 requests a minute to /mcp. Within that, each connection or key can make 60 changes a minute. Each
change also uses 2 to 4 requests of your normal API rate limit, because the tool makes several API
calls to do it. Setting up a full event from nothing takes about 35 changes.
The MCP server is part of the backend, with nothing to switch on. If you run your own reverse proxy, it needs to send
a few sign-in addresses under /.well-known/ to the backend (see
AI Assistants and OAuth Discovery), and the
scheduler clears out old tokens and connections.
Stability
The API isn’t versioned yet. The endpoints API keys can call are kept backward compatible: new endpoints, optional request fields and response fields can be added at any time, so ignore fields you don’t recognise. Removing or renaming an endpoint or field, or changing what it means, is avoided where possible and always called out in the release notes.
The in-app API reference works with no configuration. To also serve the full generated documentation, including
the endpoints only the web app uses, set API_DOCS_ENABLED=true (see
Deploying).