Skip to content
OpenReserve

OpenReserve for AI agents

An AI assistant can work in a OpenReserve workspace for the person it helps. A workspace owner or admin creates an agent key in Settings, API keys; the agent sends it with every request and can only do what the key allows.

OpenReserve API for agents

Contract 3.2.0. Base URL: https://api.openreserve.app. OpenAPI: https://api.openreserve.app/v1/agent/openapi.json

Connecting

A person who administers a tenant creates an agent key in the dashboard (API keys → kind "agent", with the permissions you need) and gives it to you. Send it on every call as Authorization: Bearer ak_…. Never print it or put it in a URL. An agent key acts for one tenant, only within its permissions, and only on the operations listed here.

Conventions

  • JSON in and out. Ids are prefixed (ten_…, usr_…). Times are ISO-8601 in UTC.
  • Lists take ?cursor=&limit= and answer { items, nextCursor }; pass nextCursor back for the next page.
  • Send a new Idempotency-Key (a UUID) with every POST, PATCH and DELETE. Retrying with the same key never repeats the action.
  • Errors answer { "error": { "code", "message", "outcome", "remediation" } }. outcome: not_committed means nothing changed.

Ask the person first

  • PATCH /v1/tenants/{tenantId} — Update a tenant's settings
  • DELETE /v1/tenants/{tenantId}/media/{mediaId} — Delete a file
  • POST /v1/tenants/{tenantId}/domains — Connect a custom domain
  • DELETE /v1/tenants/{tenantId}/domains/{domainId} — Disconnect a custom domain
  • POST /v1/tenants/{tenantId}/payments/charges — Take a payment on the tenant's account (direct charge)
  • POST /v1/tenants/{tenantId}/payments/charges/{paymentId}/refunds — Refund a payment, fully or in part
  • DELETE /v1/tenants/{tenantId}/notes/{noteId} — Delete a note
  • POST /v1/tenants/{tenantId}/booking/locations — Add a location
  • PATCH /v1/tenants/{tenantId}/booking/locations/{locationId} — Change a location
  • POST /v1/tenants/{tenantId}/booking/services — Add a service
  • PATCH /v1/tenants/{tenantId}/booking/services/{serviceId} — Change a service
  • DELETE /v1/tenants/{tenantId}/booking/services/{serviceId} — Remove a service from the menu
  • POST /v1/tenants/{tenantId}/booking/staff — Add a staff member
  • PATCH /v1/tenants/{tenantId}/booking/staff/{staffId} — Change a staff member (profile, login link, services performed)
  • DELETE /v1/tenants/{tenantId}/booking/staff/{staffId} — Archive a staff member who left
  • PATCH /v1/tenants/{tenantId}/booking/policy — Change the shop's booking policy
  • PUT /v1/tenants/{tenantId}/booking/staff/{staffId}/hours — Replace a staff member's weekly hours
  • PUT /v1/tenants/{tenantId}/booking/locations/{locationId}/hours — Replace a location's opening hours
  • POST /v1/tenants/{tenantId}/booking/time-off — Add time off (a staff member) or a closure (a location)
  • DELETE /v1/tenants/{tenantId}/booking/time-off/{timeOffId} — Remove time off or a closure
  • POST /v1/tenants/{tenantId}/booking/appointments — Book a held time for a client
  • POST /v1/tenants/{tenantId}/booking/appointments/{appointmentId}/reschedule — Move an appointment to another time (or staff member)
  • POST /v1/tenants/{tenantId}/booking/appointments/{appointmentId}/cancel — Cancel an appointment
  • POST /v1/tenants/{tenantId}/booking/clients — Create a client record
  • PATCH /v1/tenants/{tenantId}/booking/clients/{clientId} — Update client contact details or private notes

Operations

  • GET /v1/health — Check that the API is up. When: To check that the API is reachable and which contract version it serves.
  • GET /v1/app-config — Get client configuration (versions, features, sign-in client ids). When: Rarely: it describes app versions and sign-in client ids for the official apps.
  • GET /v1/public/tenants/{slug} — Get a tenant's public profile by slug. When: To read a tenant's public name and description from its slug.
  • GET /v1/public/domains/{host} — Find the tenant behind a verified custom domain. When: Rarely: it maps a custom domain to the tenant slug.
  • GET /v1/tenants/{tenantId} — Get a tenant. When: To read the tenant's name, slug, time zone and locale.
  • PATCH /v1/tenants/{tenantId} — Update a tenant's settings. When: When the person asks to rename the tenant or change its time zone or locale. Permission: tenant.manage. Ask the person first.
  • GET /v1/tenants/{tenantId}/members — List a tenant's members. When: To see who is on the team and their roles. Permission: members.view.
  • GET /v1/tenants/{tenantId}/roles — List the roles of a tenant (platform and vertical roles). When: To explain what each role can do, or before suggesting a role change. Permission: members.view.
  • GET /v1/tenants/{tenantId}/invites — List pending invites. When: To see who has been invited but has not joined yet. Permission: members.view.
  • GET /v1/tenants/{tenantId}/audit-log — Read a tenant's audit log (newest first). When: When the person asks who changed something, or what happened recently. Permission: audit.view.
  • POST /v1/tenants/{tenantId}/media/uploads — Start an upload (returns a presigned POST). When: To store a file for the workspace (first step; then send the file and call media.complete). Not when: Never make a file public unless the person asked for a public file (logo, product photo). Permission: media.manage.
  • POST /v1/tenants/{tenantId}/media/uploads/{uploadId}/complete — Finish an upload: check the file and store it. When: After sending the file to the upload URL. Permission: media.manage.
  • GET /v1/tenants/{tenantId}/media — List the workspace's files (newest first). When: To find a file the person mentions. Permission: media.view.
  • GET /v1/tenants/{tenantId}/media/{mediaId} — Get a file (with a fresh link for private files). When: To get a link to one file. Permission: media.view.
  • DELETE /v1/tenants/{tenantId}/media/{mediaId} — Delete a file. When: When the person explicitly asks to delete a file. Permission: media.manage. Ask the person first. Cannot be undone.
  • GET /v1/tenants/{tenantId}/domains — List the workspace's custom domains. When: To see which custom domains are connected and what DNS they still need. Permission: settings.manage.
  • POST /v1/tenants/{tenantId}/domains — Connect a custom domain. When: When the person wants their public pages on a domain they own. Not when: DNS changes happen at the domain owner’s provider: say what to add, then verify. Permission: settings.manage. Ask the person first.
  • POST /v1/tenants/{tenantId}/domains/{domainId}/verify — Check the DNS records of a custom domain. When: After the person says they added the DNS records. Permission: settings.manage.
  • DELETE /v1/tenants/{tenantId}/domains/{domainId} — Disconnect a custom domain. When: When the person explicitly asks to disconnect a domain. Permission: settings.manage. Ask the person first. Cannot be undone.
  • GET /v1/agent/guide — The guide for AI agents (markdown by default, JSON with ?format=json). When: First: it explains how to connect, what each operation is for, and when to ask the person.
  • GET /v1/agent/openapi.json — OpenAPI 3.1 document of the operations an agent may call. When: To generate tool definitions; x-agent-* fields say when to ask the person first.
  • GET /v1/billing/plans — List the plans tenants can subscribe to. When: To compare plans, their prices and what each one includes.
  • GET /v1/tenants/{tenantId}/billing/subscription — Get the tenant's plan, subscription status and entitlements. When: To check the tenant's plan, whether it is paid up, and what it includes.
  • GET /v1/tenants/{tenantId}/payments/account — Get the tenant's payments account and whether it can take payments. When: To check whether the tenant can take payments, or what Stripe still needs. Permission: payments.manage.
  • POST /v1/tenants/{tenantId}/payments/customers — Add one of the tenant's customers (to keep a card on file). When: Before saving a card for a customer of the tenant, when your vertical has none for them yet. Permission: payments.charge. Cannot be undone.
  • GET /v1/tenants/{tenantId}/payments/customers/{customerId} — Get a customer and their card on file. When: To see whether a customer has a card on file before charging it. Permission: payments.charge.
  • POST /v1/tenants/{tenantId}/payments/charges — Take a payment on the tenant's account (direct charge). When: When the person asks to charge a customer, e.g. a no-show fee to the card on file. Not when: Never to charge a card the customer did not agree to have charged. Permission: payments.charge. Ask the person first. Cannot be undone.
  • GET /v1/tenants/{tenantId}/payments/charges/{paymentId} — Get a payment. When: To check whether a payment succeeded, failed or was refunded. Permission: payments.charge.
  • POST /v1/tenants/{tenantId}/payments/charges/{paymentId}/refunds — Refund a payment, fully or in part. When: When the person asks to refund a payment. Permission: payments.refund. Ask the person first. Cannot be undone.
  • GET /v1/tenants/{tenantId}/notes — List notes (newest first). When: To find the team's notes before reading or changing one. Permission: notes.view.
  • POST /v1/tenants/{tenantId}/notes — Create a note. When: When the person asks you to write something down for the team. Permission: notes.manage.
  • GET /v1/tenants/{tenantId}/notes/{noteId} — Get a note. When: To read one note in full. Permission: notes.view.
  • PATCH /v1/tenants/{tenantId}/notes/{noteId} — Change a note. When: When the person asks you to edit a note. Not when: Never to rewrite a note the person did not ask about: earlier text is not kept. Permission: notes.manage. Cannot be undone.
  • DELETE /v1/tenants/{tenantId}/notes/{noteId} — Delete a note. When: When the person explicitly asks to delete a note. Permission: notes.manage. Ask the person first. Cannot be undone.
  • GET /v1/tenants/{tenantId}/booking/locations — List the shop's locations. When: To find a location id or a location time zone. Permission: booking.view.
  • POST /v1/tenants/{tenantId}/booking/locations — Add a location. When: When the owner asks you to change how the shop is set up. Permission: booking.setup.manage. Ask the person first.
  • PATCH /v1/tenants/{tenantId}/booking/locations/{locationId} — Change a location. When: When the owner asks you to change how the shop is set up. Permission: booking.setup.manage. Ask the person first.
  • GET /v1/tenants/{tenantId}/booking/services — List services (the menu), including ones not offered online. When: To find a service id, its duration, price and who performs it. Permission: booking.view.
  • POST /v1/tenants/{tenantId}/booking/services — Add a service. When: When the owner asks you to change how the shop is set up. Permission: booking.setup.manage. Ask the person first.
  • PATCH /v1/tenants/{tenantId}/booking/services/{serviceId} — Change a service. When: When the owner asks you to change how the shop is set up. Permission: booking.setup.manage. Ask the person first.
  • DELETE /v1/tenants/{tenantId}/booking/services/{serviceId} — Remove a service from the menu. When: When the owner explicitly removes a service. Permission: booking.setup.manage. Ask the person first. Cannot be undone.
  • GET /v1/tenants/{tenantId}/booking/staff — List staff members. When: To find a staff id and what they perform. Permission: booking.view.
  • POST /v1/tenants/{tenantId}/booking/staff — Add a staff member. When: When the owner asks you to change how the shop is set up. Permission: booking.setup.manage. Ask the person first.
  • PATCH /v1/tenants/{tenantId}/booking/staff/{staffId} — Change a staff member (profile, login link, services performed). When: When the owner asks you to change how the shop is set up. Permission: booking.setup.manage. Ask the person first.
  • DELETE /v1/tenants/{tenantId}/booking/staff/{staffId} — Archive a staff member who left. When: When the owner says someone left. Permission: booking.setup.manage. Ask the person first. Cannot be undone.
  • GET /v1/tenants/{tenantId}/booking/policy — Get the shop's booking policy. When: To explain notice, cancellation, reminder or fee rules. Permission: booking.view.
  • PATCH /v1/tenants/{tenantId}/booking/policy — Change the shop's booking policy. When: When the owner asks you to change how the shop is set up. Permission: booking.setup.manage. Ask the person first.
  • GET /v1/tenants/{tenantId}/booking/staff/{staffId}/hours — Get a staff member's weekly hours. When: To see when someone works each week. Permission: booking.view.
  • PUT /v1/tenants/{tenantId}/booking/staff/{staffId}/hours — Replace a staff member's weekly hours. When: When the owner tells you when someone works, is away, or when the shop is closed. Permission: booking.schedule.manage. Ask the person first.
  • GET /v1/tenants/{tenantId}/booking/locations/{locationId}/hours — Get a location's opening hours. When: To see when the shop is open. Permission: booking.view.
  • PUT /v1/tenants/{tenantId}/booking/locations/{locationId}/hours — Replace a location's opening hours. When: When the owner tells you when someone works, is away, or when the shop is closed. Permission: booking.schedule.manage. Ask the person first.
  • GET /v1/tenants/{tenantId}/booking/time-off — List time off and closures overlapping some dates. When: To see who is away or when the shop is closed. Permission: booking.view.
  • POST /v1/tenants/{tenantId}/booking/time-off — Add time off (a staff member) or a closure (a location). When: When the owner tells you when someone works, is away, or when the shop is closed. Permission: booking.schedule.manage. Ask the person first.
  • DELETE /v1/tenants/{tenantId}/booking/time-off/{timeOffId} — Remove time off or a closure. When: When the owner tells you when someone works, is away, or when the shop is closed. Permission: booking.schedule.manage. Ask the person first. Cannot be undone.
  • GET /v1/tenants/{tenantId}/booking/availability — Open slots for a service, for the front desk. When: Before booking or moving an appointment, to find a free time. Permission: booking.view.
  • POST /v1/tenants/{tenantId}/booking/holds — Hold a time while the front desk enters the client. When: First step of booking for the shop: hold the time, then book it with the client. Permission: booking.appointments.manage.
  • POST /v1/tenants/{tenantId}/booking/appointments — Book a held time for a client. When: After createHold, once you have the client and the shop agreed to the booking. Permission: booking.appointments.manage. Ask the person first.
  • GET /v1/tenants/{tenantId}/booking/appointments — Appointments starting on some dates (the calendar). When: To read the shop's calendar for a day or a week. Permission: booking.view.
  • GET /v1/tenants/{tenantId}/booking/appointments/{appointmentId} — Get an appointment. When: To read one appointment and its current version. Permission: booking.view.
  • POST /v1/tenants/{tenantId}/booking/appointments/{appointmentId}/reschedule — Move an appointment to another time (or staff member). When: When the shop or the client asks to move a booking (check availability first). Permission: booking.appointments.manage. Ask the person first.
  • POST /v1/tenants/{tenantId}/booking/appointments/{appointmentId}/cancel — Cancel an appointment. When: When asked to cancel a booking. Permission: booking.appointments.manage. Ask the person first. Cannot be undone.
  • GET /v1/tenants/{tenantId}/booking/customers — Search the shop's clients. When: To find an existing client before booking for them. Permission: booking.clients.view.
  • GET /v1/public/tenants/{slug}/booking/locations — A shop's locations open for online booking. When: To tell someone where a shop is and which time zone it books in.
  • GET /v1/public/tenants/{slug}/booking/services — A shop's services offered online, and its booking policy. When: To tell someone what a shop offers, for how long and at what price.
  • GET /v1/public/tenants/{slug}/booking/staff — A shop's staff who take online bookings. When: To tell someone who works at a shop and what each person does.
  • GET /v1/public/tenants/{slug}/booking/availability — Open slots for a service. When: To find when a service can be booked.
  • GET /v1/tenants/{tenantId}/booking/clients — List or search the shop's client directory. When: To find a client when acting for the shop. Permission: booking.clients.view.
  • GET /v1/tenants/{tenantId}/booking/clients/{clientId} — Read one client and their booking history. When: To read a client and their prior bookings for the shop. Permission: booking.clients.view.
  • POST /v1/tenants/{tenantId}/booking/clients — Create a client record. When: When the shop asks to add a client. Permission: booking.clients.manage. Ask the person first. Cannot be undone.
  • PATCH /v1/tenants/{tenantId}/booking/clients/{clientId} — Update client contact details or private notes. When: When the shop asks to correct a client record. Permission: booking.clients.manage. Ask the person first.

Errors

CodeStatusMeaningWhat to do
VALIDATION_FAILED400The request is invalid.Fix the fields listed in issues and send the request again.
UNAUTHENTICATED401Sign-in required.Send a valid access token or API key in the Authorization header (refresh the session if it expired).
FORBIDDEN403You do not have permission to do this.Ask an owner or admin of the tenant for the permission named in the message.
TENANT_NOT_FOUND404Tenant not found.Check the tenant id; you must be a member of the tenant (or hold one of its API keys).
IDEMPOTENCY_KEY_REUSED422This Idempotency-Key was already used for a different request.Use a new key for a new request; reuse a key only to retry the exact same request.
RATE_LIMITED429Too many requests.Wait the number of seconds in remediation.retryAfterSeconds (or Retry-After) and try again.
INTERNAL500Something went wrong on our side.Re-read the resource to see whether the change happened, then retry with the same Idempotency-Key.
UNAVAILABLE503The service is temporarily unavailable.Retry later with the same Idempotency-Key.
MEMBER_NOT_FOUND404Member not found.List the members and use one of their ids.
STRIPE_NOT_CONFIGURED503Stripe is not set up for this environment yet.The product's operator must store this stage's Stripe keys (docs/billing-and-payments.md); retry after that.
STRIPE_ERROR502Stripe could not complete the request.Retry with the same Idempotency-Key; if it keeps failing, look at the request in the Stripe Dashboard.
PLAN_UPGRADE_REQUIRED402The tenant's plan does not include this.Upgrade the plan (billing.checkout, or the billing portal for a paid plan), then retry.
PAYMENTS_NOT_ENABLED404Payments are not part of this product.Nothing to do: this product does not take payments for its tenants.
PAYMENTS_ACCOUNT_MISSING409The tenant has not set up payments yet.Create the payments account (POST …/payments/account), then finish onboarding in the dashboard.
PAYMENTS_ACCOUNT_NOT_READY409The payments account cannot take payments yet.Finish onboarding in the dashboard: Stripe still needs some details or is reviewing them.
PAYMENT_CUSTOMER_NOT_FOUND404Payment customer not found.Use the id returned when the customer was created.
PAYMENT_NOT_FOUND404Payment not found.Use the id of a payment of this tenant.
PAYMENT_CARD_MISSING409This customer has no card on file.Save a card first (…/card-setup), or take the payment with the customer present.
PAYMENT_NOT_REFUNDABLE409This payment cannot be refunded.Only succeeded payments with an amount left to refund can be refunded.
MEDIA_TOO_LARGE413This file is too large.Images (JPEG, PNG, WebP, GIF) up to 10 MB, PDFs up to 25 MB, videos (MP4, MOV) up to 200 MB.
UPLOAD_NOT_FOUND404This upload is unknown or has expired.Start a new upload (POST …/media/uploads) and send the file within 10 minutes.
UPLOAD_INCOMPLETE409The file has not arrived yet.POST the file to the upload URL first (every field, then the file as file), then complete again.
MEDIA_REJECTED422The file is not what the upload announced.Check the file type and size, then start a new upload with the real values.
MEDIA_NOT_FOUND404File not found.List the files and use one of their ids.
DOMAIN_NOT_ALLOWED400This domain cannot be connected.Use a domain you own, such as book.example.com: not one of ours, an IP address or a *.vercel.app name.
DOMAIN_TAKEN409This domain is already connected somewhere else.Remove it from the workspace that verified ownership or the other Vercel project, then add it again.
DOMAIN_LIMIT_REACHED409A workspace can connect at most 10 domains.Remove a domain you no longer use.
DOMAIN_NOT_FOUND404Domain not found.List the domains and use one of their ids.
CUSTOM_DOMAINS_UNAVAILABLE503Custom domains are not available right now.Try again in a few minutes; if it keeps failing, contact support.
NOTE_NOT_FOUND404Note not found.List the notes and use one of their ids.
LOCATION_NOT_FOUND404Location not found.Locations: List them and use one of their ids.
SERVICE_NOT_FOUND404Service not found.Services: List them and use one of their ids.
STAFF_NOT_FOUND404Staff member not found.Staff: List them and use one of their ids.
TIME_OFF_NOT_FOUND404Time off not found.Time off: List them and use one of their ids.
CUSTOMER_NOT_FOUND404Client not found.Clients: List them and use one of their ids.
APPOINTMENT_NOT_FOUND404Appointment not found.Appointments: List them and use one of their ids.
HOLD_NOT_FOUND404This hold does not exist or was released.Ask for availability again and pick one of the slots it returns. Then create a new hold.
LOCATION_REQUIRED400This shop has more than one location: say which one.Pass locationId (from the locations list).
SERVICE_NOT_OFFERED409That staff member does not offer this service online.Pick a staff member from the service's staffIds, or leave staffId out.
SLOT_UNAVAILABLE409That time cannot be booked (outside hours, too soon, too far ahead, or off the booking grid).Ask for availability again and pick one of the slots it returns.
SLOT_TAKEN409Someone else just booked that time.Ask for availability again and pick one of the slots it returns.
APPOINTMENT_NOT_CHANGEABLE409This appointment is not confirmed any more, so it cannot be moved or cancelled.Read the appointment. Book a new one if the client still wants to come.
VERSION_CONFLICT409The appointment changed since you read it.Read it again and retry with its current version as expectedVersion.
STAFF_HAS_APPOINTMENTS409This staff member has upcoming appointments.Move them to someone else or cancel them, then archive the profile.
MEMBERSHIP_ALREADY_LINKED409That login is already linked to another staff profile.Unlink it from the other profile first (membershipId: null).
HOURS_OVERLAP409Weekly hours overlap.Remove the overlap: one person (or one location) has one window at a time on a weekday.
BOOKING_HOLD_REFRESH_REQUIRED409This hold needs to be refreshed before checkout.Read availability and create a new hold with its holdCapability.
BOOKING_DEPOSIT_REQUIRED409A deposit is required before this booking can be confirmed.Reserve, prepare and start the deposit checkout, then await verified payment finalization.
CLIENT_CONTACT_CONFLICT409A client already uses that contact.Find the existing client or correct the email address or phone number.
CLIENT_VERSION_CONFLICT409The client changed since you read it.Read the client again and retry with its current version as expectedVersion.