API reference
Events, orders and webhooks, for organisers and venues.
The Venued API is a small, deliberately narrow REST surface over data you
already own on Venued. Every key belongs to one principal — an
organiser account or a venue — and every response is filtered to it.
GET /v1/me tells you which one a key is.
What this API deliberately cannot do
It cannot publish an event. POST and PATCH accept visibility of
draft or unlisted only; anything else is refused with 403 forbidden.
Publishing is a decision with a public consequence and a phone-verification
gate behind it, so it stays in the dashboard where the person making it can
see what they are about to make public.
⚠️ Note also that draft → unlisted is one-way. An event that has been
made unlisted cannot be returned to draft through this API or any other.
It cannot touch money. Orders are read-only. There is no refund, no payout and no ticket issuance endpoint.
It cannot write server-owned fields. Anything not on the writable list
(see EventPatch) is silently dropped rather than rejected — including
ticketing, organizerId, priority and the embedding fields.
Getting a key
API keys are created from Studio (Business account → API), not through this
API. A key is shown once, at creation, and only its SHA-256 hash is
stored — Venued cannot recover or re-display it. Creating and revoking keys
requires the owner or org_manager role on the organiser account.
A key looks like vnd_live_ followed by 48 hex characters.
Who can hold a key
A key belongs to a principal — an organiser, a venue, or (not yet) a
professional — and GET /v1/me tells you which. Authorisation is
scope ∧ principal type, not scope alone, and the second half is not
decoration:
-
events:readmeans my events to an organiser and the events at my address to a venue. Same scope string, different set. -
A venue key cannot be minted with
events:writeororders:readat all. A venue does not own the events booked into it, and the buyer names and emails on an order are the organiser's business, not the building's. -
A venue can subscribe to webhooks, for
event.publishedonly — it fires when an event at the venue's address becomes public, alongside the organiser's own delivery of the same event. -
What a venue sees at its own address:
- every
publicevent; - an
unlistedevent only when no real account chose to unlist it — that is, when it belongs to an unclaimed placeholder business or to no organiser at all. Most unlisted events are catalogue rows collected from public sources that nobody has hidden from anyone; an unlisted event owned by an active organiser is that organiser's deliberate choice, and stays hidden; - never a draft, whoever owns it. A draft is an organiser's private working copy.
Paging stays exact across that filter:
has_moreis observed rather than inferred, so a hidden row is never mistaken for the end of the list. - every
-
Professional keys are not available yet — there is nothing for one to read until
/v1/profileand/v1/offeringsexist. Minting one is refused rather than silently issuing a key that can reach nothing.
Conventions
- Success bodies are
{"data": …}— all of them. - List bodies add
has_moreandnext_cursorbesidedata, on every list endpoint, including ones that cannot currently have a second page. One shape means one mapping in whatever tool you are wiring this into, rather than one per endpoint. - Error bodies are
{"error": "<code>", "message": "<sentence>", "request_id": "<id>"}.messageis for a human and may be reworded without notice; branch onerror.request_idis on every response as theX-Request-Idheader too — quote it when reporting a problem. Send your own and it is echoed rather than replaced, provided it is a plausible token of at most 64 characters. - Paging is by cursor. Pass
?limit=(max 100) and follownext_cursorinto?cursor=. A cursor is opaque and belongs to the query that produced it: it is refused withinvalid_cursorif the ordering changed under it, or if the row it anchors on was deleted. ?updated_after=is the poller's filter, on every list endpoint. ISO 8601 or epoch milliseconds, and it reorders the result byupdatedAtascending rather than the endpoint's default order — so changes arrive in the order they happened and the lastupdatedAtyou saw is the only state you need to keep.- An unknown query parameter is a
400 unsupported_parameter, never silently ignored. A filter that looks applied but is not is how a poller quietly ships every row it meant to exclude. - Money is in minor units, as an integer, beside a non-null uppercase
ISO-4217
currency.totalAmountMinor: 1999is €19.99. - Concurrency:
GET /v1/events/{eventId}returns anETag. Send it back asIf-Matchon thePATCHand an edit that would overwrite somebody else's change fails with412 precondition_failedinstead. OmittingIf-Matchstill succeeds. HEADis served whereverGETis: same status, same headers, no body. A405always carries anAllowheader naming what the path does accept.- Timestamps are ISO 8601 strings in responses. Requests accept either ISO 8601 or epoch milliseconds.
titleanddescriptionon an event are localized maps, not strings:{"EN": "Sunrise Run"}. Locale keys are normalised to UPPERCASE. Thetitlein a response is already flattened to a single string.
Changes
The reference above describes the API as it is. What changed, and when, is kept here rather than threaded through it.
2026-09-21 — all breaking, all made while production held no API keys or webhook subscriptions, so nobody had anything to migrate:
- Venue keys. A key belongs to a principal — an organiser or a venue — rather than always an organiser. See Who can hold a key.
- Paging. Every list is ordered and pageable by
cursor, withhas_moreandnext_cursor.GET /v1/eventswas previously unordered, so an organiser with more than 100 events had no way to reach the rest. - Money.
Order.totalAmount, a float in major units, becametotalAmountMinor, an integer. The float is not kept alongside it. DELETE /v1/webhooks/{webhookId}returns the{"data": …}envelope (it returned{"ok": true}, the only endpoint with its own shape) and is metered as a write (it was metered as a read).- Rate limits belong to the account, not the key. Minting a second key no longer doubles the budget.
- Webhook envelopes name their
principalinstead oforganizerId. A venue receivingorganizerId: "<its venue id>"would have been wrong.
Discovery
What this key can do.
/v1any valid keyWhat this key can reach
Returns the scopes on the calling key, the endpoint paths, the available webhook event types, the paging and filtering conventions and the current rate limits. Useful as a connectivity and permission check — it requires a valid key but no particular scope.
The endpoints map is derived from the route table the server
dispatches from, not maintained beside it, so it cannot describe a
surface the server does not serve.
Request
curl https://europe-west3-venued.cloudfunctions.net/publicApi/v1 \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200Discovery document
401unauthorized— missing, malformed, unknown or revoked key.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
/v1/meany valid keyWho this key is
The principal this key acts as, and the scopes it was minted with.
Why this is separate from GET /v1
GET /v1 answers what can I reach — the endpoint map, the paging
conventions, the rate limits — and is the same for everybody. This
answers who am I, which is per key and is the thing an integration
branches on: a no-code step that must decide whether to offer event
actions or venue actions needs the principal, not the endpoint table.
Requires a valid key but no particular scope. A key that cannot tell you what it is cannot be debugged by the person holding it, and "which account is this key for" is the first question anybody asks when an integration has written to the wrong place.
Request
curl https://europe-west3-venued.cloudfunctions.net/publicApi/v1/me \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200The calling principal
401unauthorized— missing, malformed, unknown or revoked key.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
Events
/v1/eventsevents:readList events
Newest first, by startTime descending, and pageable with cursor.
Which events depends on the key: an organiser key lists the organiser's own events; a venue key lists the events at its address (see What a venue sees above).
⚠️ An event with no stored startTime is not returned. Nothing
reachable is hidden by that — an event without a start is not on the
site, in the app or in search either, and this API will not create
one.
With updated_after the order changes to updatedAt ascending; see
the conventions above.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer, 1–100, default 50 | Clamped to 100. A missing, non-numeric, zero or negative value becomes the default of 50 rather than an error. |
cursor | query | string | The It is anchored to a specific row of a specific ordering, and it is
rejected with |
updated_after | query | string | Only rows whose ⚠️ This changes the ordering to |
Request
curl https://europe-west3-venued.cloudfunctions.net/publicApi/v1/events \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200Events owned by this organiser, newest first
400unsupported_parameter— a query parameter this endpoint does not accept.invalid_cursor— a malformed cursor, one belonging to a different ordering, or one anchored to a row that no longer exists.invalid_argument—updated_afterwas not ISO 8601 or epoch ms.401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope— the key is valid but lacks the scope.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
/v1/eventsevents:writeCreate a draft or unlisted event
Creates an event owned by the calling organiser.
Idempotency-Key is required. A retried request carrying a key that
already succeeded replays the stored response verbatim rather than
creating a second event. A key whose first attempt FAILED is treated as
fresh and re-run — only successful results are recorded — so a failed
create is safe to retry with the same key. Keys are scoped per organiser
and retained 7 days.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
Idempotency-Keyrequired | header | string | Any opaque string you generate per logical operation — a UUID is the usual choice. Scoped to your organiser account and retained 7 days. |
Request
curl -X POST https://europe-west3-venued.cloudfunctions.net/publicApi/v1/events \
-H "Authorization: Bearer vnd_live_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"title": {
"EN": "Sunrise Run & Rave"
},
"startTime": "2026-11-21T18:00:00Z"
}'Responses
201Created
400idempotency_key_required— noIdempotency-Keyheader.invalid_argument—startTimemissing or unparseable, orendTimeunparseable.401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope, orforbiddenwhenvisibilityis anything other thandraftorunlisted.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
/v1/events/{eventId}events:readFetch one event
⚠️ An event belonging to a different organiser returns 404 not_found,
not 403. That is deliberate: a 403 would confirm the id exists.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
eventIdrequired | path | string |
Request
curl https://europe-west3-venued.cloudfunctions.net/publicApi/v1/events/{eventId} \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200The event
401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope— the key is valid but lacks the scope.404not_found. Also returned for a resource that exists but belongs to a different organiser — see the note onGET /v1/events/{eventId}.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
/v1/events/{eventId}events:writeUpdate an event
Merges the writable fields of the body into the event. Fields outside
the writable list are dropped silently, not rejected — so a body of
nothing but server-owned keys is a 400 invalid_argument ("No writable
fields in the request body"), which is usually the sign of a typo'd
field name.
No Idempotency-Key is required: a PATCH of the same body is naturally
idempotent.
If-Match makes the edit conditional. Send the ETag you got from
GET /v1/events/{eventId} and the write applies only if nothing has
changed since; otherwise it is refused with 412 precondition_failed
and nothing is written. Without the header the write applies
unconditionally, exactly as before — this is opt-in protection against
two editors overwriting each other, not a new requirement.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
eventIdrequired | path | string | |
If-Match | header | string | An |
Request
curl -X PATCH https://europe-west3-venued.cloudfunctions.net/publicApi/v1/events/{eventId} \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200The updated event
400invalid_argument— no writable fields in the body, orstartTime/endTimeunparseable.401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope, orforbiddenwhenvisibilityis anything other thandraftorunlisted.404not_found. Also returned for a resource that exists but belongs to a different organiser — see the note onGET /v1/events/{eventId}.412precondition_failed— theIf-Matchyou sent does not match the resource's currentETag, so somebody else changed it after you read it. Nothing was written. Re-read the resource, reapply your change to the new version, and retry.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
Orders
/v1/events/{eventId}/ordersorders:readConfirmed orders for one event
Only orders with status: "confirmed" are returned — pending, failed and
abandoned checkouts are not visible through this API.
Newest first, by createdAt descending, and pageable with cursor.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
eventIdrequired | path | string | |
limit | query | integer, 1–100, default 50 | Clamped to 100. A missing, non-numeric, zero or negative value becomes the default of 50 rather than an error. |
cursor | query | string | The It is anchored to a specific row of a specific ordering, and it is
rejected with |
updated_after | query | string | Only rows whose ⚠️ This changes the ordering to |
Request
curl https://europe-west3-venued.cloudfunctions.net/publicApi/v1/events/{eventId}/orders \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200Confirmed orders for this event, newest first
400unsupported_parameter— a query parameter this endpoint does not accept.invalid_cursor— a malformed cursor, one belonging to a different ordering, or one anchored to a row that no longer exists.invalid_argument—updated_afterwas not ISO 8601 or epoch ms.401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope— the key is valid but lacks the scope.404not_found. Also returned for a resource that exists but belongs to a different organiser — see the note onGET /v1/events/{eventId}.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
/v1/ordersorders:readConfirmed orders across all of this organiser's events
Newest first (createdAt descending). Confirmed orders only — pending,
failed and abandoned checkouts are never visible here.
This is the poll source a "new order" trigger in Zapier or Make needs;
the order.confirmed webhook is the push counterpart. A robust
integration usually wants both: the webhook for latency, and
?updated_after= to backfill whatever the receiver was down for.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer, 1–100, default 50 | Clamped to 100. A missing, non-numeric, zero or negative value becomes the default of 50 rather than an error. |
cursor | query | string | The It is anchored to a specific row of a specific ordering, and it is
rejected with |
updated_after | query | string | Only rows whose ⚠️ This changes the ordering to |
Request
curl https://europe-west3-venued.cloudfunctions.net/publicApi/v1/orders \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200Confirmed orders, newest first
400unsupported_parameter— a query parameter this endpoint does not accept.invalid_cursor— a malformed cursor, one belonging to a different ordering, or one anchored to a row that no longer exists.invalid_argument—updated_afterwas not ISO 8601 or epoch ms.401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope— the key is valid but lacks the scope.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
Venues
For a venue key — the place, and what happens at it.
/v1/venuesevents:readThe venue this key is, and the places it is
A venue key's own record, with its locations resolved.
⚠️ Always exactly one entry today. A venue key's principal IS a venue, so "list" is one row. It carries the page envelope anyway, for the same reason every other list does: one mapping in a no-code tool beats one per endpoint.
url is built from the venue id, not its slug. Venue slug
uniqueness is not enforced — the Studio editor writes the field
directly — so a slug URL can resolve to a different venue. The slug is
published as a field for display; it is not the link.
Request
curl https://europe-west3-venued.cloudfunctions.net/publicApi/v1/venues \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200The venue, with its locations
401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope— the key is valid but lacks the scope.404not_found. Also returned for a resource that exists but belongs to a different organiser — see the note onGET /v1/events/{eventId}.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
Webhooks
/v1/webhookswebhooks:readList webhook subscriptions
⚠️ The secret is returned here in plaintext. Treat this response as a
credential.
Request
curl https://europe-west3-venued.cloudfunctions.net/publicApi/v1/webhooks \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200Subscriptions
401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope— the key is valid but lacks the scope.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
/v1/webhookswebhooks:writeSubscribe to events
Creates a subscription and returns its signing secret. Store the
secret now — it is also readable from GET /v1/webhooks, but it is
what verifies every delivery and it should be treated as a credential
from the moment it exists.
A maximum of 10 subscriptions per account is enforced.
A venue key may subscribe to event.published only — an event at
its address became public. order.confirmed is refused with
403 forbidden rather than silently dropped: it carries a buyer's name
and email, which is the organiser's record and not the building's, and
a subscription quietly narrower than the one you asked for would only
announce itself by never firing.
Request
curl -X POST https://europe-west3-venued.cloudfunctions.net/publicApi/v1/webhooks \
-H "Authorization: Bearer vnd_live_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"url": "https://example.com/hooks/venued",
"events": [
"order.confirmed"
],
"description": "Push confirmed orders into the CRM"
}'Responses
201Created. Carries the signing secret.
400invalid_argument—urlmissing, unparseable, not https, or not a public host; oreventscontains no known type.401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope, orforbiddenwhen a venue key asks for an event type a venue may not receive (anything butevent.published).409limit_reached— already 10 subscriptions.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
/v1/webhooks/{webhookId}webhooks:writeDelete a webhook subscription
Removes the subscription and returns
{"data": {"id": "…", "deleted": true}}. Deliveries already in flight
are not recalled.
Metered as a write (120/min), like every other request that changes something.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
webhookIdrequired | path | string |
Request
curl -X DELETE https://europe-west3-venued.cloudfunctions.net/publicApi/v1/webhooks/{webhookId} \
-H "Authorization: Bearer vnd_live_your_key_here"Responses
200Deleted
400invalid_argument— nowebhookIdin the path.401unauthorized— missing, malformed, unknown or revoked key.403insufficient_scope— the key is valid but lacks the scope.404not_found. Also returned for a resource that exists but belongs to a different organiser — see the note onGET /v1/events/{eventId}.429rate_limited. 600 reads/min and 120 writes/min in a fixed 60-second window.POST,PATCHandDELETEare writes;GETandHEADare reads.⚠️ The budget belongs to the organiser account, not to the key. It was metered per key, which meant minting a second key doubled the allowance — so there was no ceiling, only a formality. Two changes, both breaking, both made while the API has no keys in existence: this one, and
DELETEmoving from the read budget to the write budget.⚠️ The limit is a soft ceiling under burst. The counter is a single Firestore document per key per window, and contention means a hard burst can push somewhat past the nominal figure before 429s begin. It also fails open: if the counter cannot be read, the request is allowed rather than refused.
Webhook events
These are sent to you: Venued POSTs the envelope below to every endpoint subscribed to that event type.
order.confirmedA ticket order or RSVP was confirmed
Sent once, on the pending → confirmed transition of an order. It does
not re-fire if the order is written again while already confirmed.
event.publishedAn event became public
Sent once, the first time an event transitions to public. Making an
already-public event public again does not re-fire it.