
Get the calendar this API key is scoped to: name, slug, public URL, description, images, and social handles. Luma API keys are scoped to exactly one calendar, so this takes no arguments. Returns the calendar ID needed by update_calendar.
Update the calendar's name, slug, description, avatar, or tint colour. Only the fields you pass are changed. Use get_calendar to find the calendar ID. Changing the slug changes the public URL and breaks existing links.
List the administrators of this calendar with their names and email addresses. Takes no arguments — the API key determines the calendar, and the endpoint is not paginated.
List events on this calendar with cursor pagination. Filter server-side by date range (before/after, ISO 8601), platform, submission status (approved or pending), and access level, and sort by startat. This is the main way to find event IDs for getevent, list_guests, and every other event tool.
Report whether an event is on this calendar. platform is required and selects the identifier: 'luma' takes eventid or eventapiid, 'external' takes url. To turn a luma.com link into an event ID, use lookupentity with the slug instead. Returns null when nothing matches.
Add an event to this calendar: an existing Luma event by eventid (platform='luma'), or an event hosted elsewhere by url (platform='external'). submissionmode='auto' approves it immediately, 'pending' leaves it for admin review. Returns the calendar-event ID for approvecalendarevent.
Approve an event submitted to this calendar, making it publicly visible on the calendar page. Use listcalendarevents with status='pending' to find submissions awaiting review. To decline one instead, use rejectcalendarevent.
Reject an event submitted to this calendar, optionally with a message to the submitter. Use listcalendarevents with status='pending' to find submissions awaiting review. To accept one instead, use approvecalendarevent.
List contacts on this calendar with cursor pagination. Filter server-side by free-text query, tag names (use listcontacttags), membership status, or membership tier (use listmembershiptiers), and sort by name, created_at, revenue, or event counts. Returns contact IDs and user IDs for the contact and tag tools.
Import contacts onto this calendar in bulk. Each contact is an object with email and optional name. Optionally apply contact tags to every imported contact — use listcontacttags to find tag names. Existing contacts are matched by email rather than duplicated.
Block a contact from registering for events on this calendar. Identify them by contactid or email — use listcontacts to find contact IDs. The record is kept and restorecontact brings it back unchanged, but a blocked contact disappears from listcontacts, which has no filter for blocked people. Use remove_contact to delete instead.
Remove a contact from this calendar. Identify them by contactid or email — use listcontacts to find contact IDs. Use restorecontact to bring them back. To keep the record but stop them registering, use blockcontact instead.
Restore a contact previously removed or blocked on this calendar, letting them register for events again. Identify them by contactid or email — use listcontacts to find contact IDs.
List discount coupons scoped to one event, with cursor pagination. Use listcalendarevents to find event IDs. Returns coupon codes for updateeventcoupon. For coupons that apply across every event on the calendar, use listcalendarcoupons.
Create a discount coupon on one event. discount requires a discounttype discriminator: {"discounttype": "percent", "percentoff": 20} or {"discounttype": "amount", "centsoff": 500, "currency": "usd"}. Optionally cap redemptions, set a validity window, or restrict it to one ticket type (listtickettypes for IDs). Use listcalendar_events for event IDs.
Update an event coupon's remaining redemption count or validity window. Identify it by event ID plus coupon code — use listeventcoupons to find codes. The discount amount cannot be changed; create a new coupon instead.
List discount coupons that apply across every event on this calendar, with cursor pagination. Returns coupon codes for updatecalendarcoupon. For coupons scoped to a single event, use listeventcoupons.
Create a discount coupon valid across every event on this calendar. discount requires a discounttype discriminator: {"discounttype": "percent", "percentoff": 20} or {"discounttype": "amount", "centsoff": 500, "currency": "usd"}. Optionally cap redemptions or set a validity window. To limit a coupon to one event, use createevent_coupon.
Update a calendar-wide coupon's remaining redemption count or validity window. Identify it by coupon code — use listcalendarcoupons to find codes. The discount amount cannot be changed; create a new coupon instead.
Get one Luma event by ID: schedule, location, capacity, visibility, hosts, and guest counts. Use listcalendarevents to find event IDs, or lookupcalendarevent to resolve a public URL to an ID. Some fields are omitted when the API key has view-only access to the event.
Create an event on the calendar this API key belongs to. Requires name, startat (ISO 8601), and an IANA timezone. Optionally set location, capacity, visibility, registration questions, and ticket types. Returns the new event ID for getevent, updateevent, and addguests.
Update an existing event. Only the fields you pass are changed. Set suppressnotifications=true to avoid emailing guests about a cosmetic edit. Use listcalendarevents to find event IDs. To change ticket prices use updateticket_type instead.
Step 1 of cancelling an event. Returns a single-use cancellationtoken plus the guest count and whether the event has paid tickets. Nothing is cancelled by this call. Pass the token to cancelevent to confirm. Use listcalendarevents to find event IDs.
Step 2 of cancelling an event: permanently cancels it and notifies guests. Requires the cancellationtoken from requesteventcancellation, which you must call first. Set shouldrefund=true to refund paid tickets. This cannot be undone.
List guests on an event with cursor pagination. Filter server-side by approvalstatus (approved, pendingapproval, invited, declined, waitlist, session) and sort by name, email, registeredat, or checkedinat. Use listcalendarevents to find event IDs. Returns guest IDs for getguest, updategueststatus, and updateguesttickets.
Get one guest on an event: approval status, registration answers, tickets held, check-in QR code, and ticket purchase orders. Use listguests to find guest IDs. Returns more detail than listguests, including eventticketorders.
Register one or more guests on an event directly, bypassing signup. Each guest is an object with email and optional name. Optionally assign a ticket type (use listtickettypes for IDs) and set approvalstatus. Set sendemail=false to add them without notifying them. To invite rather than register, use sendguestinvites.
Change a guest's approval status on an event: approve them, decline them, send them back to pendingapproval, or move them to the waitlist. Use listguests to find guest IDs. Set should_refund=true when declining a guest holding paid tickets. Moving a guest off approved releases their ticket; re-approving issues a new ticket and order, not the original.
Add or remove tickets held by a guest on an event. Use listtickettypes for ticket type IDs to add, and getguest to find the guest's existing ticket IDs to remove. Use listguests to find guest IDs. Set send_email=false to change tickets silently. A guest must keep at least one ticket: removing their last one is rejected.
Email event invitations to a list of people. Each guest is an object with email and optional name; an optional message is included in the invite. Invitees must accept to become registered. To register people directly without an invite, use add_guests instead.
Add a host to an event by email. accesslevel 'manager' can edit the event, 'check-in' can only check guests in, 'none' is listed publicly with no access; 'none' cannot be combined with isvisible=false. getevent lists only visible hosts, so a host added with isvisible=false will not appear there even though the call succeeded.
Change an existing host's access level or public visibility on an event. Identify the host by email. Use getevent to see current hosts and their access levels. To add a new host use addhost instead.
Remove a host from an event by email. The person keeps their Luma account and any guest registration; only their host role on this event is removed. Use get_event to see current hosts.
List the membership tiers on this calendar, with pricing, access rules, and the questions asked at signup. Returns tier IDs needed by addmembertotier and by the calendarmembershiptierid filter on list_contacts.
Add someone to a membership tier by email. Use listmembershiptiers to find tier IDs. Set skip_payment=true to comp a paid tier without collecting payment. Returns the membership ID and the status it was created in.
Approve or decline a calendar membership, identified by Luma user ID. Declining removes the membership outright rather than just marking it declined, and works on an already-approved member, so the person stops being a member. Use listcontacts with membershipstatus or calendarmembershiptierid to find member user IDs. To add a member, use addmembertotier.
Get the Luma user this API key belongs to: user ID, name, and email. Takes no arguments. Use this to confirm which account is connected. For the calendar the key is scoped to, use get_calendar.
Resolve a public Luma slug to the calendar, event, or user it belongs to. Pass just the slug from the URL, e.g. 'merge-events' for luma.com/merge-events, not the full URL. The result has a type field to branch on. Returns null when the slug matches nothing.
Get a pre-signed URL for uploading a JPEG or PNG to Luma's image host. PUT the raw image bytes to uploadurl, then pass the returned fileurl as coverurl on createevent or updateevent, or as avatarurl on update_calendar. The upload URL expires shortly after issue.
List the contact tags defined on this calendar, with their IDs, names, and colours. Takes no arguments. Returns tag IDs for updatecontacttag and deletecontacttag, and tag names for applycontacttag and the list_contacts tag filter.
Create a contact tag on this calendar for labelling people. Colour is one of cranberry, barney, red, green, blue, purple, yellow, orange. Returns the new tag ID. Use applycontacttag to attach it to contacts. For labelling events, use createeventtag.
Rename a contact tag or change its colour. Use listcontacttags to find tag IDs. Renaming a tag updates it everywhere it is applied.
Delete a contact tag from this calendar. The tag is removed from every contact carrying it; the contacts themselves are untouched. Use listcontacttags to find tag IDs. Deleting an ID that does not exist also reports success, so success is not proof the tag existed.
Apply a contact tag to contacts, identified by userids or emails. Use listcontacttags for tag names and listcontacts for user IDs. Returns how many contacts were tagged and how many were skipped because they already had the tag.
Remove a contact tag from contacts, identified by userids or emails. The tag itself still exists — use deletecontacttag to remove it entirely. Use listcontacts to find user IDs. Returns how many contacts were changed and how many were skipped.
List the event tags defined on this calendar, with their IDs, names, and colours. Takes no arguments. Returns tag IDs for updateeventtag and deleteeventtag, and tag names for applyeventtag. For tags on people, use listcontacttags.
Create an event tag on this calendar for grouping events. Colour is one of cranberry, barney, red, green, blue, purple, yellow, orange. Returns the new tag ID. Use applyeventtag to attach it to events. For labelling people, use createcontacttag.
Rename an event tag or change its colour. Use listeventtags to find tag IDs. Renaming a tag updates it everywhere it is applied.
Delete an event tag from this calendar. The tag is removed from every event carrying it; the events themselves are untouched. Use listeventtags to find tag IDs. Deleting an ID that does not exist also reports success, so success is not proof the tag existed.
Apply an event tag to one or more events. Use listeventtags for tag names and listcalendarevents for event IDs. Returns how many events were tagged and how many were skipped because they already had the tag.
Remove an event tag from one or more events. The tag itself still exists — use deleteeventtag to remove it entirely. Use listcalendarevents to find event IDs. Returns how many events were changed and how many were skipped.
List the ticket types on an event, including price, capacity, and sale window. Set includehidden=true to also return types hidden from the public event page. Use listcalendarevents to find event IDs. Returns ticket type IDs needed by addguests, updateguesttickets, and createeventcoupon.
Get one ticket type by ID: name, free or paid, price, currency, capacity, approval requirement, and sale window. Use listtickettypes to find ticket type IDs.
Add a ticket type to an event. Requires eventid, name, and type ('free' or 'paid'); paid types also need cents and currency. Use listcalendarevents to find event IDs. Returns the new ticket type ID for addguests and createeventcoupon.
Update a ticket type: price, name, capacity, sale window, visibility, or approval requirement. Only the fields you pass are changed. Use listtickettypes to find ticket type IDs. Existing tickets already sold keep the price they were bought at.
Delete a ticket type from an event. Use listtickettypes to find ticket type IDs. Consider updatetickettype with is_hidden=true instead if the type has already sold tickets.
Validate the Luma API key with a lightweight call to the current-user endpoint. Returns success plus a short message.
List the webhook subscriptions on this calendar with cursor pagination. Returns webhook IDs for getwebhook, updatewebhook, and delete_webhook. Each entry also carries the signing secret, so treat this response as sensitive and do not log or display it.
Get one webhook subscription: destination URL, subscribed event types, active or paused status, and the signing secret used to verify callbacks. Use list_webhooks to find webhook IDs.
Create a webhook subscription that POSTs to your URL when calendar activity happens. Event types include event.created, event.updated, event.canceled, guest.registered, guest.updated, ticket.registered, and the calendar. events; pass [''] for all. Returns the webhook ID and signing secret.
Update a webhook subscription: replace its event types, or pause and resume delivery via status. eventtypes replaces the existing list rather than adding to it. Use listwebhooks to find webhook IDs. The destination URL cannot be changed; create a new webhook instead.
Delete a webhook subscription permanently, stopping all callbacks to its URL. Use listwebhooks to find webhook IDs. To stop delivery temporarily instead, use updatewebhook with status='paused'.

In an mcp.json file, add the configuration below, and restart Cursor.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "url": "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
5 "headers": {
6 "Authorization": "Bearer yMt*****"
7 }
8 }
9 }
10}
11Open your Claude Desktop configuration file and add the server configuration below. You'll also need to restart the application for the changes to take effect.
Make sure Claude is using the Node v20+.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "yMt*****"
14 }
15 }
16 }
17}Open your Windsurf MCP configuration file and add the server configuration below.
Click on the refresh button in the top right of the Manage MCP server page or in the top right of the chat box in the box icon.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api.merge.dev/api/v1/tool-packs/<tool-pack-id>/registered-users/<registered-user-id>/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "<ah-production-access-key>"
14 }
15 }
16 }
17 }In Command Palette (Cmd+Shift+P on macOS, Ctrl+Shift+P on Windows), run "MCP: Open User Configuration".
You can then add the configuration below and press "start" right under servers. Enter the auth token when prompted.
Learn more in the official documentation ↗
1{
2 "inputs": [
3 {
4 "type": "promptString",
5 "id": "agent-handler-auth",
6 "description": "Agent Handler AUTH_TOKEN", // "yMt*****" when prompt
7 "password": true
8 }
9 ],
10 "servers": {
11 "agent-handler": {
12 "type": "stdio",
13 "command": "npx",
14 "args": [
15 "-y",
16 "mcp-remote@latest",
17 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
18 "--header",
19 "Authorization: Bearer ${input:agent-handler-auth}"
20 ]
21 }
22 }
23}Whether you're an engineer experimenting with agents or a product manager looking to add tools, you can get started for free now