Skip to content

Studio back office

Everything so far was public. The endpoints on this page act for one studio and need a studio API key.

A studio owner or manager creates keys in Studio settings → API keys (it asks for their two-step verification code). The key is shown once; store it in your server’s secret settings.

Terminal window
curl -s https://api.mrcharles.app/api/v1/studios/$STUDIO_ID/site/bookings \
-H "Authorization: Bearer $MRC_KEY"
  • Restricted keys (rk_live_…, rk_test_…) carry only the scopes you pick. Use them for everything you can.
  • Secret keys (sk_live_…, sk_test_…) carry every scope of this studio’s API.
  • A key acts on its own studio only: any other studio id answers 404.
  • test keys work on the sandbox and PRE, live keys on production. A key used on the wrong one answers 403 KEY_ENV_MISMATCH.
  • Call these from your server. Never put a key in a web page or an app; browser CORS only allows our own apps anyway.
  • Keys cannot create other keys, see payouts, edit the website content, change the domain or prices: those stay in the dashboard.

Integrations that sign in to POST /auth/login with an owner’s or manager’s email and password are deprecated and will be removed 90 days after API keys launch (the date will be announced here and in the changelog). Move to an API key now:

  • A password gives a script the whole account (payouts, team, prices); a key gets only its scopes, on one studio.
  • A key can be rotated or revoked without changing anyone’s password, and it keeps working when the owner turns on two-step verification (password sign-in then needs a code).

Until then, a password sign-in that does not come from our own web or mobile apps is answered with these headers (RFC 9745 and RFC 8288):

Deprecation: @1792972800
Link: <https://developers.mrcharles.app/integrate/studio-api/>; rel="deprecation"; type="text/html"

@1792972800 is 2026-10-26, when the deprecation was announced. There is no Sunset header yet.

ScopeLets the key
site:readRead the website configuration, checklist and room booking settings
site:publishPublish and unpublish the website
bookings:readList and read bookings, guest contact details included
bookings:writemark_paid, mark_refunded, record_external_refund, no_show, complete, cancel, note
rooms:writeChange a room’s booking settings

availability:read, holds:write, customers:read, lessons:read and lessons:write exist for endpoints that are coming; no studio endpoint needs them yet.

A publishable key (pk_live_…) is meant for your website’s pages. It has no scopes and cannot call this API. Send it as X-MC-Key (the SDK’s publishableKey option) when your own frontend creates holds. Bookings made with it are recorded with your website as the channel. It only works from the exact origins you list when you create it (https://www.yourstudio.com, no paths or wildcards), and the captcha and the guest’s code stay mandatory. A page on any other origin gets 403 ORIGIN_NOT_ALLOWED.

  • Rotate creates a replacement with the same scopes. The old key keeps working for 7 days, then answers 401 KEY_EXPIRED.
  • Revoke stops a key at once (within 30 seconds everywhere).
  • Each key shows when it was last used.
StatusCodeMeaning
401KEY_INVALIDNot a key we know (typo, wrong environment prefix, deleted)
401KEY_REVOKEDRevoked by the studio
401KEY_EXPIREDRotated more than 7 days ago: use the replacement
403KEY_ENV_MISMATCHA test key on production, or a live key elsewhere
403SCOPE_MISSINGThe key lacks the scope (details.scope)
403KEY_ROUTE_NOT_ALLOWEDKeys cannot call this endpoint
403ORIGIN_NOT_ALLOWEDA publishable key used from an origin it does not list
404RESOURCE_NOT_FOUNDThe studio in the path is not the key’s
429RATE_LIMIT_EXCEEDEDThe key’s per-minute limit (600 by default)

A key acts for the member who created it, within its scopes. If that member leaves the studio or loses the owner/manager role, actions that need the role stop working: create a new key from a current owner or manager. Rotating a key keeps the member it acts for; Settings → API keys shows that member on every key (actsAs in the list).

Today’s bookings into your own dashboard

Terminal window
curl -s "https://api.mrcharles.app/api/v1/studios/$STUDIO_ID/site/bookings?from=2026-10-08&to=2026-10-08" \
-H "Authorization: Bearer $MRC_KEY"

Each item carries the guest’s name, phone/email, times, price, payment state and the studio’s own notes.

Mark a booking paid when your till closes

Terminal window
curl -s -X POST ".../site/bookings/$BOOKING_ID/mark_paid" \
-H "Authorization: Bearer $MRC_KEY" -H 'Content-Type: application/json' \
-d '{"note":"Cash, closing shift"}'

Actions: mark_paid, mark_refunded, record_external_refund, no_show, complete, cancel, note. Every one is recorded in the booking’s event trail with the member who did it.

Open or close online booking for a room

Terminal window
curl -s -X PUT ".../rooms/$ROOM_ID/booking-settings" \
-H "Authorization: Bearer $MRC_KEY" -H 'Content-Type: application/json' \
-d '{"onlineEnabled":true,"minMinutes":60,"maxMinutes":240,"stepMinutes":30,
"paymentModes":["card","on_site"],"depositPercent":30,"cancelNoticeHours":24,
"instructions":{"es":"Llama al timbre 2."},"photos":[]}'

The response includes blockers — the reasons a room still is not bookable (no price, no hours, inactive, studio unverified).

Full list in the studio endpoints reference.

Creating studios and rooms, uploading media, and the lessons / bands / venues side of Mr Charles are not exposed publicly yet. If you need them, tell us what for — that is how this list shrinks.