The raw event feed behind the dashboard’s Events tab: every metered call, newest first, filterable by end user or event type and paged with limit / offset. The single-event endpoint adds metadata, the limit groups an event matched, and (when prompt logging is enabled for the app) the full prompt and response text.
List events
curl "https://www.vevee.org/api/v1/events?userId=user_abc123&limit=20&offset=0" \
-H "Authorization: Bearer sk_live_YOUR_KEY"Parameters
| Name | Type | Description | |
|---|---|---|---|
userId | optional | string | Only events from this end user. |
eventType | optional | string | Only events of this event type. |
limit | optional | number | 1 to 100. Defaults to 20. |
offset | optional | number | 0 to 10000. Defaults to 0. |
Paging is offset-based, not cursor-based: request limit=20&offset=0 for the first page, offset=20 for the next, and so on, up to the 10000 cap. Rows are ordered newest first by createdAt, so items can shift between pages if new events land while you paginate.
{
"ok": true,
"data": {
"events": [
{
"id": "evt_9f2ab1",
"endUserId": "user_abc123",
"eventType": "llm.tokens",
"quantity": 812,
"costCents": 24,
"matchStatus": "matched",
"createdAt": "2026-08-01T09:41:03.000Z",
"hasLog": true,
"promptPreview": "Summarize the attached transcript into five bullet points, focused on..."
},
{
"id": "evt_9f2ab0",
"endUserId": "user_abc123",
"eventType": "image.render",
"quantity": 1,
"costCents": 0,
"matchStatus": "matched",
"createdAt": "2026-08-01T09:12:47.000Z",
"hasLog": false,
"promptPreview": null
}
],
"limit": 20,
"offset": 0,
"logPromptsEnabled": true
}
}matchStatus is one of matched, matched_credits_only, unmatched, blocked, no_subscription, or released. logPromptsEnabled reflects the app’s current Log prompts setting at the time of the request, not a per-event flag: when it is false, every row in events has hasLog: false and promptPreview: null, regardless of whether a log was actually recorded for that event.
Get a single event
curl https://www.vevee.org/api/v1/events/evt_9f2ab1 \
-H "Authorization: Bearer sk_live_YOUR_KEY"{
"ok": true,
"data": {
"id": "evt_9f2ab1",
"endUserId": "user_abc123",
"eventType": "llm.tokens",
"quantity": 812,
"costCents": 24,
"matchStatus": "matched",
"createdAt": "2026-08-01T09:41:03.000Z",
"hasLog": true,
"promptPreview": "Summarize the attached transcript into five bullet points, focused on...",
"metadata": { "model": "gpt-4o", "direction": "output" },
"matchedGroupIds": ["lg_llm_tokens"],
"prompt": "Summarize the attached transcript into five bullet points, focused on action items.",
"response": "1. Ship the events endpoint.\n2. Update the docs.\n3. Run the full test suite.\n4. Grep for dashes.\n5. Commit.",
"errorCode": null
}
}metadata is the free-form object your app passed on track / reserve, or null when none was sent. matchedGroupIds lists the limit groups this event counted against; it is empty when matchStatus is not matched.
promptPreview on the list endpoint and prompt / response / errorCode on the detail endpoint are populated only when prompt logging is enabled in the app’s settings (the same log_promptsflag that gates the dashboard’s event-detail view). With the setting off, both fields are always null and hasLog is always false, even for events that do have a stored log. See track() for how to turn prompt logging on and pass prompt / response.not_found (404) covers two different situations, indistinguishably: an eventId that never existed, and one belonging to an excluded user. The caller cannot tell them apart, by design.Errors
invalid_request(400) - out-of-range or non-numericlimitoroffset.invalid_key(401) - bad or revoked API key.requires_secret_key(403) - apk_*key was used.not_found(404) - unknown or excludedeventId(single-event endpoint only).
list_events and get_event - see MCP server.