Changelog
Every change to the Shyni API contract, newest first.
Every change to the API contract is listed here, newest first. The rules behind it are in Versioning.
2026-11-04
Organizations, businesses and the portal:
- New guide Subject types and variants: what
an order's subject is, how a business defines its subject types and variants,
and how they reach
POST /orders. The quickstart now uses a General sandbox (a dog grooming salon). - New guide Building for a studio: use a studio key from a studio that already uses Shyni, or create a studio for a client and invite its owner.
- Sign up at dashboard.shyni.io. An organization owns businesses, and every new organization starts with a sandbox business.
- An organization key acts on a business named in the
Shyni-Businessheader; see Keys and auth. New refusals:400 BUSINESS_REQUIRED,400 BUSINESS_HEADER_NOT_ALLOWEDand404 BUSINESS_NOT_FOUND. - New scopes
businesses:read,businesses:manage,workers:write,payments:read,payments:manage,webhooks:readandwebhooks:manage. - The API moves to
https://api.shyni.io; the staging host stayshttps://api.shyni.dev. Test mode is free; see Pricing. test-modeis now Sandbox.
The reference now covers organizations, businesses, organization webhooks and the payment gateway:
- Businesses and
Studios: an organization key (without the
Shyni-Businessheader) creates, lists, changes and archives businesses and founds studios for clients. - Organization webhooks: one endpoint receives the events of all the organization's businesses.
- Payment gateway endpoints and new order, review and reschedule webhook events.
- New
403 BILLING_SUSPENDEDfor a live organization key whose organization was suspended for an unpaid monthly charge.
2026-10-31
Contract changes on /api/v1:
GETandPUT /subject-types: a studio of industryGENERICdefines its subject types (typed attributes,identityKeys,summaryKeys); a detailing studio returns the presetCARtype andPUTis409.- Breaking:
subject.attributesonPOST /ordersand booking links is now a map validated against the studio's type (forCAR:plate,make,model); the typedOrderCreateCarAttributesis gone. The order returnssubject {id, type, attributes, summary}. - New
400 INVALID_SUBJECTwithfieldnaming the attribute key. - Catalog variants gain
labelandcustomerPickable.
2026-10-30
Contract changes on /api/v1:
- API plan tiers are retired. Every key has one
limit: 600 requests per minute and, for secret keys, 150,000 requests per
month.
GET /meno longer returns the plan field.
2026-10-29
Contract changes on /api/v1:
DELETE /orders/{id}/inspection-photos/{photoId}is now stricter than adding a photo. It returns409 CONFLICTas soon as the studio has replied to the inspection (any reply, including "come" or "call"), or the term has started or the inspection is closed. Adding a photo stays allowed after a "come" or "call" reply.
2026-10-28
Contract changes on /api/v1:
- New
POST /orders/{id}/revivebrings aCANCELLEDorder back toCONFIRMED; the optional body takesplaceId,scheduledStartandnotifyCustomer(defaulttrue). It works only for an order the studio or the customer cancelled. A deposit that had gone back to the customer becomesNOT_REQUIRED, and a gift voucher is drawn again as far as its balance reaches. Errors:409 SLOT_UNAVAILABLE,409 TERM_IN_PAST(new code) and409 CONFLICT. It emits the new webhookorder.revived. - New
POST /orders/{id}/unreadytakes the ready mark back (readyAtbecomesnull) on aCONFIRMEDorIN_PROGRESSorder that has one; otherwise409 CONFLICT. It sends nothing to the customer and emits no webhook.
2026-10-27
Contract changes on /api/v1, made in place before the first release (the
versioning exception for the time before any
integration exists; it ends with the first release):
- Breaking: the order's
vehicleis nowsubject(order view andPOST /ordersbody). An unknown field such asvehicleis ignored on create, so an old request answers201with an order that has no car. - Breaking: the webhook
order.ready_for_pickupis noworder.ready. - Breaking: the
orders:writescope now only creates a booking (POST /orders) and prices one (POST /quotes,/quotes/batch). Managing existing orders moved to the neworders:managescope, and money on an order (deposit refund, payments) to the newpayments:writescope. A key stored withorders:writestays valid and simply gets narrower. See Keys and auth. POST /places/{id}/unarchiveanswers403when the studio is over its plan's place limit.
2026-10-26
Contract changes on /api/v1:
GET /studioreturnsterms(url,version,publishedAt), the studio's own terms and conditions; it is absent when the studio has none.POST /orderstakes an optionalacceptedTermsVersion, theterms.versionyou showed the customer. A version that is not the current one is409 TERMS_VERSION_STALE(new code); nothing is created. The order views returnacceptedTermsVersionwhen set.- Breaking: request bodies are strict. A property the endpoint does not define
is
400 UNKNOWN_FIELD(new code) withfieldnaming it, e.g.customer.foo, instead of being ignored.PATCH /studionow refuses the admin-only fields (bank account, currency, allowed domains, reference consent, team, billing, API keys, payment gateway,description) the same way. - New
POST /orders/{id}/no-showrecords a customer no-show: a studio cancel withcancellationReason: NO_SHOW, allowed only once the booked term has started. A paid deposit is not refunded automatically. Theorder.cancelledwebhook carries the same reason. POST /orderstakesattribution(utmSource,utmMedium,utmCampaign,utmTerm,utmContent,referrer,gclid,gbraid,wbraid,fbclid) andmetadata(string to string, capped). Both are returned in the order view, the create response and the webhooks.GET /availability/startsand/availability/calendartakeoptionAnswers=<questionId>:<optionId>[,...]. Starts beyond the one-year horizon are no longer offered; add-on-only selections get the same400 INVALID_INPUTasPOST /orders.ServiceViewgainedpricingMode,minAdvanceDays,multiDay,includes,imageandstorefrontVisible. A publishable key does not list services hidden from the storefront.GET /studioworks with a publishable key and returns the public studio view.- The spec's examples, required lists and
servers(the production and staging hosts) match the real behaviour.
Limits tightened on /api/v1:
- A publishable key is refused with
403 INSUFFICIENT_SCOPEon everything butGET /services,GET /availability/starts,GET /availability/calendar,GET /studio,POST /quotes,POST /quotes/batch,POST /ordersandPOST /gift-vouchers/purchases,HEADand trailing-slash variants included. - A request body over 64 KB is
413 FILE_TOO_LARGE;POST /imageswith a secret key keeps its 60 MB limit. - A
pagetoo large for a list to hold is400 INVALID_INPUTon fieldpage. serviceIdsonGET /availability/startsand/availability/calendartakes at most 10 ids.- The cancel
reasonis at most 500 characters. - A stored idempotent answer is replayed only to the API key that made the first request; another key of the studio reusing the
Idempotency-Keygets422 IDEMPOTENCY_KEY_MISMATCHand nothing is written.
Added for pricing, gift vouchers and free inspections:
POST /quotesprices one selection before booking (total, surcharges, deposit) without reserving anything;POST /quotes/batchprices up to 50 at once. See Price before booking.POST /gift-vouchers/purchasessells a gift voucher through the studio's payment gateway. See Gift vouchers online.- Free inspections:
GET /availability/starts?inspection=truereturns inspection windows,POST /orderstakesinspection: true,POST /orders/{id}/inspection-photosandDELETE /orders/{id}/inspection-photos/{photoId}manage the customer's photos, andPOST /orders/{id}/inspection/replyrecords the studio's answer (COME,CALL,POINTLESS). - Webhook
order.inspection_repliedwhen that answer changes. - The publishable key may call
GET /studio,POST /quotes,POST /quotes/batchandPOST /gift-vouchers/purchases.
Added for integrators who keep a copy of the orders:
- Order lines in
serviceLines[]carryserviceId,packageIdandoptionAnswers(questionId,optionId). - The order has
updatedAt.GET /orderstakesupdatedSince=andsortBy=scheduledStart|updatedAt. GET /orders/by-public-id/{publicId}returns one order by its public id.externalRefon the order, the customer and the vehicle: accepted onPOST /orders, returned in the views, filterable with?externalRef=onGET /ordersandGET /customers. A collision is409 CONFLICT.billing(company, company id, VAT id, address) onPOST /ordersand in the order view.- A paid deposit is the first item of
payments[];methodisGATEWAYorMANUAL, and payments have a newreferencefield. - Breaking:
depositStateisNOT_REQUIREDfor a zero deposit and for a cancelled order whose deposit was never paid. Such an order is no longerPENDING, so a filter onPENDINGno longer matches it.
2026-10-25
Additive changes to POST /orders:
- The per-studio budget (60 per hour) of the API is separate from the booking page's; the per-IP budget (10 per hour) stays shared.
- A publishable key at a studio that confirms orders manually can have at most
10 unconfirmed orders; the 11th is
429 PENDING_ORDERS_LIMIT(new code). - An unpaid order with a deposit holds the slot 30 minutes with card payment
through
paymentUrl, 3 hours with bank transfer; the response hasholdUntil. - An unpublished studio answers
409 STUDIO_NOT_PUBLISHED.
1.0
The first public version of the API, under /api/v1.