> ## Documentation Index
> Fetch the complete documentation index at: https://docs.r28.ai/charter/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Charter works for any HTTP API, including the user's own. The packs are examples of the result, not the limit: an API with no pack is declared the same way, following https://raw.githubusercontent.com/r28ai/charter/main/docs/.mintlify/skills/declaring-charter-tools/SKILL.md.
> Charter is for agents that act in customers' accounts: every call is checked field by field before it's sent, the app says whose account each call is for, and the same declarations list what each tool can reach. https://docs.r28.ai/charter/llms.txt says what it is and lists every page.

# Luma

> Create and run events: guests, tickets, coupons, email blasts, calendars, contacts, memberships and webhooks.

74 tools
API key

```python luma_example.py {10} theme={null}
import asyncio
import os

from charter.packs import luma

luma.configure(api_key=os.environ["LUMA_API_KEY"])


async def main():
    going = await luma.events_guests_list.ainvoke(event_id="evt-...", approval_status="approved")


asyncio.run(main())
```

Luma runs event pages and the calendars that list them. This API is how a
program does what an organizer does in the app: create and update events, add
and approve guests, issue ticket types and coupons, email the guest list, and
manage the calendar's contacts, tags, admins and memberships.

The pack was drafted from Luma's own
[OpenAPI document](https://public-api.luma.com/openapi.json) by
`scripts/openapi_to_pack.py`, so every parameter, enum member and description
is Luma's, word for word. What a spec cannot carry — the rules Luma states in
prose, the sentences a blank parameter needed, the limits below — was added in
review.

## Authenticating

**Get a key:** at [luma.com/calendar/manage/api-keys](https://luma.com/calendar/manage/api-keys) choose the calendar and generate a key — it reaches that calendar only, and the API needs a Luma Plus subscription — then `export LUMA_API_KEY=…`.

This pack takes an API key in `x-luma-api-key`, and [`configure()`](https://docs.r28.ai/charter/charter/reference/configuration#configure) is optional when `$LUMA_API_KEY` is set.

That key serves every call the process makes. For an application whose users each connect their own account, hand [`configure()`](https://docs.r28.ai/charter/charter/reference/configuration#configure) a `credential_provider` instead — a [`SubjectProvider`](https://docs.r28.ai/charter/charter/reference/credentials#subjectprovider) that answers per user — and each call carries the credential of the user [`use_subject`](https://docs.r28.ai/charter/charter/reference/credentials#use_subject) names. [Your users' accounts](https://docs.r28.ai/charter/charter/auth/your-users.md) says how each pack's users connect.

A calendar key reaches the calendar it was made on and nothing else, so the
`calendars_*` tools act on that calendar and only `calendars_update` asks for its
ID.

An organization key reaches the `organizations_*` tools. Where Luma documents
choosing one of the organization's calendars — approving or rejecting a
submission — it is a header, and which calendar a call acts on is your decision,
not the model's, so pass it per call rather than as an argument:

```python theme={null}
await luma.calendars_events_approve.ainvoke(
    {"calendar_event_id": "calev-..."}, headers={"x-luma-calendar-id": "cal-..."}
)
```

## The client

> [!NOTE]
>
> [`oauth_tool_factory`](https://docs.r28.ai/charter/charter/reference/factories#oauth_tool_factory) is the whole client: a thin wrapper over `httpx` that attaches your key and these endpoint constants to each request. No vendor SDK enters your dependency tree.

```python Without the pack theme={null}
import os

from charter import oauth_tool_factory
from charter.auth import StaticTokenProvider

api_key = os.environ["LUMA_API_KEY"]

luma_api_client = oauth_tool_factory(
    base_url="https://public-api.luma.com/",
    provider="luma",
    credential_provider=StaticTokenProvider(api_key),
    # the token is not sent in Authorization
    token_header="x-luma-api-key",
    pack="luma",
    body_format="json",
    query_format="repeat",
    body_case="snake",
    query_case="snake",
    path_case="snake",
    # this API reports failure with an HTTP status code
    envelope=None,
)
```

```python With the pack theme={null}
import os

from charter.packs import luma

luma.configure(api_key=os.environ["LUMA_API_KEY"])

# The base URL, the casing, the envelope and the pagination are
# already declared. 74 tools, ready to hand to a model:
tools = luma.TOOLS
```

### Paging through a list

A cursor belongs to the tool that returns it, so it is declared on that tool's builder call:

```python luma_pagination.py theme={null}
calendars_events_list = luma_api_client(
    name="calendars_events_list",
    args_schema=CalendarsEventsListRequest,
    method="GET",
    url_template="v1/calendars/events/list",
    pagination=Pagination(
        cursor_field="next_cursor",
        cursor_param="pagination_cursor",
        more_field="has_more",
    ),
)
```

> [!NOTE]
>
> Pagination is declared on `calendars_events_list`, `events_guests_list`, `images_search`, `calendars_contacts_list`, `events_coupons_list`, `calendars_coupons_list`, `memberships_tiers_list`, `webhooks_list`, `organizations_calendars_list` and `organizations_events_list`. The other 64 take no cursor.

Reads are `GET`s with query parameters and every write is a `POST`. Luma versions
each route on its own, so `/v1/` and `/v2/` sit side by side and the version is
part of each tool's URL. Failure is an HTTP status — `429` past the rate limit of
200 requests a minute per calendar key — and the ten list tools page on
`has_more`, sending `next_cursor` back as `pagination_cursor`.

## Limits

* **`null` cannot be sent.** Charter omits an unset field rather than sending
  `null`, so what Luma clears with `null` — an event's `font`, a registration
  question's library `source`, a calendar's `location`, a ticket type's
  `max_per_guest` — can be set through these tools but not cleared.
* **Uploading an image is two steps, and the second is not a tool.**
  `images_create_upload_url` returns an `upload_url` to `PUT` the bytes to, which
  is a file transfer to Luma's CDN rather than an API call.
* **`events_create` and `events_update` are large**, about 22KB of schema each,
  mostly themes, fonts and the thirteen kinds of registration question. A
  [projection](https://docs.r28.ai/charter/charter/tools/projections.md) keeps what an agent uses.

## Tools

Each is a [`Tool`](https://docs.r28.ai/charter/charter/reference/tool), called with
[`ainvoke`](https://docs.r28.ai/charter/charter/reference/tool#tool-ainvoke) as in the snippet above.

Events

[events\_getGET
Return details about an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_get.md)

[events\_guests\_getGET
Get detailed information for an event guest by looking them up by their ID.](https://docs.r28.ai/charter/charter/packs/luma/events/events_guests_get.md)

[events\_guests\_listGET
Get list of guests who have registered or been invited to an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_guests_list.md)

[events\_coupons\_listGET
List all coupons that have been created for an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_coupons_list.md)

[events\_ticket\_types\_listGET
List all ticket types for an event](https://docs.r28.ai/charter/charter/packs/luma/events/events_ticket_types_list.md)

[events\_ticket\_types\_getGET
Get a single ticket type by ID](https://docs.r28.ai/charter/charter/packs/luma/events/events_ticket_types_get.md)

[events\_blasts\_listGET
List the blasts (emails to guests) on an event, newest first.](https://docs.r28.ai/charter/charter/packs/luma/events/events_blasts_list.md)

[events\_blasts\_getGET
Get a blast by ID.](https://docs.r28.ai/charter/charter/packs/luma/events/events_blasts_get.md)

[events\_createPOST
Create an event on the calendar.](https://docs.r28.ai/charter/charter/packs/luma/events/events_create.md)

[events\_updatePOST
Update an event by its ID.](https://docs.r28.ai/charter/charter/packs/luma/events/events_update.md)

[events\_guests\_update\_statusPOST
Update a guest’s status.](https://docs.r28.ai/charter/charter/packs/luma/events/events_guests_update_status.md)

[events\_guests\_update\_ticketsPOST
Add or remove tickets from an existing guest.](https://docs.r28.ai/charter/charter/packs/luma/events/events_guests_update_tickets.md)

[events\_guests\_send\_invitesPOST
Send guests an invite to an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_guests_send_invites.md)

[events\_guests\_addPOST
Add guests to the event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_guests_add.md)

[events\_hosts\_addPOST
Add a host to an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_hosts_add.md)

[events\_hosts\_updatePOST
Update a host's permissions or visibility on an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_hosts_update.md)

[events\_hosts\_removePOST
Remove a host from an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_hosts_remove.md)

[events\_coupons\_createPOST
Create a coupon that can be applied when a guest is registering for an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_coupons_create.md)

[events\_coupons\_updatePOST
Change how many more times an event coupon can be used, or the window it is valid in.](https://docs.r28.ai/charter/charter/packs/luma/events/events_coupons_update.md)

[events\_ticket\_types\_createPOST
Create a new ticket type for an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_ticket_types_create.md)

[events\_ticket\_types\_updatePOST
Update an existing ticket type configuration](https://docs.r28.ai/charter/charter/packs/luma/events/events_ticket_types_update.md)

[events\_ticket\_types\_deletePOST
Soft delete a ticket type.](https://docs.r28.ai/charter/charter/packs/luma/events/events_ticket_types_delete.md)

[events\_blasts\_createPOST
Email a message to an event's guests now, or at `scheduled_for`.](https://docs.r28.ai/charter/charter/packs/luma/events/events_blasts_create)

[events\_blasts\_updatePOST
Edit a blast.](https://docs.r28.ai/charter/charter/packs/luma/events/events_blasts_update.md)

[events\_blasts\_deletePOST
Delete a blast.](https://docs.r28.ai/charter/charter/packs/luma/events/events_blasts_delete.md)

[events\_cancel\_requestPOST
Request a cancellation token for an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_cancel_request.md)

[events\_cancelPOST
Cancel an event.](https://docs.r28.ai/charter/charter/packs/luma/events/events_cancel.md)

Calendars

[calendars\_getGET
Get information about the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_get.md)

[calendars\_events\_listGET
Every event and API key on Luma is managed by a [Luma Calendar](https://help.luma.com/p/luma-calendar-overview).](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_events_list)

[calendars\_contact\_tags\_listGET
List the contact tags on the calendar, with the IDs that apply, unapply, update and delete them.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contact_tags_list.md)

[calendars\_event\_tags\_listGET
List the event tags on the calendar, with the IDs that apply, unapply, update and delete them.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_event_tags_list.md)

[calendars\_admins\_listGET
List all admins for the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_admins_list.md)

[calendars\_events\_lookupGET
See if an event already exists on the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_events_lookup.md)

[calendars\_contacts\_listGET
List the calendar's contacts, optionally narrowed by search text, contact tags, or membership tier and status, and sorted by the column you choose.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contacts_list.md)

[calendars\_coupons\_listGET
List all coupons that have been created for a calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_coupons_list.md)

[calendars\_coupons\_createPOST
Create a coupon that can be applied to any event that is managed by the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_coupons_create.md)

[calendars\_coupons\_updatePOST
Change how many more times a calendar coupon can be used, or the window it is valid in.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_coupons_update.md)

[calendars\_contacts\_importPOST
Import contacts to the calendar, so they can be invited to events and sent newsletters.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contacts_import.md)

[calendars\_contacts\_blockPOST
Block a contact so they can’t follow your calendar or join its events.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contacts_block.md)

[calendars\_contacts\_removePOST
Remove a contact from your calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contacts_remove.md)

[calendars\_contacts\_restorePOST
Restore a blocked or removed contact, returning them to your active contacts.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contacts_restore.md)

[calendars\_contact\_tags\_createPOST
Create a contact tag on the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contact_tags_create.md)

[calendars\_contact\_tags\_updatePOST
Rename a contact tag or change its color.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contact_tags_update.md)

[calendars\_contact\_tags\_deletePOST
Delete a contact tag from the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contact_tags_delete.md)

[calendars\_contact\_tags\_applyPOST
Apply a tag to existing calendar contacts.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contact_tags_apply.md)

[calendars\_contact\_tags\_unapplyPOST
Unapply a tag from calendar contacts.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_contact_tags_unapply.md)

[calendars\_event\_tags\_createPOST
Create an event tag on the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_event_tags_create.md)

[calendars\_event\_tags\_updatePOST
Rename an event tag or change its color.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_event_tags_update.md)

[calendars\_event\_tags\_deletePOST
Delete an event tag from the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_event_tags_delete.md)

[calendars\_event\_tags\_applyPOST
Apply a tag to events on the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_event_tags_apply.md)

[calendars\_event\_tags\_unapplyPOST
Unapply a tag from events on the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_event_tags_unapply.md)

[calendars\_events\_addPOST
Add or submit an existing event (on Luma or on an external platform) to the Luma calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_events_add.md)

[calendars\_events\_approvePOST
Approve a pending event submission on your calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_events_approve.md)

[calendars\_events\_rejectPOST
Reject a pending event submission on your calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_events_reject.md)

[calendars\_admins\_addPOST
Add admins to the calendar.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_admins_add.md)

[calendars\_updatePOST
Update a calendar's settings.](https://docs.r28.ai/charter/charter/packs/luma/calendars/calendars_update.md)

Miscellaneous

[users\_get\_selfGET
Get the Luma user the API key belongs to.](https://docs.r28.ai/charter/charter/packs/luma/miscellaneous/users_get_self.md)

[entities\_lookupGET
Look up an event or calendar by its slug, Luma URL, or permanent public path such as `event/evt-...`, `e/evt-...`, or `calendar/cal-...`.](https://docs.r28.ai/charter/charter/packs/luma/miscellaneous/entities_lookup)

[places\_searchGET
Search Google Maps for a place and get up to 5 candidates.](https://docs.r28.ai/charter/charter/packs/luma/miscellaneous/places_search.md)

[images\_searchGET
Search Luma’s gallery of stock event cover images by keyword.](https://docs.r28.ai/charter/charter/packs/luma/miscellaneous/images_search.md)

[images\_create\_upload\_urlPOST
Get a URL to upload a JPEG or PNG to Luma's CDN.](https://docs.r28.ai/charter/charter/packs/luma/miscellaneous/images_create_upload_url.md)

Memberships

[memberships\_tiers\_listGET
List the calendar's membership tiers, including hidden ones (see is\_hidden).](https://docs.r28.ai/charter/charter/packs/luma/memberships/memberships_tiers_list.md)

[memberships\_members\_addPOST
Add a user to a membership tier.](https://docs.r28.ai/charter/charter/packs/luma/memberships/memberships_members_add.md)

[memberships\_members\_update\_statusPOST
Update a member's membership status.](https://docs.r28.ai/charter/charter/packs/luma/memberships/memberships_members_update_status.md)

Webhooks

[webhooks\_listGET
List all webhook endpoints for the calendar.](https://docs.r28.ai/charter/charter/packs/luma/webhooks/webhooks_list.md)

[webhooks\_getGET
Get details about a specific webhook endpoint.](https://docs.r28.ai/charter/charter/packs/luma/webhooks/webhooks_get.md)

[webhooks\_createPOST
Create a new webhook endpoint to receive event notifications.](https://docs.r28.ai/charter/charter/packs/luma/webhooks/webhooks_create.md)

[webhooks\_updatePOST
Update a webhook endpoint's event types or status (active/paused).](https://docs.r28.ai/charter/charter/packs/luma/webhooks/webhooks_update.md)

[webhooks\_deletePOST
Delete a webhook endpoint.](https://docs.r28.ai/charter/charter/packs/luma/webhooks/webhooks_delete.md)

Organizations

[organizations\_admins\_listGET
List all admins for the organization.](https://docs.r28.ai/charter/charter/packs/luma/organizations/organizations_admins_list.md)

[organizations\_calendars\_listGET
List all calendars belonging to the organization.](https://docs.r28.ai/charter/charter/packs/luma/organizations/organizations_calendars_list.md)

[organizations\_events\_listGET
List all events across all calendars belonging to the organization.](https://docs.r28.ai/charter/charter/packs/luma/organizations/organizations_events_list.md)

[organizations\_calendars\_createPOST
Create a new calendar within the organization.](https://docs.r28.ai/charter/charter/packs/luma/organizations/organizations_calendars_create.md)

[organizations\_events\_transfer\_calendarPOST
Transfer an event from its current managing calendar to a different calendar within the organization.](https://docs.r28.ai/charter/charter/packs/luma/organizations/organizations_events_transfer_calendar.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.