Studio

Update the studio settings

PATCH
/api/v1/studio

Changes the listed fields; an omitted or null field stays as it is. Same rules as the admin settings screen: the basic info, deposit amounts and footer texts are written to the studio's draft and go live with the next publish, the cancellation / confirmation windows and the confirmation mode are effective at once. employeeCount above 0 needs the MAX plan (0 turns the pool off on every plan). Switching a deposit on needs a payment path (422 DEPOSIT_WITHOUT_PAYMENT_PATH). A wrong type or value is 400 with field. Not part of the request, and refused as 400 UNKNOWN_FIELD when sent: bank account, currency, allowed domains, reference consent, team, billing, API keys and the payment gateway - those change in the admin only. The rich-text description is not editable here either. Audited with the API key as the actor (deposit amounts, rounding mode). The answer is the whole studio as the draft now holds it. Requires the settings:write scope and an Idempotency-Key header.

Authorization

ApiKeyAuth settings:write
headerAuthorizationBearer <shyni_sk_live_*>

An API key, issued once and never retrievable again: an organization key in the developer portal, or a studio key in the studio's admin (Moje studio → API). Send as Authorization: Bearer shyni_sk_live_....

Scope: settings:write

Header Parameters

Idempotency-Key*string

Caller-chosen idempotency token for this write. A retry under the SAME key with the SAME body replays the first response; the SAME key with a DIFFERENT body is 422 IDEMPOTENCY_KEY_MISMATCH. See Idempotency above.

Lengthlength <= 64

Request Body

application/json
  1. body

Every field optional; omitted or null = unchanged. A blank string clears an optional text. contactEmail is not writable through the API - it receives invoices and legal notices, so a request carrying it is refused with 403 (FORBIDDEN); the studio owner changes it in the admin.

name?string
Lengthlength <= 255
phone?string
address?string
emailSignOff?string

Closing line of customer e-mails, shown above the studio name, address and phone. One line of plain text (no line breaks, no < or >); a blank string clears it.

Lengthlength <= 120
timezone?string
obor?string
Value in"DETAILING""PPF""KERAMIKA""MYCKA""TUNING""CALOUNENI"
tagline?string
Lengthlength <= 160
servicesHeading?string
Lengthlength <= 80
beforeAfterSubtitle?string
Lengthlength <= 120
gallerySubtitle?string
Lengthlength <= 120
packagesSubtitle?string
Lengthlength <= 120
publicEmail?string
ico?string
legalName?string
legalAddress?string
socialLinks?array<>

Replaces the list; an empty list removes all links.

Itemsitems <= 4
vatPayer?boolean
priceRoundingMode?string
Value in"NONE""PSYCHOLOGICAL"
depositAmountMode?string
Value in"FIXED""PERCENT"
depositAmount?integer
Formatint64
Range0 <= value
depositPercent?integer
Range1 <= value <= 100
depositMinAmount?integer
Formatint64
Range0 <= value
knownCarDepositWaived?boolean
employeeCount?integer

0 turns the pool off; above 0 needs the MAX plan.

Range0 <= value <= 99
turnoverMinutes?integer
Range0 <= value <= 480
inspectionMinutes?integer
Range1 <= value <= 240
cancellationCutoffHours?integer
Range0 <= value <= 168
confirmWithinHours?integer
Range1 <= value <= 168
confirmMode?string
Value in"MANUAL""AUTO"

Response Body

The studio settings.

application/json
  1. response

The studio's basic info and operational settings as the draft holds them. Draft-staged: name, phone, address, texts, footer, VAT, rounding, deposit amounts, employee pool, buffers - live after the next publish (hasUnpublishedChanges). Effective at once: contact e-mail, timezone, obor, booking pause, deposit collection mode, reminders, review mail, Google review link, employee rights, confirmation mode and the cancellation / confirmation windows.

id*string
slug*string
name*string
contactEmail*string
phone?string|null
address?string|null
emailSignOff?|

The studio's own closing line of customer e-mails (e.g. "Těším se, Franta"), shown above the studio name, address and phone. Plain text, one line. Null = none. Draft-staged. Not part of the public profile.

Lengthlength <= 120
timezone*string
obor?|
Value in"DETAILING""PPF""KERAMIKA""MYCKA""TUNING""CALOUNENI"null
currency*string

ISO 4217 code of every amount of the studio. Read-only here.

tagline?string|null
servicesHeading?string|null
beforeAfterSubtitle?string|null
gallerySubtitle?string|null
packagesSubtitle?string|null
publicEmail?string|null
ico?string|null
legalName?string|null
legalAddress?string|null
socialLinks*array<>
vatPayer*boolean
priceRoundingMode*string
Value in"NONE""PSYCHOLOGICAL"
depositAmountMode*string
Value in"FIXED""PERCENT"
depositAmount*integer

Minor units of currency.

Formatint64
depositPercent*integer
depositMinAmount*integer

Minor units of currency.

Formatint64
knownCarDepositWaived*boolean
employeeCount?|

Employee pool; null = the constraint is off.

turnoverMinutes*integer
inspectionMinutes*integer
cancellationCutoffHours*integer
confirmWithinHours*integer
confirmMode*string
Value in"MANUAL""AUTO"
bookingPaused*boolean
bookingPausedAt?|

ISO-8601 instant.

bookingPauseNote?string|null
depositCollectionMode*string
Value in"MANUAL""ONLINE""BOTH"
returnRemindersEnabled*boolean
reviewRequestEmailEnabled*boolean
googleReviewUrl?string|null
employeesConfirmAndHandOver*boolean
hasUnpublishedChanges*boolean
terms?

The studio's current terms and conditions. The whole terms object is absent when the studio has none (nothing to show, nothing to send back). Show the customer a link to url, then send version as acceptedTermsVersion in POST /orders.

Example Request
curl -X PATCH 'https://api.shyni.io/api/v1/studio' \  -H 'Authorization: Bearer shyni_sk_test_YOUR_KEY' \  -H 'Idempotency-Key: 7f3c9a52-1d4e-4b86-a0c7-5e2b9d8f6a13' \  -H 'Content-Type: application/json' \  -d '{}'

Response 200

The studio settings.

{  "id": "string",  "slug": "string",  "name": "string",  "contactEmail": "string",  "phone": "string",  "address": "string",  "emailSignOff": "string",  "timezone": "string",  "obor": "DETAILING",  "currency": "string",  "tagline": "string",  "servicesHeading": "string",  "beforeAfterSubtitle": "string",  "gallerySubtitle": "string",  "packagesSubtitle": "string",  "publicEmail": "string",  "ico": "string",  "legalName": "string",  "legalAddress": "string",  "socialLinks": [    {      "network": "INSTAGRAM",      "url": "string"    }  ],  "vatPayer": true,  "priceRoundingMode": "NONE",  "depositAmountMode": "FIXED",  "depositAmount": 0,  "depositPercent": 0,  "depositMinAmount": 0,  "knownCarDepositWaived": true,  "employeeCount": 0,  "turnoverMinutes": 0,  "inspectionMinutes": 0,  "cancellationCutoffHours": 0,  "confirmWithinHours": 0,  "confirmMode": "MANUAL",  "bookingPaused": true,  "bookingPausedAt": "string",  "bookingPauseNote": "string",  "depositCollectionMode": "MANUAL",  "returnRemindersEnabled": true,  "reviewRequestEmailEnabled": true,  "googleReviewUrl": "string",  "employeesConfirmAndHandOver": true,  "hasUnpublishedChanges": true,  "terms": {    "url": "http://example.com",    "version": 0,    "publishedAt": "2019-08-24T14:15:22Z"  }}

Response 400

A parameter, header or request body is missing, malformed, or out of range. A request body property the endpoint does not define answers UNKNOWN_FIELD instead, with field naming it.

{  "code": "INVALID_INPUT",  "message": "Parameter perPage must be between 1 and 100."}

Response 401

Missing, malformed, unknown, or revoked API key (INVALID_API_KEY).

{  "code": "INVALID_API_KEY",  "message": "Missing or invalid API key."}

Response 403

The key is valid but the request is refused. Branch on code: INSUFFICIENT_SCOPE (the key lacks the permission this endpoint requires), PLAN_REQUIRED (the studio is not on a plan that includes API keys, Pro and above), ORIGIN_NOT_ALLOWED, SECRET_KEY_IN_BROWSER, or DEMO_STUDIO on a write to the demo studio. See Authentication and Scopes above.

{  "code": "INSUFFICIENT_SCOPE",  "message": "This API key does not have the permission this endpoint requires."}

Response 422

The same Idempotency-Key was already used for a request with a different body, use a new key (see Idempotency above).

{  "code": "IDEMPOTENCY_KEY_MISMATCH",  "message": "This Idempotency-Key was already used for a different request. Use a new key."}

Response 429

Burst rate limit exceeded.

{  "code": "RATE_LIMITED",  "message": "Too many requests. Retry after the time given in the Retry-After header."}