API
HTTP API
A plain HTTPS API over the same seven read operations the AI connector exposes. One key, one header, JSON back. Use it from a script, Zapier, Make or your booth software to check which events have audio ready, pull a gallery link, or read gallery stats, without opening the dashboard.
Who can use it
- Operators on the Monthly plan (Annual counts: it is the same unlimited plan billed yearly). Pay-per-event accounts see the key card locked in Settings, and a key on an account that leaves the plan answers
403 plan_requireduntil it is back. - Each key belongs to one operator and reads that operator’s own account only. There are no third-party app credentials; a vendor building for many operators uses the MCP connector and OAuth.
- Phase 1 is read-only. Creating or changing events and starting a clean stay in the dashboard and the connector for now.
API keys
In the dashboard open Settings, then Account, and find the API keys card. Name the key after what will use it and click Create key. The full key is shown once; copy it then, because only its hash is kept. Up to 5 active keys per account. Revoke a key from the same card and anything using it stops at once.
- Format
hha_live_followed by 43 letters and digits- Stored as
- SHA-256 hash only. Lost keys cannot be recovered; revoke and create a new one.
- Shown
- Once, at creation. The card lists each key by its first characters and last-used date.
- Scope
- Read, your own account. Scopes are fixed in Phase 1.
Authentication
Send the key as a bearer token on every request. Nothing else is needed: no sign-in, no session, no OAuth.
curl "https://www.happyhearaudio.com/api/v1/events?query=Rivera&from=2026-11-01&to=2026-11-30&limit=10" \
-H "Authorization: Bearer $HHA_API_KEY"A missing or unknown key answers 401 with a WWW-Authenticate: Bearer header; a revoked key answers 401 revoked_key. Keep the key server-side. It is as sensitive as your password: anyone holding it can read every event in the account.
Making calls
Base URL https://www.happyhearaudio.com/api/v1. All endpoints are GET and answer JSON. Filters go in the query string and ids in the path. The full list, with parameters and example responses, is on the API reference.
| Endpoint | What it answers |
|---|---|
| GET /events | Search your events |
| GET /events/needing-attention | List events that need a look |
| GET /events/{id} | Get one event |
| GET /events/{id}/audio-status | Check audio status on an event |
| GET /events/{id}/gallery-link | Get the gallery link |
| GET /events/{id}/gallery-stats | Get gallery stats |
| GET /account/plan | Get your plan and usage |
Errors are always one shape: { "error": { "code", "message" } }. A validation error adds issues naming the field.
{
"error": {
"code": "invalid_request",
"message": "A parameter is missing or malformed.",
"issues": [
{
"field": "limit",
"message": "Too big: expected number to be <=100"
}
]
}
}Limits
- Requests
- 60 per 60 seconds, per key
- Headers
X-RateLimit-LimitandX-RateLimit-Remainingon every answer;Retry-After(seconds) on a429- Result size
- Up to 100 events per search; up to 500 messages per event
- Keys
- 5 active per account
Back off for Retry-After seconds and retry. Polling an event every few seconds is fine; polling it in a tight loop is what the limit is for.
What is never exposed
The API reads the same allow-listed views as the connector. None of the following is in any response, with any key, on any plan:
- Guest audio, in any form (no file, no URL, no stream)
- Transcripts and any words a guest said
- Caller phone numbers and SMS bodies
- Speaker names and emotion tags
- Gallery share codes (only whether one is set)
- Storage paths, signed URLs and Twilio identifiers
- Card, invoice or payment details
Versioning
The version is in the path (/api/v1/). Within v1, fields are only ever added, never renamed or removed, and a new optional parameter never changes the answer to an old request. Anything that would break an existing client ships as /api/v2/ with v1 kept running for at least 90 days and the date announced on the changelog. Read responses by field name, not position, and ignore fields you do not know.
The machine-readable description is /api/v1/openapi.json (OpenAPI 3.1), generated from the same code that validates each request.
curl https://www.happyhearaudio.com/api/v1/openapi.jsonA complete example
Set the key once, then ask which events still need a look:
export HHA_API_KEY="hha_live_…"
curl "https://www.happyhearaudio.com/api/v1/events/needing-attention" \
-H "Authorization: Bearer $HHA_API_KEY"