Studio back office
Everything so far was public. The endpoints on this page act for one studio and need a studio API key.
Authentication: API keys
Section titled “Authentication: API keys”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.
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. testkeys work on the sandbox and PRE,livekeys on production. A key used on the wrong one answers403 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.
Owner password sign-in is deprecated
Section titled “Owner password sign-in is deprecated”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: @1792972800Link: <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.
Scopes
Section titled “Scopes”| Scope | Lets the key |
|---|---|
site:read | Read the website configuration, checklist and room booking settings |
site:publish | Publish and unpublish the website |
bookings:read | List and read bookings, guest contact details included |
bookings:write | mark_paid, mark_refunded, record_external_refund, no_show, complete, cancel, note |
rooms:write | Change 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.
Publishable keys (your website)
Section titled “Publishable keys (your website)”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 and revoke
Section titled “Rotate and revoke”- 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.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | KEY_INVALID | Not a key we know (typo, wrong environment prefix, deleted) |
| 401 | KEY_REVOKED | Revoked by the studio |
| 401 | KEY_EXPIRED | Rotated more than 7 days ago: use the replacement |
| 403 | KEY_ENV_MISMATCH | A test key on production, or a live key elsewhere |
| 403 | SCOPE_MISSING | The key lacks the scope (details.scope) |
| 403 | KEY_ROUTE_NOT_ALLOWED | Keys cannot call this endpoint |
| 403 | ORIGIN_NOT_ALLOWED | A publishable key used from an origin it does not list |
| 404 | RESOURCE_NOT_FOUND | The studio in the path is not the key’s |
| 429 | RATE_LIMIT_EXCEEDED | The key’s per-minute limit (600 by default) |
Who the key acts as
Section titled “Who the key acts as”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).
Typical automations
Section titled “Typical automations”Today’s bookings into your own dashboard
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
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
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.
What there is no API for yet
Section titled “What there is no API for yet”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.