Keys and auth

Organization and studio keys, scopes, the business header and allowed domains.

There is no anonymous access. Every request carries a key as a bearer token:

Authorization: Bearer shyni_sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

A missing, malformed, unknown or revoked key is one uniform answer, 401 INVALID_API_KEY.

Creating a key

You create an organization key in the portal under API keys. Give it a name of 1 to 100 characters, choose secret or publishable, test or live, and for a secret key at least one scope. A key is shown once; Shyni keeps only a hash, so a lost key cannot be recovered: revoke it and issue a new one. An organization has at most 20 active keys of each kind.

What a member may create depends on the role:

RoleTest keysLive keys
Owner, adminYesYes, once live mode is on
DeveloperYesNo

A live key needs live mode turned on for the organization; see Sandbox. A test key acts only on sandbox businesses, a live key only on live ones.

Choosing the business

An organization key works across all businesses of the organization. Name the one a request is for in the Shyni-Business header; GET /businesses lists the ids.

Shyni-Business: 5c1d8e0a-3f2b-4a76-9b0e-7d4c2a1f6e83

The refusals:

CodeStatusMeaning
BUSINESS_REQUIRED400A business endpoint was called without the header. Only the organization-level endpoints (/businesses, /studios, /webhook-endpoints, and /me for the organization itself) work without it.
BUSINESS_HEADER_NOT_ALLOWED400A studio key sent the header. Studio keys never choose a business.
BUSINESS_NOT_FOUND404The business does not exist, belongs to another organization, is archived, or its mode differs from the key's. The answer is the same in every case.
BILLING_SUSPENDED403A live key of an organization whose live mode was suspended for an unpaid monthly charge. Test keys keep working.

Secret and publishable

PrefixKindWhere it runs
shyni_sk_live_secretYour server only. Carries scopes.
shyni_pk_live_publishableA browser on the business's own website. Fixed allowance, no scopes.
shyni_sk_test_secretAs sk_live, acts on sandbox businesses.
shyni_pk_test_publishableAs pk_live, acts on sandbox businesses.

live or test is the mode of the key, set when it is created. A key works on a business only when its mode equals the business's mode. GET /me reports it as mode.

Scopes

A secret key carries one or more scopes, chosen when it is created.

ScopeGrants
catalog:readGET /services, GET /availability/starts, GET /availability/calendar, and the secret-key reads of drafts and settings: GET /catalog/draft/services, /catalog/draft/packages, /publish-state, /service-categories, /service-groups, /places, /discount-codes, /availability/blocks, /availability/day-policies, /availability/hours, /studio, /storefront, /images
orders:readGET /orders, GET /orders/{id}
customers:readGET /customers, GET /customers/{id}
orders:writePOST /orders, creating a booking, and POST /quotes, /quotes/batch, the price of a booking before it is made. It changes no existing order
orders:manageManaging orders that already exist: confirm, start, complete, cancel, no-show, ready, reschedule and its requests, work intervals, inspection, PATCH /orders/{id}, custom lines, booking links, review replies and reports
payments:writeMoney on an existing order: the deposit refund and the paid and refunded marks, POST /orders/{id}/payments and DELETE /orders/{id}/payments/{paymentId}
vouchers:readGET /gift-vouchers, GET /gift-vouchers/{code}, GET /gift-vouchers/{code}/pdf
vouchers:writePOST /gift-vouchers, /refund, /resend, and the deactivate, confirm-payment and cancel actions
catalog:writeServices, categories, configurator groups, questions, packages, places, discount codes, variant defaults, and POST /catalog/publish, DELETE /catalog/draft
availability:writeAvailability blocks, day policies and opening hours
storefront:writeThe studio page (description, FAQ, layout, theme, photos), POST /storefront/publish, DELETE /storefront/draft, and the photo library (/images)
settings:writePATCH /studio and the studio's operational settings under /studio/...
businesses:readGET /businesses, GET /businesses/{id}, GET /studios, GET /studios/{id}. Organization-level: no Shyni-Business header
businesses:managePOST /businesses, PATCH /businesses/{id}, …/archive, …/reset, POST /studios and …/owner-invite. Organization-level
workers:writePOST /workers, PATCH /workers/{id} and …/archive
payments:readGET /payments/gateway
payments:managePUT and DELETE /payments/gateway
webhooks:readGET /webhook-endpoints and GET /webhook-endpoints/{id}. Organization-level
webhooks:managePOST, PATCH and DELETE /webhook-endpoints. Organization-level

POST /publish publishes the catalog and the studio page together and needs both catalog:write and storefront:write.

Scopes are independent: no scope implies another. orders:write does not include orders:read, orders:manage or payments:write, and a *:write scope does not include the matching read; the list reads of drafts and settings need catalog:read. A key without the scope an endpoint needs gets 403 INSUFFICIENT_SCOPE. See Writing through the API for what a write does.

A key for a partner website that only takes bookings needs orders:write alone. It cannot cancel an order or refund a deposit.

GET /me is exempt for secret keys. It works with any valid secret key and tells you which scopes the key carries and its quota use. See Who am I.

Publishable keys in the browser

A publishable key has no scopes and its allowance cannot be widened: GET /services, GET /availability/starts, GET /availability/calendar, GET /studio, POST /quotes, POST /quotes/batch, POST /orders and POST /gift-vouchers/purchases. It never writes anything else. Every other endpoint, including /me, the other gift-voucher endpoints and every catalog, availability, studio and storefront write, answers 403 INSUFFICIENT_SCOPE. The list is exact: other methods on those paths (HEAD, say) and variants such as a trailing slash are refused the same way.

A publishable key is used from a browser on the business's own website, so the allowed websites must be on a list. There are two lists, and a request is accepted if its origin is on either:

  • the organization's list, in the portal under Settings → Allowed websites;
  • the list of the selected business, set with allowedDomains on PATCH /businesses/{id}; the portal shows it on the business page.

Each list holds up to 10 hostnames such as www.mypawsalon.com. A browser request carries an Origin header, and with a publishable key it is accepted only when the origin is https://<host> with <host> on a list. http://localhost works only when a list holds localhost; the organization's list takes no localhost, so list it on a sandbox business. Any other origin gets 403 ORIGIN_NOT_ALLOWED. An organization can issue publishable keys like secret ones; each key still names its business with Shyni-Business, and the key's mode must match the business.

An accepted request is answered with Access-Control-Allow-Origin set to that exact origin (never *) and Vary: Origin. Cookies are never allowed. The response exposes X-Quota-Limit, X-Quota-Used, X-Quota-Remaining, Retry-After and Idempotency-Key to your code.

The preflight (OPTIONS with an Origin header, on any /api/v1 path) needs no key. It answers 204 with Access-Control-Allow-Methods: GET, POST, Access-Control-Allow-Headers: Authorization, Content-Type, Idempotency-Key, Shyni-Business and Access-Control-Max-Age: 600. A request without an Origin header, such as from a server or curl, is not affected by the list.

Never a secret key in a browser

A request that carries an Origin header with a secret key is refused with 403 SECRET_KEY_IN_BROWSER. Use a publishable key in the browser and keep secret keys on your server. A key that has been exposed should be revoked and re-issued.

Personal data

An orders:read or customers:read key can read customer name, e-mail, phone and subject details (such as a dog's name and breed, or for auto detailing the car's plate, make and model). Whoever holds the key acts as a data processor for that data under the terms of the business it belongs to. The API redacts no field in v1. Keep keys in an environment variable or a secret manager, never in source control or logs.

Studio keys

A studio, a business with a Shyni admin of its own, issues its own keys in that admin. Such a key is bound to the studio, never sends Shyni-Business (the header is refused with BUSINESS_HEADER_NOT_ALLOWED) and needs the studio to be on a Pro subscription (403 PLAN_REQUIRED below it). Building for a studio covers working with a studio that uses Shyni and creating one for a client.

See Errors for every refusal and what to do about it.

On this page