{"openapi":"3.0.3","info":{"title":"BizKitHub API","description":"Mix of API endpoints used to power BizKitHub and related apps. Please contact at info@bizkithub.com for more information.","version":"1.0.0","contact":{"name":"Jan Barášek","url":"https://bizkithub.com","email":"info@bizkithub.com"}},"tags":[{"name":"external","description":"External endpoints"},{"name":"bff","description":"Internal CMS endpoints"}],"paths":{"/api/v1/address/list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":true}],"responses":{"200":{"description":"List of customer addresses.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of address objects.","type":"array","items":{"type":"object","allOf":[{"type":"object","required":["id"],"properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}},{"type":"object","required":["defaultAddress"],"properties":{"defaultAddress":{"description":"True if this is the default address for the contact.","type":"boolean"}}}]}},"itemCount":{"description":"Total number of addresses.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of address objects.","type":"array","items":{"type":"object","allOf":[{"type":"object","required":["id"],"properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}},{"type":"object","required":["defaultAddress"],"properties":{"defaultAddress":{"description":"True if this is the default address for the contact.","type":"boolean"}}}]}},"itemCount":{"description":"Total number of addresses.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of address objects.","type":"array","items":{"type":"object","allOf":[{"type":"object","required":["id"],"properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}},{"type":"object","required":["defaultAddress"],"properties":{"defaultAddress":{"description":"True if this is the default address for the contact.","type":"boolean"}}}]}},"itemCount":{"description":"Total number of addresses.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getApiV1AddressList","tags":["Address"],"summary":"List customer addresses","description":"Returns all addresses associated with a specific contact/customer. Each address includes type (delivery/billing/contact), personal/company details, and geographic information. The default address for the contact is marked with defaultAddress: true."}},"/api/v1/address/create":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}},"required":["id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}},"required":["id"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}},"required":["id"]}}}}},"operationId":"postApiV1AddressCreate","tags":["Address"],"summary":"Create new address","description":"Creates a new address for the specified contact. Address is automatically validated and normalized (street names, postal codes, etc.). If country is not provided, it defaults to the organisation default country. Returns the created address object with the generated ID.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}}}}}}},"/api/v1/address/update":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}},"required":["id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}},"required":["id"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ, similar in other countries).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}},"required":["id"]}}}}},"operationId":"postApiV1AddressUpdate","tags":["Address"],"summary":"Update existing address","description":"Updates an existing address identified by ID. Only provided fields will be updated, omitted fields remain unchanged. Address is automatically validated and normalized. Requires identityId to verify the address belongs to the contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identityId","id"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["identityId","id"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["identityId","id"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"Address external identifier (core__address.external_id).","type":"string"},"type":{"examples":["delivery","billing","contact"],"description":"Address type code. Common values: delivery, billing, contact, invoice.","type":"string"},"firstName":{"description":"First name of the person.","type":"string"},"lastName":{"description":"Last name of the person.","type":"string"},"companyName":{"description":"Company name (for business addresses).","type":"string"},"streetAddress":{"description":"Street name and house number.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"city":{"description":"City name.","type":"string"},"cityPart":{"description":"City district or part.","type":"string"},"stateRegion":{"description":"State or region name.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO in CZ).","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ in CZ, VAT ID in EU).","type":"string"},"notice":{"description":"Additional notes or delivery instructions.","type":"string"}}}}}}}},"/api/v1/address/load-address-by-company-registration-number":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":false},{"description":"Company registration number (IČO in CZ, similar in other countries).","examples":["12345678"],"schema":{"type":"string"},"in":"query","name":"companyRegistrationNumber","required":true},{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ","SK","US"],"schema":{"type":"string"},"in":"query","name":"country","required":false}],"responses":{"200":{"anyOf":[{"type":"object","properties":{"companyName":{"description":"Registered company name.","type":"string"},"streetAddress":{"description":"Registered street address.","type":"string"},"city":{"description":"Registered city.","type":"string"},"postalCode":{"description":"Registered postal code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number.","type":"string"}}},{"type":"object","required":["error"],"properties":{"error":{"description":"Error message if company was not found or registry unavailable.","type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"companyName":{"description":"Registered company name.","type":"string"},"streetAddress":{"description":"Registered street address.","type":"string"},"city":{"description":"Registered city.","type":"string"},"postalCode":{"description":"Registered postal code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number.","type":"string"}}},{"type":"object","required":["error"],"properties":{"error":{"description":"Error message if company was not found or registry unavailable.","type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","properties":{"companyName":{"description":"Registered company name.","type":"string"},"streetAddress":{"description":"Registered street address.","type":"string"},"city":{"description":"Registered city.","type":"string"},"postalCode":{"description":"Registered postal code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number.","type":"string"}}},{"type":"object","required":["error"],"properties":{"error":{"description":"Error message if company was not found or registry unavailable.","type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","properties":{"companyName":{"description":"Registered company name.","type":"string"},"streetAddress":{"description":"Registered street address.","type":"string"},"city":{"description":"Registered city.","type":"string"},"postalCode":{"description":"Registered postal code.","type":"string"},"country":{"examples":["CZ","SK","US"],"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number.","type":"string"}}},{"type":"object","required":["error"],"properties":{"error":{"description":"Error message if company was not found or registry unavailable.","type":"string"}}}]}}}}},"operationId":"getApiV1AddressLoad-address-by-company-registration-number","tags":["Address"],"summary":"Load address from business registry","description":"Fetches company details from official business registries based on company registration number. Returns company name, address, tax ID, and other registered information. Supports multiple countries (CZ, SK, and others). apiKey is optional for public access, but rate-limited."}},"/api/v1/bank/bank-account-status":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"- **Digits-only technical formats** (Czech accounts only):\n  - 20 digits BBAN: `BBBBPPPPPPAAAAAAAAAA` (bank 4 + prefix 6 + account 10).\n  - 22 digits: `CCBBBB...` where it represents `CZ` + check digits + BBAN without the country prefix.\n  - Without separators: `<account+optional prefix><bank>`, e.g. `20027706302010`.\n\nInvalid input: If the value contains letters but is not a valid/repairable IBAN, conversion fails and the endpoint returns `{ success: false }`.","examples":["CZ5420100000002002770630","2002770630/2010","000000-2002770630/2010","20027706302010"],"schema":{"type":"string"},"in":"query","name":"bankAccount","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success","iban","domestic"],"properties":{"success":{"description":"Operation result. When `true`, fields `iban` and `domestic` are present.","examples":[true],"type":"boolean"},"iban":{"examples":["CZ5420100000002002770630"],"description":"Canonical IBAN (uppercased, without spaces or separators).","type":"string"},"domestic":{"examples":["2002770630/2010"],"description":"Domestic bank account format derived from the IBAN (Czech format).","type":"string"}}},{"type":"object","required":["success"],"properties":{"success":{"description":"Operation result. When `false`, the provided `bankAccount` could not be converted to a valid IBAN.","examples":[false],"type":"boolean"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success","iban","domestic"],"properties":{"success":{"description":"Operation result. When `true`, fields `iban` and `domestic` are present.","examples":[true],"type":"boolean"},"iban":{"examples":["CZ5420100000002002770630"],"description":"Canonical IBAN (uppercased, without spaces or separators).","type":"string"},"domestic":{"examples":["2002770630/2010"],"description":"Domestic bank account format derived from the IBAN (Czech format).","type":"string"}}},{"type":"object","required":["success"],"properties":{"success":{"description":"Operation result. When `false`, the provided `bankAccount` could not be converted to a valid IBAN.","examples":[false],"type":"boolean"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success","iban","domestic"],"properties":{"success":{"description":"Operation result. When `true`, fields `iban` and `domestic` are present.","examples":[true],"type":"boolean"},"iban":{"examples":["CZ5420100000002002770630"],"description":"Canonical IBAN (uppercased, without spaces or separators).","type":"string"},"domestic":{"examples":["2002770630/2010"],"description":"Domestic bank account format derived from the IBAN (Czech format).","type":"string"}}},{"type":"object","required":["success"],"properties":{"success":{"description":"Operation result. When `false`, the provided `bankAccount` could not be converted to a valid IBAN.","examples":[false],"type":"boolean"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success","iban","domestic"],"properties":{"success":{"description":"Operation result. When `true`, fields `iban` and `domestic` are present.","examples":[true],"type":"boolean"},"iban":{"examples":["CZ5420100000002002770630"],"description":"Canonical IBAN (uppercased, without spaces or separators).","type":"string"},"domestic":{"examples":["2002770630/2010"],"description":"Domestic bank account format derived from the IBAN (Czech format).","type":"string"}}},{"type":"object","required":["success"],"properties":{"success":{"description":"Operation result. When `false`, the provided `bankAccount` could not be converted to a valid IBAN.","examples":[false],"type":"boolean"}}}]}}}}},"operationId":"getApiV1BankBank-account-status","tags":["bank"],"description":"Validate / normalize a bank account and return its canonical IBAN.\n\nThe endpoint accepts either an IBAN or a Czech domestic account format and tries to convert it to a valid IBAN.\n\n### Input\n- `bankAccount`: IBAN or CZ domestic account.\n- `apiKey`: standard API key.\n\n### Behavior\n- If `bankAccount` is a valid IBAN → returns it normalized (uppercased, without separators).\n- If it looks like a Czech IBAN with wrong check digits → recomputes and repairs the checksum.\n- If it is a Czech domestic account → converts it to CZ IBAN.\n- If conversion/validation fails → returns `{ success: false }`.\n\n### Output\n- `iban`: canonical IBAN (no spaces).\n- `domestic`: formatted domestic account representation (Czech format).\n\n### Notes\nThis endpoint does not verify whether the account actually exists at a bank; it only validates and normalizes the format."}},"/api/v1/branch/list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Page number (starting from 1).","schema":{"type":"string","default":"1"},"in":"query","name":"page","required":false},{"description":"Reference GPS latitude. When provided together with `longitude`, branches are ordered by great-circle distance from this point (ascending) and each item carries a `distanceKm` field. Branches without GPS coordinates are placed last.","examples":[50.0755],"schema":{"type":"number","minimum":-90,"maximum":90},"in":"query","name":"latitude","required":false},{"description":"Reference GPS longitude. Must be passed together with `latitude` — providing just one of the two is rejected.","examples":[14.4378],"schema":{"type":"number","minimum":-180,"maximum":180},"in":"query","name":"longitude","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","slug","name","branchType"],"properties":{"id":{"description":"Branch slug (used as identifier in /detail).","examples":["prague-central"],"type":"string"},"slug":{"description":"URL-safe unique branch slug.","examples":["prague-central"],"type":"string"},"name":{"description":"Branch display name.","examples":["Prague Central"],"type":"string"},"description":{"description":"Short branch description.","type":"string"},"url":{"description":"Public branch URL.","type":"string"},"latitude":{"description":"Branch GPS latitude.","examples":[50.0755],"type":"number"},"longitude":{"description":"Branch GPS longitude.","examples":[14.4378],"type":"number"},"mainPhotoUrl":{"description":"URL of the main public photo.","type":"string"},"addressSummary":{"description":"Short rendered address (street, ZIP, city).","examples":["Hlavní 1, 110 00, Praha"],"type":"string"},"branchType":{"description":"Branch kind. Defaults to \"own\" for historical rows.","examples":["own"],"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"distanceKm":{"description":"Great-circle distance from the reference GPS point in kilometres. Present only when both `latitude` and `longitude` query parameters are provided and the branch has GPS coordinates filled in.","examples":[3.42],"type":"number"}}}},"itemCount":{"description":"Total number of active branches.","examples":[12],"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","slug","name","branchType"],"properties":{"id":{"description":"Branch slug (used as identifier in /detail).","examples":["prague-central"],"type":"string"},"slug":{"description":"URL-safe unique branch slug.","examples":["prague-central"],"type":"string"},"name":{"description":"Branch display name.","examples":["Prague Central"],"type":"string"},"description":{"description":"Short branch description.","type":"string"},"url":{"description":"Public branch URL.","type":"string"},"latitude":{"description":"Branch GPS latitude.","examples":[50.0755],"type":"number"},"longitude":{"description":"Branch GPS longitude.","examples":[14.4378],"type":"number"},"mainPhotoUrl":{"description":"URL of the main public photo.","type":"string"},"addressSummary":{"description":"Short rendered address (street, ZIP, city).","examples":["Hlavní 1, 110 00, Praha"],"type":"string"},"branchType":{"description":"Branch kind. Defaults to \"own\" for historical rows.","examples":["own"],"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"distanceKm":{"description":"Great-circle distance from the reference GPS point in kilometres. Present only when both `latitude` and `longitude` query parameters are provided and the branch has GPS coordinates filled in.","examples":[3.42],"type":"number"}}}},"itemCount":{"description":"Total number of active branches.","examples":[12],"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","slug","name","branchType"],"properties":{"id":{"description":"Branch slug (used as identifier in /detail).","examples":["prague-central"],"type":"string"},"slug":{"description":"URL-safe unique branch slug.","examples":["prague-central"],"type":"string"},"name":{"description":"Branch display name.","examples":["Prague Central"],"type":"string"},"description":{"description":"Short branch description.","type":"string"},"url":{"description":"Public branch URL.","type":"string"},"latitude":{"description":"Branch GPS latitude.","examples":[50.0755],"type":"number"},"longitude":{"description":"Branch GPS longitude.","examples":[14.4378],"type":"number"},"mainPhotoUrl":{"description":"URL of the main public photo.","type":"string"},"addressSummary":{"description":"Short rendered address (street, ZIP, city).","examples":["Hlavní 1, 110 00, Praha"],"type":"string"},"branchType":{"description":"Branch kind. Defaults to \"own\" for historical rows.","examples":["own"],"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"distanceKm":{"description":"Great-circle distance from the reference GPS point in kilometres. Present only when both `latitude` and `longitude` query parameters are provided and the branch has GPS coordinates filled in.","examples":[3.42],"type":"number"}}}},"itemCount":{"description":"Total number of active branches.","examples":[12],"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getApiV1BranchList","tags":["branch"],"summary":"List public branches","description":"Returns a paginated list of active branches (pobočky) of the organisation. Each item carries only the publicly displayable subset of branch information (name, description, GPS, public URL, main photo, summary address, branch type). Use `/branch/detail?slug=…` to fetch the full public detail of a specific branch.\n\nWhen the `latitude` and `longitude` query parameters are both supplied, the result is sorted by great-circle (haversine) distance from that reference point ascending and each item carries an additional `distanceKm` field. Branches whose GPS coordinates are missing are placed at the end of the list."}},"/api/v1/branch/detail":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Branch slug.","examples":["prague-central"],"schema":{"type":"string"},"in":"query","name":"slug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Branch slug.","examples":["prague-central"],"type":"string"},"slug":{"examples":["prague-central"],"type":"string"},"name":{"examples":["Prague Central"],"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"latitude":{"examples":[50.0755],"type":"number"},"longitude":{"examples":[14.4378],"type":"number"},"branchType":{"description":"Branch kind declared by the operator. \"own\" = the organisation runs the branch directly; \"franchise\" = a third-party franchisee runs it under the organisation's brand; \"partner\" = a cooperating but independent business.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranch":{"type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the operational parent (regional flagship / HQ).","type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]}}},"operatingCompany":{"type":"object","properties":{"name":{"description":"Legal name of the entity operating this branch.","type":"string"},"companyRegistrationNumber":{"description":"Czech IČO (or local equivalent). Publicly listed in the business register.","type":"string"},"taxIdentificationNumber":{"description":"Czech DIČ / EU VAT ID (or local equivalent).","type":"string"}}},"establishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"termsAndConditions":{"description":"Terms & Conditions (VOP), Markdown source.","type":"string"},"complaintsProcedure":{"description":"Complaints procedure (Reklamační řád), Markdown source.","type":"string"},"privacyPolicy":{"description":"Privacy policy (GDPR), Markdown source.","type":"string"},"mainPhotoUrl":{"type":"string"},"address":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"}}},"openingHours":{"type":"object","required":["regular","exceptions"],"properties":{"regular":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday … 6 = Sunday.","type":"number"},"definition":{"description":"Time range definition (e.g. \"08:00-17:00\").","type":"string"},"description":{"type":"string"},"validFrom":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"exceptions":{"type":"array","items":{"type":"object","required":["date","isOpen"],"properties":{"date":{"description":"Exception date (ISO YYYY-MM-DD).","examples":["2026-12-24"],"type":"string"},"isOpen":{"type":"boolean"},"reason":{"type":"string"}}}}}},"emails":{"type":"array","items":{"type":"object","required":["email"],"properties":{"email":{"examples":["info@example.com"],"type":"string"},"role":{"type":"string"}}}},"phones":{"type":"array","items":{"type":"object","required":["phone"],"properties":{"phone":{"examples":["+420 777123456"],"type":"string"},"role":{"type":"string"}}}},"people":{"type":"array","items":{"type":"object","required":["role"],"properties":{"role":{"description":"Branch person role (e.g. owner, manager, custodian).","type":"string"},"customLabel":{"description":"Free-text label that overrides the role display.","type":"string"},"name":{"description":"Person display name.","type":"string"}}}}},"required":["id","slug","name","branchType","openingHours","emails","phones","people"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Branch slug.","examples":["prague-central"],"type":"string"},"slug":{"examples":["prague-central"],"type":"string"},"name":{"examples":["Prague Central"],"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"latitude":{"examples":[50.0755],"type":"number"},"longitude":{"examples":[14.4378],"type":"number"},"branchType":{"description":"Branch kind declared by the operator. \"own\" = the organisation runs the branch directly; \"franchise\" = a third-party franchisee runs it under the organisation's brand; \"partner\" = a cooperating but independent business.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranch":{"type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the operational parent (regional flagship / HQ).","type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]}}},"operatingCompany":{"type":"object","properties":{"name":{"description":"Legal name of the entity operating this branch.","type":"string"},"companyRegistrationNumber":{"description":"Czech IČO (or local equivalent). Publicly listed in the business register.","type":"string"},"taxIdentificationNumber":{"description":"Czech DIČ / EU VAT ID (or local equivalent).","type":"string"}}},"establishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"termsAndConditions":{"description":"Terms & Conditions (VOP), Markdown source.","type":"string"},"complaintsProcedure":{"description":"Complaints procedure (Reklamační řád), Markdown source.","type":"string"},"privacyPolicy":{"description":"Privacy policy (GDPR), Markdown source.","type":"string"},"mainPhotoUrl":{"type":"string"},"address":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"}}},"openingHours":{"type":"object","required":["regular","exceptions"],"properties":{"regular":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday … 6 = Sunday.","type":"number"},"definition":{"description":"Time range definition (e.g. \"08:00-17:00\").","type":"string"},"description":{"type":"string"},"validFrom":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"exceptions":{"type":"array","items":{"type":"object","required":["date","isOpen"],"properties":{"date":{"description":"Exception date (ISO YYYY-MM-DD).","examples":["2026-12-24"],"type":"string"},"isOpen":{"type":"boolean"},"reason":{"type":"string"}}}}}},"emails":{"type":"array","items":{"type":"object","required":["email"],"properties":{"email":{"examples":["info@example.com"],"type":"string"},"role":{"type":"string"}}}},"phones":{"type":"array","items":{"type":"object","required":["phone"],"properties":{"phone":{"examples":["+420 777123456"],"type":"string"},"role":{"type":"string"}}}},"people":{"type":"array","items":{"type":"object","required":["role"],"properties":{"role":{"description":"Branch person role (e.g. owner, manager, custodian).","type":"string"},"customLabel":{"description":"Free-text label that overrides the role display.","type":"string"},"name":{"description":"Person display name.","type":"string"}}}}},"required":["id","slug","name","branchType","openingHours","emails","phones","people"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Branch slug.","examples":["prague-central"],"type":"string"},"slug":{"examples":["prague-central"],"type":"string"},"name":{"examples":["Prague Central"],"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"latitude":{"examples":[50.0755],"type":"number"},"longitude":{"examples":[14.4378],"type":"number"},"branchType":{"description":"Branch kind declared by the operator. \"own\" = the organisation runs the branch directly; \"franchise\" = a third-party franchisee runs it under the organisation's brand; \"partner\" = a cooperating but independent business.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranch":{"type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the operational parent (regional flagship / HQ).","type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]}}},"operatingCompany":{"type":"object","properties":{"name":{"description":"Legal name of the entity operating this branch.","type":"string"},"companyRegistrationNumber":{"description":"Czech IČO (or local equivalent). Publicly listed in the business register.","type":"string"},"taxIdentificationNumber":{"description":"Czech DIČ / EU VAT ID (or local equivalent).","type":"string"}}},"establishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"termsAndConditions":{"description":"Terms & Conditions (VOP), Markdown source.","type":"string"},"complaintsProcedure":{"description":"Complaints procedure (Reklamační řád), Markdown source.","type":"string"},"privacyPolicy":{"description":"Privacy policy (GDPR), Markdown source.","type":"string"},"mainPhotoUrl":{"type":"string"},"address":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"}}},"openingHours":{"type":"object","required":["regular","exceptions"],"properties":{"regular":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday … 6 = Sunday.","type":"number"},"definition":{"description":"Time range definition (e.g. \"08:00-17:00\").","type":"string"},"description":{"type":"string"},"validFrom":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"exceptions":{"type":"array","items":{"type":"object","required":["date","isOpen"],"properties":{"date":{"description":"Exception date (ISO YYYY-MM-DD).","examples":["2026-12-24"],"type":"string"},"isOpen":{"type":"boolean"},"reason":{"type":"string"}}}}}},"emails":{"type":"array","items":{"type":"object","required":["email"],"properties":{"email":{"examples":["info@example.com"],"type":"string"},"role":{"type":"string"}}}},"phones":{"type":"array","items":{"type":"object","required":["phone"],"properties":{"phone":{"examples":["+420 777123456"],"type":"string"},"role":{"type":"string"}}}},"people":{"type":"array","items":{"type":"object","required":["role"],"properties":{"role":{"description":"Branch person role (e.g. owner, manager, custodian).","type":"string"},"customLabel":{"description":"Free-text label that overrides the role display.","type":"string"},"name":{"description":"Person display name.","type":"string"}}}}},"required":["id","slug","name","branchType","openingHours","emails","phones","people"]}}}}},"operationId":"getApiV1BranchDetail","tags":["branch"],"summary":"Get public branch detail","description":"Returns the full publicly displayable detail of a single active branch identified by `slug`. Includes address (without internal delivery notes), opening hours (regular + exceptions), public e-mails and phones, branch type, parent branch reference, operating company (name + IČO + DIČ — public business-register information), public legal documents (Terms & Conditions, complaints procedure, privacy policy) and the list of associated people (role and display name only).\n\nInternal data (internal code, internal description, staff instructions, AI system prompt, internal billing contact, attached calendars / products / locks, monetary write-offs) is deliberately excluded from this endpoint."}},"/api/v1/calendar/add-event":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"eventId":{"examples":["fqdjnvzrfqjcsmvyhgjirjtvftknayzx"],"type":"string"}},"required":["eventId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"eventId":{"examples":["fqdjnvzrfqjcsmvyhgjirjtvftknayzx"],"type":"string"}},"required":["eventId"]}},"text/plain":{"schema":{"type":"object","properties":{"eventId":{"examples":["fqdjnvzrfqjcsmvyhgjirjtvftknayzx"],"type":"string"}},"required":["eventId"]}}}}},"operationId":"postApiV1CalendarAdd-event","tags":["calendar"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["event"],"properties":{"event":{"type":"object","required":["calendarId","startTime","endTime","title"],"properties":{"calendarId":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"description":"Unique identifier of the calendar where the event will be created.","type":"string"},"startTime":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 timestamp marking when the event starts.","type":"string"},"endTime":{"format":"date-time","examples":["2024-05-01T12:00:00.000Z"],"description":"ISO 8601 timestamp marking when the event ends.","type":"string"},"title":{"minLength":1,"maxLength":250,"description":"Short title that clearly describes the event.","examples":["Training with Jan"],"type":"string"},"description":{"description":"Additional details that describe the event context or purpose.","examples":["Training will start in Prague – Nusle."],"type":"string"},"agenda":{"description":"List of agenda items or talking points. Other team members may edit this content.","examples":["– Warm-up\n– Deadlift technique\n– Cool down"],"type":"string"},"url":{"examples":["https://gymroom.cz/pobocky/vinohrady"],"description":"Public or internal link associated with the event.","type":"string"},"notifyBefore":{"examples":["1h 30m"],"description":"Relative time before the event when email/sms notification should be sent.","type":"string"},"blockingTo":{"format":"date-time","examples":["2024-05-01T12:00:00.000Z"],"description":"Time until which the calendar slot remains blocked. Prevents overlapping reservations in the same resource.","type":"string"},"locationTitle":{"description":"Full physical address of the event location.","examples":["Varšavská 11, 120 00, Praha 2 – Vinohrady"],"type":"string"},"isAllDay":{"default":false,"description":"If true, the event spans the entire day (00:00–23:59).","examples":[false],"type":"boolean"},"isBlocking":{"default":true,"description":"If true, the event occupies a time slot and conflicts with other events.","examples":[true],"type":"boolean"},"attendees":{"type":"array","items":{"type":"object","required":["name"],"properties":{"memberId":{"description":"Internal system identifier of a registered member.","examples":[1234],"type":"number"},"customerId":{"description":"Unique external customer identifier,","examples":["HxanU4a1n4El61zx"],"type":"number"},"name":{"examples":["Jan Barášek"],"description":"Full name of the attendee.","type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Email address of the attendee.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Phone number of the attendee in international format.","type":"string"}}}},"type":{"examples":["training","webinar"],"description":"Classification of the event, used for filtering and analytics. Unknown type will be created.","type":"string"}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["event"],"properties":{"event":{"type":"object","required":["calendarId","startTime","endTime","title"],"properties":{"calendarId":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"description":"Unique identifier of the calendar where the event will be created.","type":"string"},"startTime":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 timestamp marking when the event starts.","type":"string"},"endTime":{"format":"date-time","examples":["2024-05-01T12:00:00.000Z"],"description":"ISO 8601 timestamp marking when the event ends.","type":"string"},"title":{"minLength":1,"maxLength":250,"description":"Short title that clearly describes the event.","examples":["Training with Jan"],"type":"string"},"description":{"description":"Additional details that describe the event context or purpose.","examples":["Training will start in Prague – Nusle."],"type":"string"},"agenda":{"description":"List of agenda items or talking points. Other team members may edit this content.","examples":["– Warm-up\n– Deadlift technique\n– Cool down"],"type":"string"},"url":{"examples":["https://gymroom.cz/pobocky/vinohrady"],"description":"Public or internal link associated with the event.","type":"string"},"notifyBefore":{"examples":["1h 30m"],"description":"Relative time before the event when email/sms notification should be sent.","type":"string"},"blockingTo":{"format":"date-time","examples":["2024-05-01T12:00:00.000Z"],"description":"Time until which the calendar slot remains blocked. Prevents overlapping reservations in the same resource.","type":"string"},"locationTitle":{"description":"Full physical address of the event location.","examples":["Varšavská 11, 120 00, Praha 2 – Vinohrady"],"type":"string"},"isAllDay":{"default":false,"description":"If true, the event spans the entire day (00:00–23:59).","examples":[false],"type":"boolean"},"isBlocking":{"default":true,"description":"If true, the event occupies a time slot and conflicts with other events.","examples":[true],"type":"boolean"},"attendees":{"type":"array","items":{"type":"object","required":["name"],"properties":{"memberId":{"description":"Internal system identifier of a registered member.","examples":[1234],"type":"number"},"customerId":{"description":"Unique external customer identifier,","examples":["HxanU4a1n4El61zx"],"type":"number"},"name":{"examples":["Jan Barášek"],"description":"Full name of the attendee.","type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Email address of the attendee.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Phone number of the attendee in international format.","type":"string"}}}},"type":{"examples":["training","webinar"],"description":"Classification of the event, used for filtering and analytics. Unknown type will be created.","type":"string"}}}}}},"text/plain":{"schema":{"type":"object","required":["event"],"properties":{"event":{"type":"object","required":["calendarId","startTime","endTime","title"],"properties":{"calendarId":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"description":"Unique identifier of the calendar where the event will be created.","type":"string"},"startTime":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 timestamp marking when the event starts.","type":"string"},"endTime":{"format":"date-time","examples":["2024-05-01T12:00:00.000Z"],"description":"ISO 8601 timestamp marking when the event ends.","type":"string"},"title":{"minLength":1,"maxLength":250,"description":"Short title that clearly describes the event.","examples":["Training with Jan"],"type":"string"},"description":{"description":"Additional details that describe the event context or purpose.","examples":["Training will start in Prague – Nusle."],"type":"string"},"agenda":{"description":"List of agenda items or talking points. Other team members may edit this content.","examples":["– Warm-up\n– Deadlift technique\n– Cool down"],"type":"string"},"url":{"examples":["https://gymroom.cz/pobocky/vinohrady"],"description":"Public or internal link associated with the event.","type":"string"},"notifyBefore":{"examples":["1h 30m"],"description":"Relative time before the event when email/sms notification should be sent.","type":"string"},"blockingTo":{"format":"date-time","examples":["2024-05-01T12:00:00.000Z"],"description":"Time until which the calendar slot remains blocked. Prevents overlapping reservations in the same resource.","type":"string"},"locationTitle":{"description":"Full physical address of the event location.","examples":["Varšavská 11, 120 00, Praha 2 – Vinohrady"],"type":"string"},"isAllDay":{"default":false,"description":"If true, the event spans the entire day (00:00–23:59).","examples":[false],"type":"boolean"},"isBlocking":{"default":true,"description":"If true, the event occupies a time slot and conflicts with other events.","examples":[true],"type":"boolean"},"attendees":{"type":"array","items":{"type":"object","required":["name"],"properties":{"memberId":{"description":"Internal system identifier of a registered member.","examples":[1234],"type":"number"},"customerId":{"description":"Unique external customer identifier,","examples":["HxanU4a1n4El61zx"],"type":"number"},"name":{"examples":["Jan Barášek"],"description":"Full name of the attendee.","type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Email address of the attendee.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Phone number of the attendee in international format.","type":"string"}}}},"type":{"examples":["training","webinar"],"description":"Classification of the event, used for filtering and analytics. Unknown type will be created.","type":"string"}}}}}}}}}},"/api/v1/calendar/detail":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"examples":["Jan reservation meeting calendar"],"type":"string"},"color":{"examples":["#000000"],"type":"string"},"timezone":{"examples":["Europe/Prague"],"type":"string"},"configuration":{"type":"object","required":["onlineChangeDeadline","relatedCalendarIds","reserveFrom","reserveUntil","timeSlotInterval"],"properties":{"description":{"examples":["Personal meetings for new clients."],"type":"string"},"onlineChangeDeadline":{"examples":["24h"],"type":"string"},"relatedCalendarIds":{"type":"array","items":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"type":"string"}},"reserveFrom":{"examples":["0m"],"type":"string"},"reserveUntil":{"examples":["14d"],"type":"string"},"timeSlotInterval":{"examples":["15m"],"type":"string"}}}},"required":["name","color","timezone","configuration"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"examples":["Jan reservation meeting calendar"],"type":"string"},"color":{"examples":["#000000"],"type":"string"},"timezone":{"examples":["Europe/Prague"],"type":"string"},"configuration":{"type":"object","required":["onlineChangeDeadline","relatedCalendarIds","reserveFrom","reserveUntil","timeSlotInterval"],"properties":{"description":{"examples":["Personal meetings for new clients."],"type":"string"},"onlineChangeDeadline":{"examples":["24h"],"type":"string"},"relatedCalendarIds":{"type":"array","items":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"type":"string"}},"reserveFrom":{"examples":["0m"],"type":"string"},"reserveUntil":{"examples":["14d"],"type":"string"},"timeSlotInterval":{"examples":["15m"],"type":"string"}}}},"required":["name","color","timezone","configuration"]}},"text/plain":{"schema":{"type":"object","properties":{"name":{"examples":["Jan reservation meeting calendar"],"type":"string"},"color":{"examples":["#000000"],"type":"string"},"timezone":{"examples":["Europe/Prague"],"type":"string"},"configuration":{"type":"object","required":["onlineChangeDeadline","relatedCalendarIds","reserveFrom","reserveUntil","timeSlotInterval"],"properties":{"description":{"examples":["Personal meetings for new clients."],"type":"string"},"onlineChangeDeadline":{"examples":["24h"],"type":"string"},"relatedCalendarIds":{"type":"array","items":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"type":"string"}},"reserveFrom":{"examples":["0m"],"type":"string"},"reserveUntil":{"examples":["14d"],"type":"string"},"timeSlotInterval":{"examples":["15m"],"type":"string"}}}},"required":["name","color","timezone","configuration"]}}}}},"operationId":"getApiV1CalendarDetail","tags":["calendar"]}},"/api/v1/calendar/event-find-conflict":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"operationId":"postApiV1CalendarEvent-find-conflict","tags":["calendar"],"responses":{"200":{}}}},"/api/v1/calendar/event-list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Calendar internal code.","schema":{"type":"string"},"in":"query","name":"code","required":true},{"examples":["week"],"schema":{"anyOf":[{"const":"report","type":"string"},{"const":"day","type":"string"},{"const":"week","type":"string"},{"const":"month","type":"string"},{"const":"year","type":"string"}]},"in":"query","name":"step","required":false},{"schema":{"anyOf":[{"type":"boolean"},{"format":"boolean","default":false,"type":"string"}]},"in":"query","name":"returnPlainList","required":false},{"schema":{"type":"string"},"in":"query","name":"selectorFrom","required":false},{"schema":{"type":"string"},"in":"query","name":"eventTypeCode","required":false}],"operationId":"getApiV1CalendarEvent-list","tags":["calendar"],"responses":{"200":{}}}},"/api/v1/calendar/scheduling-assistant":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"code","required":true},{"schema":{"type":"string"},"in":"query","name":"startTime","required":true},{"schema":{"type":"string"},"in":"query","name":"endTime","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"calendarName":{"type":"string"},"events":{"type":"array","items":{"type":"object","required":["startTime","endTime","isAllDay","isBlocking"],"properties":{"startTime":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"reservedBlockingTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"examples":[false],"type":"boolean"},"isBlocking":{"examples":[true],"type":"boolean"}}}}},"required":["calendarName","events"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"calendarName":{"type":"string"},"events":{"type":"array","items":{"type":"object","required":["startTime","endTime","isAllDay","isBlocking"],"properties":{"startTime":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"reservedBlockingTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"examples":[false],"type":"boolean"},"isBlocking":{"examples":[true],"type":"boolean"}}}}},"required":["calendarName","events"]}},"text/plain":{"schema":{"type":"object","properties":{"calendarName":{"type":"string"},"events":{"type":"array","items":{"type":"object","required":["startTime","endTime","isAllDay","isBlocking"],"properties":{"startTime":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"reservedBlockingTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"examples":[false],"type":"boolean"},"isBlocking":{"examples":[true],"type":"boolean"}}}}},"required":["calendarName","events"]}}}}},"operationId":"getApiV1CalendarScheduling-assistant","tags":["calendar"]}},"/api/v1/calendar/timezones":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"clientTimezone":{"examples":["Europe/Prague"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"examples":["America/New_York"],"type":"string"},"timezone":{"examples":["America/New_York"],"type":"string"},"gmt":{"examples":["-05:00"],"type":"string"},"label":{"examples":["Eastern Time - New York"],"type":"string"}}}}},"required":["clientTimezone","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"clientTimezone":{"examples":["Europe/Prague"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"examples":["America/New_York"],"type":"string"},"timezone":{"examples":["America/New_York"],"type":"string"},"gmt":{"examples":["-05:00"],"type":"string"},"label":{"examples":["Eastern Time - New York"],"type":"string"}}}}},"required":["clientTimezone","items"]}},"text/plain":{"schema":{"type":"object","properties":{"clientTimezone":{"examples":["Europe/Prague"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"examples":["America/New_York"],"type":"string"},"timezone":{"examples":["America/New_York"],"type":"string"},"gmt":{"examples":["-05:00"],"type":"string"},"label":{"examples":["Eastern Time - New York"],"type":"string"}}}}},"required":["clientTimezone","items"]}}}}},"operationId":"getApiV1CalendarTimezones","tags":["calendar"]}},"/api/v1/cart/detail":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Existing cart ID. If omitted or invalid, a new empty cart is returned.","examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"schema":{"type":"string"},"in":"query","name":"cartId","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"customerId":{"examples":["HxanU4a1n4El61zx"],"type":"string"},"customerName":{"examples":["Jan Barášek"],"type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceTotal":{"examples":[12699],"type":"number"},"deliveryCode":{"examples":["packeta"],"type":"string"},"deliveryBranchId":{"type":"number"},"deliveryBranchProvider":{"type":"string"},"paymentCode":{"examples":["comgate"],"type":"string"},"deliveryList":{"type":"array","items":{"type":"object","required":["name","code","price","active"],"properties":{"name":{"examples":["Zásilkovna"],"type":"string"},"code":{"examples":["packeta"],"type":"string"},"description":{"type":"string"},"price":{"examples":[59],"type":"number"},"active":{"examples":[true],"type":"boolean"},"selected":{"examples":[false],"type":"boolean"}}}},"paymentList":{"type":"array","items":{"type":"object","required":["name","code","price","active"],"properties":{"name":{"examples":["Online platba kartou"],"type":"string"},"code":{"examples":["comgate"],"type":"string"},"description":{"examples":["Platební brána Comgate"],"type":"string"},"price":{"examples":[0],"type":"number"},"active":{"examples":[true],"type":"boolean"},"selected":{"examples":[false],"type":"boolean"}}}},"deliveryAndPaymentCombinations":{"type":"array","items":{"type":"object","required":["deliveryCode","paymentCode"],"properties":{"deliveryCode":{"examples":["packeta"],"type":"string"},"paymentCode":{"examples":["comgate"],"type":"string"}}}},"items":{"type":"array","items":{"type":"object","required":["id","label","productCode","productSlug","price","quantity"],"properties":{"id":{"examples":["v211g68VlHP98w3s"],"type":"string"},"label":{"examples":["Coca cola zero"],"type":"string"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"productCode":{"examples":["coca-cola"],"type":"string"},"productSlug":{"examples":["coca-cola"],"type":"string"},"variantCode":{"examples":["coca-cola-zero"],"type":"string"},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"quantity":{"examples":[4],"type":"number"}}}}},"required":["id","currency","priceTotal","deliveryList","paymentList","deliveryAndPaymentCombinations","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"customerId":{"examples":["HxanU4a1n4El61zx"],"type":"string"},"customerName":{"examples":["Jan Barášek"],"type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceTotal":{"examples":[12699],"type":"number"},"deliveryCode":{"examples":["packeta"],"type":"string"},"deliveryBranchId":{"type":"number"},"deliveryBranchProvider":{"type":"string"},"paymentCode":{"examples":["comgate"],"type":"string"},"deliveryList":{"type":"array","items":{"type":"object","required":["name","code","price","active"],"properties":{"name":{"examples":["Zásilkovna"],"type":"string"},"code":{"examples":["packeta"],"type":"string"},"description":{"type":"string"},"price":{"examples":[59],"type":"number"},"active":{"examples":[true],"type":"boolean"},"selected":{"examples":[false],"type":"boolean"}}}},"paymentList":{"type":"array","items":{"type":"object","required":["name","code","price","active"],"properties":{"name":{"examples":["Online platba kartou"],"type":"string"},"code":{"examples":["comgate"],"type":"string"},"description":{"examples":["Platební brána Comgate"],"type":"string"},"price":{"examples":[0],"type":"number"},"active":{"examples":[true],"type":"boolean"},"selected":{"examples":[false],"type":"boolean"}}}},"deliveryAndPaymentCombinations":{"type":"array","items":{"type":"object","required":["deliveryCode","paymentCode"],"properties":{"deliveryCode":{"examples":["packeta"],"type":"string"},"paymentCode":{"examples":["comgate"],"type":"string"}}}},"items":{"type":"array","items":{"type":"object","required":["id","label","productCode","productSlug","price","quantity"],"properties":{"id":{"examples":["v211g68VlHP98w3s"],"type":"string"},"label":{"examples":["Coca cola zero"],"type":"string"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"productCode":{"examples":["coca-cola"],"type":"string"},"productSlug":{"examples":["coca-cola"],"type":"string"},"variantCode":{"examples":["coca-cola-zero"],"type":"string"},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"quantity":{"examples":[4],"type":"number"}}}}},"required":["id","currency","priceTotal","deliveryList","paymentList","deliveryAndPaymentCombinations","items"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"customerId":{"examples":["HxanU4a1n4El61zx"],"type":"string"},"customerName":{"examples":["Jan Barášek"],"type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceTotal":{"examples":[12699],"type":"number"},"deliveryCode":{"examples":["packeta"],"type":"string"},"deliveryBranchId":{"type":"number"},"deliveryBranchProvider":{"type":"string"},"paymentCode":{"examples":["comgate"],"type":"string"},"deliveryList":{"type":"array","items":{"type":"object","required":["name","code","price","active"],"properties":{"name":{"examples":["Zásilkovna"],"type":"string"},"code":{"examples":["packeta"],"type":"string"},"description":{"type":"string"},"price":{"examples":[59],"type":"number"},"active":{"examples":[true],"type":"boolean"},"selected":{"examples":[false],"type":"boolean"}}}},"paymentList":{"type":"array","items":{"type":"object","required":["name","code","price","active"],"properties":{"name":{"examples":["Online platba kartou"],"type":"string"},"code":{"examples":["comgate"],"type":"string"},"description":{"examples":["Platební brána Comgate"],"type":"string"},"price":{"examples":[0],"type":"number"},"active":{"examples":[true],"type":"boolean"},"selected":{"examples":[false],"type":"boolean"}}}},"deliveryAndPaymentCombinations":{"type":"array","items":{"type":"object","required":["deliveryCode","paymentCode"],"properties":{"deliveryCode":{"examples":["packeta"],"type":"string"},"paymentCode":{"examples":["comgate"],"type":"string"}}}},"items":{"type":"array","items":{"type":"object","required":["id","label","productCode","productSlug","price","quantity"],"properties":{"id":{"examples":["v211g68VlHP98w3s"],"type":"string"},"label":{"examples":["Coca cola zero"],"type":"string"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"productCode":{"examples":["coca-cola"],"type":"string"},"productSlug":{"examples":["coca-cola"],"type":"string"},"variantCode":{"examples":["coca-cola-zero"],"type":"string"},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"quantity":{"examples":[4],"type":"number"}}}}},"required":["id","currency","priceTotal","deliveryList","paymentList","deliveryAndPaymentCombinations","items"]}}}}},"operationId":"getApiV1CartDetail","tags":["cart"],"summary":"Get cart detail","description":"Returns the full cart state including items, prices, available delivery/payment methods, and their valid combinations. Creates a new cart if cartId is not provided."}},"/api/v1/cart/buy":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CartBuy","tags":["cart"],"summary":"Add product to cart","description":"Adds a product (optionally a specific variant) to the cart. If the product already exists in the cart, its quantity is increased.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cartId","productCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"identityId":{"examples":["9jq49ZE1xoKI7S5ys4J0a70y3Xp2hQqc"],"description":"Use customer identity cookies value when is logged in.","type":"string"},"quantity":{"examples":[2],"type":"number"},"productCode":{"examples":["coca-cola"],"type":"string"},"productVariantCode":{"examples":["coca-cola-zero"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["cartId","productCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"identityId":{"examples":["9jq49ZE1xoKI7S5ys4J0a70y3Xp2hQqc"],"description":"Use customer identity cookies value when is logged in.","type":"string"},"quantity":{"examples":[2],"type":"number"},"productCode":{"examples":["coca-cola"],"type":"string"},"productVariantCode":{"examples":["coca-cola-zero"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["cartId","productCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"identityId":{"examples":["9jq49ZE1xoKI7S5ys4J0a70y3Xp2hQqc"],"description":"Use customer identity cookies value when is logged in.","type":"string"},"quantity":{"examples":[2],"type":"number"},"productCode":{"examples":["coca-cola"],"type":"string"},"productVariantCode":{"examples":["coca-cola-zero"],"type":"string"}}}}}}}},"/api/v1/cart/change-quantity":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CartChange-quantity","tags":["cart"],"summary":"Change cart item quantity","description":"Updates the quantity of an existing cart item. Setting quantity to 0 removes the item from the cart.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cartId","itemId","quantity"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"itemId":{"examples":["8YOoIOOuc48IShi2"],"type":"string"},"quantity":{"examples":[4,0],"description":"Set product quantity. Use `0` to remove item from cart.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["cartId","itemId","quantity"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"itemId":{"examples":["8YOoIOOuc48IShi2"],"type":"string"},"quantity":{"examples":[4,0],"description":"Set product quantity. Use `0` to remove item from cart.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["cartId","itemId","quantity"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"itemId":{"examples":["8YOoIOOuc48IShi2"],"type":"string"},"quantity":{"examples":[4,0],"description":"Set product quantity. Use `0` to remove item from cart.","type":"number"}}}}}}}},"/api/v1/cart/set-delivery":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CartSet-delivery","tags":["cart"],"summary":"Set cart delivery method","description":"Sets the delivery method for the cart. Use codes from the deliveryList returned by /detail.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cartId","deliveryCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"deliveryCode":{"description":"Delivery method code.","examples":["packeta"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["cartId","deliveryCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"deliveryCode":{"description":"Delivery method code.","examples":["packeta"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["cartId","deliveryCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"deliveryCode":{"description":"Delivery method code.","examples":["packeta"],"type":"string"}}}}}}}},"/api/v1/cart/set-payment":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CartSet-payment","tags":["cart"],"summary":"Set cart payment method","description":"Sets the payment method for the cart. Use codes from the paymentList returned by /detail.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cartId","paymentCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"paymentCode":{"description":"Payment method code.","examples":["comgate"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["cartId","paymentCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"paymentCode":{"description":"Payment method code.","examples":["comgate"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["cartId","paymentCode"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"paymentCode":{"description":"Payment method code.","examples":["comgate"],"type":"string"}}}}}}}},"/api/v1/cart/set-packeta-branch":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CartSet-packeta-branch","tags":["cart"],"summary":"Set Packeta pickup branch","description":"Sets the Packeta pickup point for the cart. Only applicable when delivery method is Packeta.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cartId","packetaBranchId"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"packetaBranchId":{"description":"Packeta pickup point branch ID.","examples":[12345],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["cartId","packetaBranchId"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"packetaBranchId":{"description":"Packeta pickup point branch ID.","examples":[12345],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["cartId","packetaBranchId"],"properties":{"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"packetaBranchId":{"description":"Packeta pickup point branch ID.","examples":[12345],"type":"number"}}}}}}}},"/api/v1/crm/member-invite/validate":{"get":{"parameters":[{"description":"Invitation token from the e-mail link.","schema":{"type":"string"},"in":"query","name":"token","required":true}],"operationId":"getApiV1CrmMember-inviteValidate","tags":["crm"],"summary":"Validate a member-invitation token","description":"Returns invitation metadata (organisation name, e-mail, optional first/last name pre-fill) if the token is valid and not expired. Used by the public marketing site to render the set-password registration form.","responses":{"200":{}}}},"/api/v1/crm/member-invite/complete":{"post":{"parameters":[],"operationId":"postApiV1CrmMember-inviteComplete","tags":["crm"],"summary":"Complete a member invitation","description":"Finishes the invitation flow — creates the user/contact, joins the organisation, applies pre-granted permissions stored on the invitation, and invalidates the token.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","firstName","lastName","password","agreeToTerms"],"properties":{"token":{"description":"Invitation token from the e-mail link.","type":"string"},"firstName":{"description":"First name of the invitee.","minLength":1,"maxLength":128,"type":"string"},"lastName":{"description":"Last name of the invitee.","minLength":1,"maxLength":128,"type":"string"},"password":{"description":"Chosen account password.","minLength":8,"type":"string"},"agreeToTerms":{"description":"Accepted Terms of Service.","type":"boolean"},"agreeToMarketing":{"description":"Accepted marketing communications.","type":"boolean"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["token","firstName","lastName","password","agreeToTerms"],"properties":{"token":{"description":"Invitation token from the e-mail link.","type":"string"},"firstName":{"description":"First name of the invitee.","minLength":1,"maxLength":128,"type":"string"},"lastName":{"description":"Last name of the invitee.","minLength":1,"maxLength":128,"type":"string"},"password":{"description":"Chosen account password.","minLength":8,"type":"string"},"agreeToTerms":{"description":"Accepted Terms of Service.","type":"boolean"},"agreeToMarketing":{"description":"Accepted marketing communications.","type":"boolean"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["token","firstName","lastName","password","agreeToTerms"],"properties":{"token":{"description":"Invitation token from the e-mail link.","type":"string"},"firstName":{"description":"First name of the invitee.","minLength":1,"maxLength":128,"type":"string"},"lastName":{"description":"Last name of the invitee.","minLength":1,"maxLength":128,"type":"string"},"password":{"description":"Chosen account password.","minLength":8,"type":"string"},"agreeToTerms":{"description":"Accepted Terms of Service.","type":"boolean"},"agreeToMarketing":{"description":"Accepted marketing communications.","type":"boolean"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}}}},"responses":{"200":{}}}},"/api/v1/customer/create":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"newAccount":{"examples":[true],"type":"boolean"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["success","newAccount","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"newAccount":{"examples":[true],"type":"boolean"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["success","newAccount","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"newAccount":{"examples":[true],"type":"boolean"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["success","newAccount","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}}}}},"operationId":"postApiV1CustomerCreate","tags":["customer"],"summary":"Create customer","description":"Registers a new customer or returns an existing one by email. Returns the full customer profile with a flag indicating whether a new account was created.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}}}}}},"/api/v1/customer/create-api-key":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"apiKey":{"examples":["63VQn5OUY2zfcPdz1I8s2rWzI2KyOX0z"],"type":"string"},"expirationDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["success","apiKey","expirationDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"apiKey":{"examples":["63VQn5OUY2zfcPdz1I8s2rWzI2KyOX0z"],"type":"string"},"expirationDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["success","apiKey","expirationDate"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"apiKey":{"examples":["63VQn5OUY2zfcPdz1I8s2rWzI2KyOX0z"],"type":"string"},"expirationDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["success","apiKey","expirationDate"]}}}}},"operationId":"postApiV1CustomerCreate-api-key","tags":["customer"],"summary":"Create customer API key","description":"Generates a new API key (identity) for an authenticated customer. The key can be scoped to a specific workspace.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"description":{"examples":["User Jan Barasek"],"type":"string"},"workspaceCode":{"examples":["my-workspace"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"description":{"examples":["User Jan Barasek"],"type":"string"},"workspaceCode":{"examples":["my-workspace"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"description":{"examples":["User Jan Barasek"],"type":"string"},"workspaceCode":{"examples":["my-workspace"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}}}}}},"/api/v1/customer/credit-log":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"creditBalance":{"examples":[510],"type":"number"},"creditMoneyBalance":{"examples":[460],"description":"Total credit balance in the organisation default currency.","type":"number"},"currency":{"examples":["CZK"],"description":"ISO 4217 code of the organisation default currency.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["id","amount","amountMoney","balance","balanceMoney","insertedDate"],"properties":{"id":{"examples":["HxanU4a1n4El61zx"],"type":"string"},"amount":{"examples":[100],"type":"number"},"amountMoney":{"examples":[90],"description":"Transaction value in default currency (CZK). Defaults to same as amount (1:1).","type":"number"},"balance":{"examples":[410],"type":"number"},"balanceMoney":{"examples":[370],"description":"Running balance in default currency (CZK).","type":"number"},"order":{"type":"object","required":["orderNumber","hash","groupName"],"properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"groupName":{"examples":["GymRoom Vinohrady"],"type":"string"}}},"expiration":{"type":"object","required":["date","status"],"properties":{"date":{"examples":["2025-01-10T16:19:41.675Z"],"anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"examples":["pending"],"anyOf":[{"const":"processed","type":"string"},{"const":"expired","type":"string"},{"const":"pending","type":"string"}]},"processed":{"examples":["2025-01-10T16:19:41.675Z"],"anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"description":{"examples":["Order 25000087"],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of credit record.","anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of credit record.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["creditBalance","creditMoneyBalance","currency","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"creditBalance":{"examples":[510],"type":"number"},"creditMoneyBalance":{"examples":[460],"description":"Total credit balance in the organisation default currency.","type":"number"},"currency":{"examples":["CZK"],"description":"ISO 4217 code of the organisation default currency.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["id","amount","amountMoney","balance","balanceMoney","insertedDate"],"properties":{"id":{"examples":["HxanU4a1n4El61zx"],"type":"string"},"amount":{"examples":[100],"type":"number"},"amountMoney":{"examples":[90],"description":"Transaction value in default currency (CZK). Defaults to same as amount (1:1).","type":"number"},"balance":{"examples":[410],"type":"number"},"balanceMoney":{"examples":[370],"description":"Running balance in default currency (CZK).","type":"number"},"order":{"type":"object","required":["orderNumber","hash","groupName"],"properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"groupName":{"examples":["GymRoom Vinohrady"],"type":"string"}}},"expiration":{"type":"object","required":["date","status"],"properties":{"date":{"examples":["2025-01-10T16:19:41.675Z"],"anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"examples":["pending"],"anyOf":[{"const":"processed","type":"string"},{"const":"expired","type":"string"},{"const":"pending","type":"string"}]},"processed":{"examples":["2025-01-10T16:19:41.675Z"],"anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"description":{"examples":["Order 25000087"],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of credit record.","anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of credit record.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["creditBalance","creditMoneyBalance","currency","items"]}},"text/plain":{"schema":{"type":"object","properties":{"creditBalance":{"examples":[510],"type":"number"},"creditMoneyBalance":{"examples":[460],"description":"Total credit balance in the organisation default currency.","type":"number"},"currency":{"examples":["CZK"],"description":"ISO 4217 code of the organisation default currency.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["id","amount","amountMoney","balance","balanceMoney","insertedDate"],"properties":{"id":{"examples":["HxanU4a1n4El61zx"],"type":"string"},"amount":{"examples":[100],"type":"number"},"amountMoney":{"examples":[90],"description":"Transaction value in default currency (CZK). Defaults to same as amount (1:1).","type":"number"},"balance":{"examples":[410],"type":"number"},"balanceMoney":{"examples":[370],"description":"Running balance in default currency (CZK).","type":"number"},"order":{"type":"object","required":["orderNumber","hash","groupName"],"properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"groupName":{"examples":["GymRoom Vinohrady"],"type":"string"}}},"expiration":{"type":"object","required":["date","status"],"properties":{"date":{"examples":["2025-01-10T16:19:41.675Z"],"anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"examples":["pending"],"anyOf":[{"const":"processed","type":"string"},{"const":"expired","type":"string"},{"const":"pending","type":"string"}]},"processed":{"examples":["2025-01-10T16:19:41.675Z"],"anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"description":{"examples":["Order 25000087"],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of credit record.","anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of credit record.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["creditBalance","creditMoneyBalance","currency","items"]}}}}},"operationId":"getApiV1CustomerCredit-log","tags":["customer"],"summary":"Get credit log","description":"Returns the customer credit balance and a list of all credit transactions (deposits, spending, expirations)."}},"/api/v1/customer/credit-spend":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"transactionId":{"examples":["HxanU4a1n4El61zx","xxxxxxxxxxxxxxxx"],"description":"Unique transaction id (for example `HxanU4a1n4El61zx`). In case of `amount = 0` transactionId is `xxxxxxxxxxxxxxxx`.","type":"string"},"oldCreditBalance":{"examples":[510],"type":"number"},"newCreditBalance":{"examples":[410],"type":"number"}},"required":["success","transactionId","oldCreditBalance","newCreditBalance"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"transactionId":{"examples":["HxanU4a1n4El61zx","xxxxxxxxxxxxxxxx"],"description":"Unique transaction id (for example `HxanU4a1n4El61zx`). In case of `amount = 0` transactionId is `xxxxxxxxxxxxxxxx`.","type":"string"},"oldCreditBalance":{"examples":[510],"type":"number"},"newCreditBalance":{"examples":[410],"type":"number"}},"required":["success","transactionId","oldCreditBalance","newCreditBalance"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"transactionId":{"examples":["HxanU4a1n4El61zx","xxxxxxxxxxxxxxxx"],"description":"Unique transaction id (for example `HxanU4a1n4El61zx`). In case of `amount = 0` transactionId is `xxxxxxxxxxxxxxxx`.","type":"string"},"oldCreditBalance":{"examples":[510],"type":"number"},"newCreditBalance":{"examples":[410],"type":"number"}},"required":["success","transactionId","oldCreditBalance","newCreditBalance"]}}}}},"operationId":"postApiV1CustomerCredit-spend","tags":["customer"],"summary":"Spend customer credit","description":"Deducts credit from the customer account. The amount is always treated as negative (spending). Returns the old and new balance along with a transaction ID.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identityId","amount"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"amount":{"examples":[100],"type":"number"},"description":{"examples":["video.rewrite:15m"],"description":"App internal description.","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["identityId","amount"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"amount":{"examples":[100],"type":"number"},"description":{"examples":["video.rewrite:15m"],"description":"App internal description.","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["identityId","amount"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"amount":{"examples":[100],"type":"number"},"description":{"examples":["video.rewrite:15m"],"description":"App internal description.","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}}}}}},"/api/v1/customer/customer-match-customer":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CustomerCustomer-match-customer","tags":["customer"],"summary":"Match two customers","description":"Create many-to-many relation between two customers.\n\nThis feature is suitable, for example, for matching clients and trainers, or for obtaining contacts on a dating site or company contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["managerCuRefNo"],"properties":{"managerCuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"customerCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Customer of relation.","type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"notice":{"examples":["Customer prefers cardio training. Contact obtained via the website."],"description":"A public note for this connection. The note will be visible to both customers. For example, a trainer can write information about a new client here.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["managerCuRefNo"],"properties":{"managerCuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"customerCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Customer of relation.","type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"notice":{"examples":["Customer prefers cardio training. Contact obtained via the website."],"description":"A public note for this connection. The note will be visible to both customers. For example, a trainer can write information about a new client here.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["managerCuRefNo"],"properties":{"managerCuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"customerCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Customer of relation.","type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"notice":{"examples":["Customer prefers cardio training. Contact obtained via the website."],"description":"A public note for this connection. The note will be visible to both customers. For example, a trainer can write information about a new client here.","type":"string"}}}}}}}},"/api/v1/customer/customer-unmatch-customer":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CustomerCustomer-unmatch-customer","tags":["customer"],"summary":"Unmatch two customers","description":"Deactivate many-to-many relation between two customers.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["managerCuRefNo","customerCuRefNo"],"properties":{"managerCuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"customerCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Customer to unmatch.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["managerCuRefNo","customerCuRefNo"],"properties":{"managerCuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"customerCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Customer to unmatch.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["managerCuRefNo","customerCuRefNo"],"properties":{"managerCuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"customerCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Customer to unmatch.","type":"string"}}}}}}}},"/api/v1/customer/detail":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":true},{"description":"cuRefNo = customer reference number.","examples":["1cGIHvFoQDGLAbcA"],"schema":{"type":"string","maxLength":16,"minLength":16},"in":"query","name":"cuRefNo","required":true},{"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","examples":["1.1.1.1","2001:4860:4860::8888"],"schema":{"type":"string"},"in":"query","name":"customerRealIp","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"loggedIn":{"examples":[true],"type":"boolean"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["loggedIn","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"loggedIn":{"examples":[true],"type":"boolean"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["loggedIn","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}},"text/plain":{"schema":{"type":"object","properties":{"loggedIn":{"examples":[true],"type":"boolean"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["loggedIn","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}}}}},"operationId":"getApiV1CustomerDetail","tags":["customer"],"summary":"Get customer detail","description":"Returns the full profile of a customer identified by identityId and cuRefNo. Updates the last activity timestamp. Throws PUBLIC_CUSTOMER_DETAIL_NOT_PERMITTED if the identity cannot access the requested customer."}},"/api/v1/customer/export-gdpr":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":true}],"operationId":"getApiV1CustomerExport-gdpr","tags":["customer"],"summary":"Download personal data export (GDPR Art. 15)","description":"Returns an `application/zip` archive with every personal data point the organisation holds about the customer identified by `identityId` — profile, addresses, company record, additional e-mails, consent audit trail, orders, invoices, subscriptions, comments, and the system activity log. Companion `README.md` and `index.html` are rendered in the customer’s preferred language. Internal identifiers, hashes and other non-personal data are deliberately omitted.\n\n### How to call this endpoint safely\n\nThe `apiKey` is an organisation-wide secret — exposing it in the browser would let anyone export anyone’s data. Treat this endpoint as **server-to-server only**:\n\n1. The customer authenticates against **your** application (e.g. via `/customer/login` or `/customer/magic-auth`) and you obtain their short-lived `identityId`.\n2. When the customer requests their data export, **your backend** (never the browser) calls this endpoint with the secret `apiKey` and the customer’s `identityId`.\n3. The endpoint verifies that the identity belongs to a customer in the same organisation as the API key — a mismatch is logged as a critical security event and the request is rejected.\n4. Your backend then proxies the binary response to the end user, typically by streaming the body straight back with the same `Content-Disposition` header, or by storing it briefly and serving a one-time download URL.\n\nThis indirection keeps the API key on your server and lets you layer your own checks (rate limits, audit logging, a second-factor confirmation, etc.) before honouring the request — the endpoint itself enforces only the organisation/identity binding.","responses":{"200":{}}}},"/api/v1/customer/get-account-info":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":true},{"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","examples":["1.1.1.1","2001:4860:4860::8888"],"schema":{"type":"string"},"in":"query","name":"customerRealIp","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"loggedIn":{"examples":[true],"type":"boolean"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["loggedIn","identityId","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"loggedIn":{"examples":[true],"type":"boolean"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["loggedIn","identityId","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}},"text/plain":{"schema":{"type":"object","properties":{"loggedIn":{"examples":[true],"type":"boolean"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"creditBalance":{"examples":[123],"type":"number"},"email":{"nullable":true,"anyOf":[{"examples":["jan@barasek.com"],"description":"Contact e-mail address, or `null` for phone-only contacts.\n\n**When null:** the contact was registered with only a phone number (no e-mail), or was anonymised via GDPR right-to-erasure. Such contacts cannot be looked up by e-mail and cannot log in (login requires e-mail). UI should fall back to the contact's name, phone, or external reference when rendering.\n\nWhen non-null, the value is the canonical normalized form (`fixEmail`) and is unique per organisation.","type":"string"},{"type":"null"}]},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"premium":{"examples":[true],"type":"boolean"},"ban":{"examples":[false],"type":"boolean"},"groups":{"type":"array","items":{"type":"object","required":["name","slug"],"properties":{"name":{"examples":["Personal Trainer"],"type":"string"},"slug":{"examples":["trainer"],"type":"string"}}}},"meta":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"customFields":{"type":"object","patternProperties":{"^(.*)$":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"referral":{"type":"object","required":["code","email"],"properties":{"code":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}},"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["loggedIn","identityId","cuRefNo","creditBalance","email","premium","ban","groups","meta","customFields","runningSubscriptionList"]}}}}},"operationId":"getApiV1CustomerGet-account-info","tags":["customer"],"summary":"Get account info","description":"Returns the profile of the currently authenticated customer (by identityId). Updates the last activity timestamp."}},"/api/v1/customer/login":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success","identityId"],"properties":{"success":{"const":true,"type":"boolean"},"identityId":{"examples":["9jq49ZE1xoKI7S5ys4J0a70y3Xp2hQqc"],"type":"string"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004","E005","E006","E007"],"type":"string"},"message":{"examples":["Customer login failed.","Customer e-mail does not exist.","Customer have not a registered account.","Wrong e-mail or password.","Customer account has been banned.","Too many login attempts.","Customer mail has not been authorized."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success","identityId"],"properties":{"success":{"const":true,"type":"boolean"},"identityId":{"examples":["9jq49ZE1xoKI7S5ys4J0a70y3Xp2hQqc"],"type":"string"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004","E005","E006","E007"],"type":"string"},"message":{"examples":["Customer login failed.","Customer e-mail does not exist.","Customer have not a registered account.","Wrong e-mail or password.","Customer account has been banned.","Too many login attempts.","Customer mail has not been authorized."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success","identityId"],"properties":{"success":{"const":true,"type":"boolean"},"identityId":{"examples":["9jq49ZE1xoKI7S5ys4J0a70y3Xp2hQqc"],"type":"string"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004","E005","E006","E007"],"type":"string"},"message":{"examples":["Customer login failed.","Customer e-mail does not exist.","Customer have not a registered account.","Wrong e-mail or password.","Customer account has been banned.","Too many login attempts.","Customer mail has not been authorized."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success","identityId"],"properties":{"success":{"const":true,"type":"boolean"},"identityId":{"examples":["9jq49ZE1xoKI7S5ys4J0a70y3Xp2hQqc"],"type":"string"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004","E005","E006","E007"],"type":"string"},"message":{"examples":["Customer login failed.","Customer e-mail does not exist.","Customer have not a registered account.","Wrong e-mail or password.","Customer account has been banned.","Too many login attempts.","Customer mail has not been authorized."],"type":"string"}}}]}}}}},"operationId":"postApiV1CustomerLogin","tags":["customer"],"summary":"Customer login","description":"Create a new customer identity based on real customer e-mail and password. Return identity session value or error code.\n\nList of error codes:\n\n| Code | Message |\n|------|---------|\n| E001 | Customer login failed. |\n| E002 | Customer e-mail does not exist. |\n| E003 | Customer have not a registered account. |\n| E004 | Wrong e-mail or password. |\n| E005 | Customer account has been banned. |\n| E006 | Too many login attempts. |\n| E007 | Customer mail has not been authorized. |","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"password":{"examples":["1234"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"password":{"examples":["1234"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"password":{"examples":["1234"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}}}}}},"/api/v1/customer/logout":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CustomerLogout","tags":["customer"],"summary":"Customer logout","description":"Invalidates the customer identity session and logs activity with geolocation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["identityId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}}}}}},"/api/v1/customer/magic-auth":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success","identityId"],"properties":{"success":{"const":true,"type":"boolean"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"New created user identity, please store it to your frontend cookies.","type":"string"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004","E005","E006","E007"],"type":"string"},"message":{"examples":["Customer login failed.","Customer e-mail does not exist.","Customer have not a registered account.","Wrong e-mail or password.","Customer account has been banned.","Too many login attempts.","Customer mail has not been authorized."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success","identityId"],"properties":{"success":{"const":true,"type":"boolean"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"New created user identity, please store it to your frontend cookies.","type":"string"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004","E005","E006","E007"],"type":"string"},"message":{"examples":["Customer login failed.","Customer e-mail does not exist.","Customer have not a registered account.","Wrong e-mail or password.","Customer account has been banned.","Too many login attempts.","Customer mail has not been authorized."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success","identityId"],"properties":{"success":{"const":true,"type":"boolean"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"New created user identity, please store it to your frontend cookies.","type":"string"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004","E005","E006","E007"],"type":"string"},"message":{"examples":["Customer login failed.","Customer e-mail does not exist.","Customer have not a registered account.","Wrong e-mail or password.","Customer account has been banned.","Too many login attempts.","Customer mail has not been authorized."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success","identityId"],"properties":{"success":{"const":true,"type":"boolean"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"New created user identity, please store it to your frontend cookies.","type":"string"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004","E005","E006","E007"],"type":"string"},"message":{"examples":["Customer login failed.","Customer e-mail does not exist.","Customer have not a registered account.","Wrong e-mail or password.","Customer account has been banned.","Too many login attempts.","Customer mail has not been authorized."],"type":"string"}}}]}}}}},"operationId":"postApiV1CustomerMagic-auth","tags":["customer"],"summary":"Magic auth (passwordless login)","description":"Create a new customer identity based on e-mail without password. Return identity session value or error code.\n\nList of error codes:\n\n| Code | Message |\n|------|---------|\n| E001 | Customer login failed. |\n| E002 | Customer e-mail does not exist. |\n| E003 | Customer have not a registered account. |\n| E004 | Wrong e-mail or password. |\n| E005 | Customer account has been banned. |\n| E006 | Too many login attempts. |\n| E007 | Customer mail has not been authorized. |","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}}}}}}},"/api/v1/customer/matched-customer-list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":true},{"description":"Optional search query to filter matched customers by name or email.","schema":{"type":"string"},"in":"query","name":"query","required":false}],"operationId":"getApiV1CustomerMatched-customer-list","tags":["customer"],"summary":"List matched customers","description":"Returns a list of customers matched (linked) to the customer identified by identityId.","responses":{"200":{}}}},"/api/v1/customer/order-list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":true},{"description":"Page number (string, converted to number internally).","schema":{"type":"string","default":"1"},"in":"query","name":"page","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","orderNumber","status","price","insertedDate","updatedDate","lines"],"properties":{"id":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"orderNumber":{"examples":["25000055"],"type":"string"},"status":{"type":"object","required":["label","code","backgroundColor","textColor"],"properties":{"label":{"examples":["Storno"],"type":"string"},"code":{"examples":["storno"],"type":"string"},"backgroundColor":{"examples":["#901020"],"type":"string"},"textColor":{"examples":["#fff"],"type":"string"}}},"price":{"examples":["0&nbsp;Kč"],"type":"string"},"notice":{"examples":["Please reserve a trainer to me."],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lines":{"type":"array","items":{"type":"object","required":["id","label","count","storno","price","insertedDate"],"properties":{"id":{"examples":["2d33677772eddbd4e869c6ed6bf6d9f3"],"type":"string"},"label":{"examples":["Jan Barášek GymRoom Vinohrady rezervace"],"type":"string"},"count":{"examples":[1],"type":"number"},"storno":{"default":false,"type":"boolean"},"price":{"examples":["110&nbsp;Kč"],"type":"string"},"unit":{"examples":["ks","h","kg"],"type":"string"},"vat":{"examples":[21],"type":"number"},"creditAmount":{"examples":[100],"type":"number"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"event":{"type":"object","required":["id","calendarId","startTime","endTime","isAllDay","isBlocking","isStorno"],"properties":{"id":{"examples":["7lRIAiC69gZMfwsDbG3CJvQdqnY15XdS"],"type":"string"},"calendarId":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"type":"string"},"startTime":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"examples":["Jan Barášek GymRoom Vinohrady rezervace"],"type":"string"},"isAllDay":{"default":false,"type":"boolean"},"isBlocking":{"default":true,"type":"boolean"},"isStorno":{"default":true,"type":"boolean"}}}}}}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","orderNumber","status","price","insertedDate","updatedDate","lines"],"properties":{"id":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"orderNumber":{"examples":["25000055"],"type":"string"},"status":{"type":"object","required":["label","code","backgroundColor","textColor"],"properties":{"label":{"examples":["Storno"],"type":"string"},"code":{"examples":["storno"],"type":"string"},"backgroundColor":{"examples":["#901020"],"type":"string"},"textColor":{"examples":["#fff"],"type":"string"}}},"price":{"examples":["0&nbsp;Kč"],"type":"string"},"notice":{"examples":["Please reserve a trainer to me."],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lines":{"type":"array","items":{"type":"object","required":["id","label","count","storno","price","insertedDate"],"properties":{"id":{"examples":["2d33677772eddbd4e869c6ed6bf6d9f3"],"type":"string"},"label":{"examples":["Jan Barášek GymRoom Vinohrady rezervace"],"type":"string"},"count":{"examples":[1],"type":"number"},"storno":{"default":false,"type":"boolean"},"price":{"examples":["110&nbsp;Kč"],"type":"string"},"unit":{"examples":["ks","h","kg"],"type":"string"},"vat":{"examples":[21],"type":"number"},"creditAmount":{"examples":[100],"type":"number"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"event":{"type":"object","required":["id","calendarId","startTime","endTime","isAllDay","isBlocking","isStorno"],"properties":{"id":{"examples":["7lRIAiC69gZMfwsDbG3CJvQdqnY15XdS"],"type":"string"},"calendarId":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"type":"string"},"startTime":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"examples":["Jan Barášek GymRoom Vinohrady rezervace"],"type":"string"},"isAllDay":{"default":false,"type":"boolean"},"isBlocking":{"default":true,"type":"boolean"},"isStorno":{"default":true,"type":"boolean"}}}}}}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","orderNumber","status","price","insertedDate","updatedDate","lines"],"properties":{"id":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"orderNumber":{"examples":["25000055"],"type":"string"},"status":{"type":"object","required":["label","code","backgroundColor","textColor"],"properties":{"label":{"examples":["Storno"],"type":"string"},"code":{"examples":["storno"],"type":"string"},"backgroundColor":{"examples":["#901020"],"type":"string"},"textColor":{"examples":["#fff"],"type":"string"}}},"price":{"examples":["0&nbsp;Kč"],"type":"string"},"notice":{"examples":["Please reserve a trainer to me."],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lines":{"type":"array","items":{"type":"object","required":["id","label","count","storno","price","insertedDate"],"properties":{"id":{"examples":["2d33677772eddbd4e869c6ed6bf6d9f3"],"type":"string"},"label":{"examples":["Jan Barášek GymRoom Vinohrady rezervace"],"type":"string"},"count":{"examples":[1],"type":"number"},"storno":{"default":false,"type":"boolean"},"price":{"examples":["110&nbsp;Kč"],"type":"string"},"unit":{"examples":["ks","h","kg"],"type":"string"},"vat":{"examples":[21],"type":"number"},"creditAmount":{"examples":[100],"type":"number"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"event":{"type":"object","required":["id","calendarId","startTime","endTime","isAllDay","isBlocking","isStorno"],"properties":{"id":{"examples":["7lRIAiC69gZMfwsDbG3CJvQdqnY15XdS"],"type":"string"},"calendarId":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"type":"string"},"startTime":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"examples":["Jan Barášek GymRoom Vinohrady rezervace"],"type":"string"},"isAllDay":{"default":false,"type":"boolean"},"isBlocking":{"default":true,"type":"boolean"},"isStorno":{"default":true,"type":"boolean"}}}}}}}}}},"required":["items"]}}}}},"operationId":"getApiV1CustomerOrder-list","tags":["customer"],"summary":"List customer orders","description":"Returns a paginated list of orders for the customer identified by identityId, including order lines, status, prices, and linked calendar events."}},"/api/v1/customer/update-profile":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CustomerUpdate-profile","tags":["customer"],"summary":"Update customer profile","description":"Updates the profile of an existing customer identified by email in the request body.","requestBody":{"required":true,"content":{"application/json":{"schema":{"description":"Paying customer (payer). This customer pays the order and is used as the primary billing entity. If the specified customer account does not exist, the system will automatically create a new customer and link it to the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}}},"multipart/form-data":{"schema":{"description":"Paying customer (payer). This customer pays the order and is used as the primary billing entity. If the specified customer account does not exist, the system will automatically create a new customer and link it to the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}}},"text/plain":{"schema":{"description":"Paying customer (payer). This customer pays the order and is used as the primary billing entity. If the specified customer account does not exist, the system will automatically create a new customer and link it to the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}}}}}}},"/api/v1/customer/register-account":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Customer register failed.","Customer has been registered.","Customer account has been banned.","Too many registration attempts."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Customer register failed.","Customer has been registered.","Customer account has been banned.","Too many registration attempts."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Customer register failed.","Customer has been registered.","Customer account has been banned.","Too many registration attempts."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Customer register failed.","Customer has been registered.","Customer account has been banned.","Too many registration attempts."],"type":"string"}}}]}}}}},"operationId":"postApiV1CustomerRegister-account","tags":["customer"],"summary":"Register customer account","description":"Registers a new customer account with email and password. Sends a verification email. Returns error codes on validation failure.\n\nList of error codes:\n\n| Code | Message |\n|------|---------|\n| E001 | Customer register failed. |\n| E002 | Customer has been registered. |\n| E003 | Customer account has been banned. |\n| E004 | Too many registration attempts. |","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"password":{"minLength":1,"type":"string"},"returnUrl":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"password":{"minLength":1,"type":"string"},"returnUrl":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"password":{"minLength":1,"type":"string"},"returnUrl":{"type":"string"}}}}}}}},"/api/v1/customer/register-account-verify":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"examples":[true],"type":"boolean"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"returnUrl":{"type":"string"}},"required":["success","email"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"examples":[true],"type":"boolean"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"returnUrl":{"type":"string"}},"required":["success","email"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"examples":[true],"type":"boolean"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"returnUrl":{"type":"string"}},"required":["success","email"]}}}}},"operationId":"postApiV1CustomerRegister-account-verify","tags":["customer"],"summary":"Verify account registration","description":"Verifies a customer registration using the one-time token sent via email. Returns the customer email and optional return URL.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"description":"One-time verification token from the registration email.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["token"],"properties":{"token":{"description":"One-time verification token from the registration email.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["token"],"properties":{"token":{"description":"One-time verification token from the registration email.","type":"string"}}}}}}}},"/api/v1/customer/reset-password":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CustomerReset-password","tags":["customer"],"summary":"Request password reset","description":"Create a new reset password request and send verification mail to customer automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"expirationTime":{"examples":["3h 20m"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"expirationTime":{"examples":["3h 20m"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"expirationTime":{"examples":["3h 20m"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}}}}}},"/api/v1/customer/set-new-password":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Change password failed.","You have entered a previously used password. For security reasons, please enter a new and unique password.","Reset password request does not exist.","Reset password request has been expired."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Change password failed.","You have entered a previously used password. For security reasons, please enter a new and unique password.","Reset password request does not exist.","Reset password request has been expired."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Change password failed.","You have entered a previously used password. For security reasons, please enter a new and unique password.","Reset password request does not exist.","Reset password request has been expired."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Change password failed.","You have entered a previously used password. For security reasons, please enter a new and unique password.","Reset password request does not exist.","Reset password request has been expired."],"type":"string"}}}]}}}}},"operationId":"postApiV1CustomerSet-new-password","tags":["customer"],"summary":"Set new password","description":"Set a new password based on one time token given from user verification e-mail.\n\nList of error codes:\n\n| Code | Message |\n|------|---------|\n| E001 | Change password failed. |\n| E002 | You have entered a previously used password. For security reasons, please enter a new and unique password. |\n| E003 | Reset password request does not exist. |\n| E004 | Reset password request has been expired. |","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","password"],"properties":{"token":{"examples":["Hm2cDfmTS8x49Mo67gOxId8gEwNBwf1A"],"description":"System one time token given from user verification e-mail.","type":"string"},"password":{"examples":["1234"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["token","password"],"properties":{"token":{"examples":["Hm2cDfmTS8x49Mo67gOxId8gEwNBwf1A"],"description":"System one time token given from user verification e-mail.","type":"string"},"password":{"examples":["1234"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["token","password"],"properties":{"token":{"examples":["Hm2cDfmTS8x49Mo67gOxId8gEwNBwf1A"],"description":"System one time token given from user verification e-mail.","type":"string"},"password":{"examples":["1234"],"type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}}}}}},"/api/v1/customer/list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Number of items per page.","schema":{"type":"number","default":100},"in":"query","name":"limit","required":true},{"description":"Page number.","schema":{"type":"number","default":1},"in":"query","name":"page","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"itemCount":{"examples":[10],"type":"number"},"items":{"type":"array","items":{"type":"object","required":["cuRefNo","email","locale","registered","premium","credit","referredCustomerCount","insertedDate","updatedDate","lastActivityDate"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"registered":{"examples":[true],"type":"boolean"},"premium":{"examples":[true],"type":"boolean"},"credit":{"examples":[123],"type":"number"},"referralCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Parent referral customer relation.","type":"string"},"referredCustomerCount":{"examples":[2],"description":"Number of customer who referred this customer.","type":"number"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["itemCount","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"itemCount":{"examples":[10],"type":"number"},"items":{"type":"array","items":{"type":"object","required":["cuRefNo","email","locale","registered","premium","credit","referredCustomerCount","insertedDate","updatedDate","lastActivityDate"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"registered":{"examples":[true],"type":"boolean"},"premium":{"examples":[true],"type":"boolean"},"credit":{"examples":[123],"type":"number"},"referralCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Parent referral customer relation.","type":"string"},"referredCustomerCount":{"examples":[2],"description":"Number of customer who referred this customer.","type":"number"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["itemCount","items"]}},"text/plain":{"schema":{"type":"object","properties":{"itemCount":{"examples":[10],"type":"number"},"items":{"type":"array","items":{"type":"object","required":["cuRefNo","email","locale","registered","premium","credit","referredCustomerCount","insertedDate","updatedDate","lastActivityDate"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"registered":{"examples":[true],"type":"boolean"},"premium":{"examples":[true],"type":"boolean"},"credit":{"examples":[123],"type":"number"},"referralCuRefNo":{"examples":["5CmsaVNgAQqRqoen"],"description":"Parent referral customer relation.","type":"string"},"referredCustomerCount":{"examples":[2],"description":"Number of customer who referred this customer.","type":"number"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["itemCount","items"]}}}}},"operationId":"getApiV1CustomerList","tags":["customer"],"summary":"List customers","description":"Returns a paginated list of all customers in the organisation."}},"/api/v1/customer/add-bank-account":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CustomerAdd-bank-account","tags":["customer"],"summary":"Add bank account","description":"Links a bank account number to a customer identified by cuRefNo.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cuRefNo","bankAccount"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"bankAccount":{"examples":["CZ5420100000002002770630","2002770630/2010","000000-2002770630/2010","20027706302010"],"description":"- **Digits-only technical formats** (Czech accounts only):\n  - 20 digits BBAN: `BBBBPPPPPPAAAAAAAAAA` (bank 4 + prefix 6 + account 10).\n  - 22 digits: `CCBBBB...` where it represents `CZ` + check digits + BBAN without the country prefix.\n  - Without separators: `<account+optional prefix><bank>`, e.g. `20027706302010`.\n\nInvalid input: If the value contains letters but is not a valid/repairable IBAN, conversion fails and the endpoint returns `{ success: false }`.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["cuRefNo","bankAccount"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"bankAccount":{"examples":["CZ5420100000002002770630","2002770630/2010","000000-2002770630/2010","20027706302010"],"description":"- **Digits-only technical formats** (Czech accounts only):\n  - 20 digits BBAN: `BBBBPPPPPPAAAAAAAAAA` (bank 4 + prefix 6 + account 10).\n  - 22 digits: `CCBBBB...` where it represents `CZ` + check digits + BBAN without the country prefix.\n  - Without separators: `<account+optional prefix><bank>`, e.g. `20027706302010`.\n\nInvalid input: If the value contains letters but is not a valid/repairable IBAN, conversion fails and the endpoint returns `{ success: false }`.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["cuRefNo","bankAccount"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"bankAccount":{"examples":["CZ5420100000002002770630","2002770630/2010","000000-2002770630/2010","20027706302010"],"description":"- **Digits-only technical formats** (Czech accounts only):\n  - 20 digits BBAN: `BBBBPPPPPPAAAAAAAAAA` (bank 4 + prefix 6 + account 10).\n  - 22 digits: `CCBBBB...` where it represents `CZ` + check digits + BBAN without the country prefix.\n  - Without separators: `<account+optional prefix><bank>`, e.g. `20027706302010`.\n\nInvalid input: If the value contains letters but is not a valid/repairable IBAN, conversion fails and the endpoint returns `{ success: false }`.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"}}}}}}}},"/api/v1/customer/hierarchy":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"cuRefNo = customer reference number.","examples":["1cGIHvFoQDGLAbcA"],"schema":{"type":"string","maxLength":16,"minLength":16},"in":"query","name":"cuRefNo","required":true}],"operationId":"getApiV1CustomerHierarchy","tags":["customer"],"summary":"Get customer hierarchy","description":"Returns the superior (at most one), subordinates (direct children), and colleagues (customers sharing the same non-null superior) for the given customer.","responses":{"200":{}}}},"/api/v1/customer/set-parent":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1CustomerSet-parent","tags":["customer"],"summary":"Set customer superior","description":"Assigns a parent (superior) customer for the given `cuRefNo`. Pass null/omit `parentCuRefNo` to detach. Rejected when the target would create a cycle or when customer equals parent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cuRefNo"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"parentCuRefNo":{"nullable":true,"anyOf":[{"examples":["1cGIHvFoQDGLAbcA"],"description":"External ID of the new superior. Pass null or omit to detach (customer becomes a root node).","maxLength":16,"minLength":16,"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["cuRefNo"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"parentCuRefNo":{"nullable":true,"anyOf":[{"examples":["1cGIHvFoQDGLAbcA"],"description":"External ID of the new superior. Pass null or omit to detach (customer becomes a root node).","maxLength":16,"minLength":16,"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["cuRefNo"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"parentCuRefNo":{"nullable":true,"anyOf":[{"examples":["1cGIHvFoQDGLAbcA"],"description":"External ID of the new superior. Pass null or omit to detach (customer becomes a root node).","maxLength":16,"minLength":16,"type":"string"},{"type":"null"}]}}}}}}}},"/api/v1/customer/org-tree":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"cuRefNo = customer reference number.","examples":["1cGIHvFoQDGLAbcA"],"schema":{"type":"string","maxLength":16,"minLength":16},"in":"query","name":"cuRefNo","required":true}],"operationId":"getApiV1CustomerOrg-tree","tags":["customer"],"summary":"Get organisational tree","description":"Returns the focused customer together with ancestors (root-first) and the full subtree rooted at the focused customer. Depth capped at 32 levels in each direction.","responses":{"200":{}}}},"/api/v1/disk/store-pdf":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"examples":[true],"type":"boolean"},"downloadUrl":{"description":"Resolvable public URL for downloading the stored PDF.","examples":["https://storage.xhp.cz/..."],"type":"string"},"token":{"description":"Blob access token (storage-level).","examples":["abc123..."],"type":"string"},"blobPath":{"description":"Internal blob path inside storage.","examples":["pdf/2026-01/invoice_..._R4nd0mStr1ng.pdf"],"type":"string"},"size":{"description":"Stored PDF size in bytes.","examples":[153042],"type":"number"}},"required":["success","downloadUrl","token","blobPath","size"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"examples":[true],"type":"boolean"},"downloadUrl":{"description":"Resolvable public URL for downloading the stored PDF.","examples":["https://storage.xhp.cz/..."],"type":"string"},"token":{"description":"Blob access token (storage-level).","examples":["abc123..."],"type":"string"},"blobPath":{"description":"Internal blob path inside storage.","examples":["pdf/2026-01/invoice_..._R4nd0mStr1ng.pdf"],"type":"string"},"size":{"description":"Stored PDF size in bytes.","examples":[153042],"type":"number"}},"required":["success","downloadUrl","token","blobPath","size"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"examples":[true],"type":"boolean"},"downloadUrl":{"description":"Resolvable public URL for downloading the stored PDF.","examples":["https://storage.xhp.cz/..."],"type":"string"},"token":{"description":"Blob access token (storage-level).","examples":["abc123..."],"type":"string"},"blobPath":{"description":"Internal blob path inside storage.","examples":["pdf/2026-01/invoice_..._R4nd0mStr1ng.pdf"],"type":"string"},"size":{"description":"Stored PDF size in bytes.","examples":[153042],"type":"number"}},"required":["success","downloadUrl","token","blobPath","size"]}}}}},"operationId":"diskStorePdf","tags":["disk"],"summary":"Generate PDF from HTML and store it to blob storage","description":"Generates a PDF from provided HTML using the BizKitHub PDF generator parameters, stores it in blob storage, and returns a public download URL.\n\nSizing priority: width overrides format. Optional height makes page size explicit. autoHeight enables print-safe margins; margin overrides them. fitHeight enables single-page receipt mode.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["htmlContent","filename"],"properties":{"htmlContent":{"description":"HTML content to render into PDF. This is sent as the generator request body (compressed).","examples":["<!doctype html><html><body><h1>Invoice #123</h1></body></html>"],"type":"string"},"filename":{"description":"Original filename. The service normalizes it, appends a random suffix, and forces the .pdf extension.","examples":["invoice-123.pdf"],"type":"string"},"tag":{"description":"Optional storage tag (internal metadata label).","examples":["invoice","contract","report"],"type":"string"},"format":{"description":"Standard paper format (e.g. A4, Letter, …). Used when width is not set. Default is A4.","examples":["A4","Letter"],"type":"string"},"width":{"description":"Custom page width (CSS length, e.g. 80mm, 210mm, 800px). When set, it overrides format.","examples":["80mm","210mm","800px"],"type":"string"},"height":{"description":"Custom page height (CSS length). Used in fixed-size mode. When width is set and fitHeight is not enabled, height defaults like A4 height behavior.","examples":["150mm","297mm"],"type":"string"},"autoHeight":{"description":"Enables print-safe margins consistently across pages (improves page breaks and prevents edge clipping).","examples":[true],"type":"boolean"},"margin":{"description":"Overrides margin size when autoHeight=true. CSS shorthand (1–4 values), e.g. \"12mm 10mm\" or \"2mm\".","examples":["12mm 10mm","2mm"],"type":"string"},"fitHeight":{"description":"Receipt mode: generates a single-page PDF whose height is derived from rendered content. Works best with width (e.g. 80mm).","examples":[true],"type":"boolean"},"uuid":{"description":"Optional identifier stored in PDF metadata keywords.","examples":["order_123","invoice_2026_0001"],"type":"string"},"author":{"description":"Optional author label in PDF metadata (Author/Creator/Producer). If omitted, defaults to organisation name.","examples":["BizKitHub","Jan Barášek"],"type":"string"},"debug":{"description":"Adds debug CSS borders to the rendered HTML for layout inspection (internal).","examples":[true],"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["htmlContent","filename"],"properties":{"htmlContent":{"description":"HTML content to render into PDF. This is sent as the generator request body (compressed).","examples":["<!doctype html><html><body><h1>Invoice #123</h1></body></html>"],"type":"string"},"filename":{"description":"Original filename. The service normalizes it, appends a random suffix, and forces the .pdf extension.","examples":["invoice-123.pdf"],"type":"string"},"tag":{"description":"Optional storage tag (internal metadata label).","examples":["invoice","contract","report"],"type":"string"},"format":{"description":"Standard paper format (e.g. A4, Letter, …). Used when width is not set. Default is A4.","examples":["A4","Letter"],"type":"string"},"width":{"description":"Custom page width (CSS length, e.g. 80mm, 210mm, 800px). When set, it overrides format.","examples":["80mm","210mm","800px"],"type":"string"},"height":{"description":"Custom page height (CSS length). Used in fixed-size mode. When width is set and fitHeight is not enabled, height defaults like A4 height behavior.","examples":["150mm","297mm"],"type":"string"},"autoHeight":{"description":"Enables print-safe margins consistently across pages (improves page breaks and prevents edge clipping).","examples":[true],"type":"boolean"},"margin":{"description":"Overrides margin size when autoHeight=true. CSS shorthand (1–4 values), e.g. \"12mm 10mm\" or \"2mm\".","examples":["12mm 10mm","2mm"],"type":"string"},"fitHeight":{"description":"Receipt mode: generates a single-page PDF whose height is derived from rendered content. Works best with width (e.g. 80mm).","examples":[true],"type":"boolean"},"uuid":{"description":"Optional identifier stored in PDF metadata keywords.","examples":["order_123","invoice_2026_0001"],"type":"string"},"author":{"description":"Optional author label in PDF metadata (Author/Creator/Producer). If omitted, defaults to organisation name.","examples":["BizKitHub","Jan Barášek"],"type":"string"},"debug":{"description":"Adds debug CSS borders to the rendered HTML for layout inspection (internal).","examples":[true],"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["htmlContent","filename"],"properties":{"htmlContent":{"description":"HTML content to render into PDF. This is sent as the generator request body (compressed).","examples":["<!doctype html><html><body><h1>Invoice #123</h1></body></html>"],"type":"string"},"filename":{"description":"Original filename. The service normalizes it, appends a random suffix, and forces the .pdf extension.","examples":["invoice-123.pdf"],"type":"string"},"tag":{"description":"Optional storage tag (internal metadata label).","examples":["invoice","contract","report"],"type":"string"},"format":{"description":"Standard paper format (e.g. A4, Letter, …). Used when width is not set. Default is A4.","examples":["A4","Letter"],"type":"string"},"width":{"description":"Custom page width (CSS length, e.g. 80mm, 210mm, 800px). When set, it overrides format.","examples":["80mm","210mm","800px"],"type":"string"},"height":{"description":"Custom page height (CSS length). Used in fixed-size mode. When width is set and fitHeight is not enabled, height defaults like A4 height behavior.","examples":["150mm","297mm"],"type":"string"},"autoHeight":{"description":"Enables print-safe margins consistently across pages (improves page breaks and prevents edge clipping).","examples":[true],"type":"boolean"},"margin":{"description":"Overrides margin size when autoHeight=true. CSS shorthand (1–4 values), e.g. \"12mm 10mm\" or \"2mm\".","examples":["12mm 10mm","2mm"],"type":"string"},"fitHeight":{"description":"Receipt mode: generates a single-page PDF whose height is derived from rendered content. Works best with width (e.g. 80mm).","examples":[true],"type":"boolean"},"uuid":{"description":"Optional identifier stored in PDF metadata keywords.","examples":["order_123","invoice_2026_0001"],"type":"string"},"author":{"description":"Optional author label in PDF metadata (Author/Creator/Producer). If omitted, defaults to organisation name.","examples":["BizKitHub","Jan Barášek"],"type":"string"},"debug":{"description":"Adds debug CSS borders to the rendered HTML for layout inspection (internal).","examples":[true],"type":"boolean"}}}}}}}},"/api/v1/disk/store-blob":{"post":{"parameters":[],"operationId":"postApiV1DiskStore-blob","tags":["disk"],"summary":"Upload file to blob storage","description":"Uploads a file via multipart/form-data to blob storage and returns a public download URL. Form fields: `file` (required, the file blob), `blobPath` (optional, storage directory prefix), `tag` (optional, metadata label).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["file"],"properties":{"file":{"default":"File","description":"Binary file payload.","type":"string","format":"binary"},"blobPath":{"description":"Optional storage directory prefix.","type":"string"},"tag":{"description":"Optional metadata label.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"default":"File","description":"Binary file payload.","type":"string","format":"binary"},"blobPath":{"description":"Optional storage directory prefix.","type":"string"},"tag":{"description":"Optional metadata label.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["file"],"properties":{"file":{"default":"File","description":"Binary file payload.","type":"string","format":"binary"},"blobPath":{"description":"Optional storage directory prefix.","type":"string"},"tag":{"description":"Optional metadata label.","type":"string"}}}}}},"responses":{"200":{}}}},"/api/v1/disk/store-contract":{"post":{"operationId":"postApiV1DiskStore-contract","tags":["disk"],"summary":"Store contract (not implemented)","description":"Placeholder endpoint for contract storage. Not yet implemented.","responses":{"200":{}}}},"/api/v1/docs/error-list":{"get":{"responses":{"200":{"description":"Complete error code reference.","content":{"application/json":{"schema":{"type":"object","properties":{"errorList":{"description":"Map of error codes to their definitions.","type":"object","patternProperties":{"^(.*)$":{"type":"object","required":["message"],"properties":{"message":{"description":"Short error message.","type":"string"},"httpStatusCode":{"description":"Suggested HTTP status code.","examples":[400,404,500],"type":"number"},"description":{"description":"Detailed explanation of the error.","type":"string"},"troubleshoot":{"description":"List of troubleshooting steps.","type":"array","items":{"type":"string"}}}}}}},"required":["errorList"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"errorList":{"description":"Map of error codes to their definitions.","type":"object","patternProperties":{"^(.*)$":{"type":"object","required":["message"],"properties":{"message":{"description":"Short error message.","type":"string"},"httpStatusCode":{"description":"Suggested HTTP status code.","examples":[400,404,500],"type":"number"},"description":{"description":"Detailed explanation of the error.","type":"string"},"troubleshoot":{"description":"List of troubleshooting steps.","type":"array","items":{"type":"string"}}}}}}},"required":["errorList"]}},"text/plain":{"schema":{"type":"object","properties":{"errorList":{"description":"Map of error codes to their definitions.","type":"object","patternProperties":{"^(.*)$":{"type":"object","required":["message"],"properties":{"message":{"description":"Short error message.","type":"string"},"httpStatusCode":{"description":"Suggested HTTP status code.","examples":[400,404,500],"type":"number"},"description":{"description":"Detailed explanation of the error.","type":"string"},"troubleshoot":{"description":"List of troubleshooting steps.","type":"array","items":{"type":"string"}}}}}}},"required":["errorList"]}}}}},"operationId":"getApiV1DocsError-list","tags":["docs"],"summary":"List all error codes","description":"Returns a dictionary of all known application error codes with their messages, descriptions, and troubleshooting hints."}},"/api/v1/docs/env-list":{"get":{"responses":{"200":{"description":"Configuration key reference.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"List of configuration entries.","type":"array","items":{"type":"object","required":["key"],"properties":{"key":{"description":"Configuration key name.","examples":["comgate_merchant_id"],"type":"string"},"description":{"description":"Human-readable description of the key.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"List of configuration entries.","type":"array","items":{"type":"object","required":["key"],"properties":{"key":{"description":"Configuration key name.","examples":["comgate_merchant_id"],"type":"string"},"description":{"description":"Human-readable description of the key.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"List of configuration entries.","type":"array","items":{"type":"object","required":["key"],"properties":{"key":{"description":"Configuration key name.","examples":["comgate_merchant_id"],"type":"string"},"description":{"description":"Human-readable description of the key.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getApiV1DocsEnv-list","tags":["docs"],"summary":"List configuration keys","description":"Returns a list of all available configuration keys (environment variables / app settings) with their descriptions."}},"/api/v1/docs/page":{"get":{"parameters":[{"description":"Documentation page slug.","examples":["getting-started"],"schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"operationId":"getApiV1DocsPage","tags":["docs"],"summary":"Get documentation page (public)","description":"Returns a public documentation page by slug with locale fallback. Content is rendered from Markdown to HTML with anchor list extraction. Powers docs.bizkithub.com — the same content rendered in the admin help center is served here. Returns { found: false } when the page does not exist.","responses":{"200":{}}}},"/api/v1/docs/list":{"get":{"parameters":[{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","required":["id","name","articles"],"properties":{"id":{"description":"Category external ID.","type":"string"},"name":{"description":"Localized category name.","type":"string"},"articles":{"type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}}}},"uncategorized":{"type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}},"required":["categories","uncategorized"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","required":["id","name","articles"],"properties":{"id":{"description":"Category external ID.","type":"string"},"name":{"description":"Localized category name.","type":"string"},"articles":{"type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}}}},"uncategorized":{"type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}},"required":["categories","uncategorized"]}},"text/plain":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","required":["id","name","articles"],"properties":{"id":{"description":"Category external ID.","type":"string"},"name":{"description":"Localized category name.","type":"string"},"articles":{"type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}}}},"uncategorized":{"type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}},"required":["categories","uncategorized"]}}}}},"operationId":"getApiV1DocsList","tags":["docs"],"summary":"List documentation pages (public)","description":"Returns all published documentation pages grouped by category. Public mirror of /bff/doc/list — same dataset, no session required."}},"/api/v1/emailer/send":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1EmailerSend","tags":["emailer"],"summary":"Send email","description":"Queues or immediately sends an email through the organisation mail system. Supports HTML body, attachments (from blob storage, URL, or raw text), and priority control.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subject","to"],"properties":{"subject":{"description":"Email subject line.","examples":["Order confirmation #12345"],"type":"string"},"from":{"description":"Sender email address or name+email. If omitted, organisation default is used.","examples":["support@example.com"],"type":"string"},"to":{"description":"Recipient email address.","examples":["customer@example.com"],"type":"string"},"cc":{"description":"CC recipient email address.","type":"string"},"bcc":{"description":"BCC recipient email address.","type":"string"},"replyTo":{"description":"Reply-To email address.","type":"string"},"priority":{"description":"Email priority (lower = higher priority). Default queue priority if omitted.","examples":[1,5,10],"type":"number"},"note":{"description":"Internal note attached to the email record (not sent to recipient).","type":"string"},"htmlBody":{"description":"HTML content of the email body.","type":"string"},"tag":{"description":"Tag for categorizing the email (e.g. for analytics).","examples":["order-confirmation","newsletter"],"type":"string"},"forceSendNow":{"description":"If true, send immediately bypassing the queue. Default: false.","type":"boolean"},"attachmentList":{"description":"List of attachments. Each item is one of blobToken, attachmentUrl, or rawTextContent.","type":"array","items":{"anyOf":[{"type":"object","required":["blobToken"],"properties":{"blobToken":{"description":"Token of a file stored in blob storage.","type":"string"}}},{"type":"object","required":["attachmentUrl"],"properties":{"attachmentUrl":{"description":"Public URL of the file to attach.","type":"string"}}},{"type":"object","required":["rawTextContent"],"properties":{"rawTextContent":{"description":"Raw text content to attach as a file.","type":"string"}}}]}}}}},"multipart/form-data":{"schema":{"type":"object","required":["subject","to"],"properties":{"subject":{"description":"Email subject line.","examples":["Order confirmation #12345"],"type":"string"},"from":{"description":"Sender email address or name+email. If omitted, organisation default is used.","examples":["support@example.com"],"type":"string"},"to":{"description":"Recipient email address.","examples":["customer@example.com"],"type":"string"},"cc":{"description":"CC recipient email address.","type":"string"},"bcc":{"description":"BCC recipient email address.","type":"string"},"replyTo":{"description":"Reply-To email address.","type":"string"},"priority":{"description":"Email priority (lower = higher priority). Default queue priority if omitted.","examples":[1,5,10],"type":"number"},"note":{"description":"Internal note attached to the email record (not sent to recipient).","type":"string"},"htmlBody":{"description":"HTML content of the email body.","type":"string"},"tag":{"description":"Tag for categorizing the email (e.g. for analytics).","examples":["order-confirmation","newsletter"],"type":"string"},"forceSendNow":{"description":"If true, send immediately bypassing the queue. Default: false.","type":"boolean"},"attachmentList":{"description":"List of attachments. Each item is one of blobToken, attachmentUrl, or rawTextContent.","type":"array","items":{"anyOf":[{"type":"object","required":["blobToken"],"properties":{"blobToken":{"description":"Token of a file stored in blob storage.","type":"string"}}},{"type":"object","required":["attachmentUrl"],"properties":{"attachmentUrl":{"description":"Public URL of the file to attach.","type":"string"}}},{"type":"object","required":["rawTextContent"],"properties":{"rawTextContent":{"description":"Raw text content to attach as a file.","type":"string"}}}]}}}}},"text/plain":{"schema":{"type":"object","required":["subject","to"],"properties":{"subject":{"description":"Email subject line.","examples":["Order confirmation #12345"],"type":"string"},"from":{"description":"Sender email address or name+email. If omitted, organisation default is used.","examples":["support@example.com"],"type":"string"},"to":{"description":"Recipient email address.","examples":["customer@example.com"],"type":"string"},"cc":{"description":"CC recipient email address.","type":"string"},"bcc":{"description":"BCC recipient email address.","type":"string"},"replyTo":{"description":"Reply-To email address.","type":"string"},"priority":{"description":"Email priority (lower = higher priority). Default queue priority if omitted.","examples":[1,5,10],"type":"number"},"note":{"description":"Internal note attached to the email record (not sent to recipient).","type":"string"},"htmlBody":{"description":"HTML content of the email body.","type":"string"},"tag":{"description":"Tag for categorizing the email (e.g. for analytics).","examples":["order-confirmation","newsletter"],"type":"string"},"forceSendNow":{"description":"If true, send immediately bypassing the queue. Default: false.","type":"boolean"},"attachmentList":{"description":"List of attachments. Each item is one of blobToken, attachmentUrl, or rawTextContent.","type":"array","items":{"anyOf":[{"type":"object","required":["blobToken"],"properties":{"blobToken":{"description":"Token of a file stored in blob storage.","type":"string"}}},{"type":"object","required":["attachmentUrl"],"properties":{"attachmentUrl":{"description":"Public URL of the file to attach.","type":"string"}}},{"type":"object","required":["rawTextContent"],"properties":{"rawTextContent":{"description":"Raw text content to attach as a file.","type":"string"}}}]}}}}}}}}},"/api/v1/emailer/webhook-incoming-email":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1EmailerWebhook-incoming-email","tags":["emailer"],"summary":"Incoming email webhook","description":"Receives incoming email data from an external email provider webhook. The body format depends on the provider and is processed internally.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","patternProperties":{"^(.*)$":{}}}},"multipart/form-data":{"schema":{"type":"object","patternProperties":{"^(.*)$":{}}}},"text/plain":{"schema":{"type":"object","patternProperties":{"^(.*)$":{}}}}}}}},"/api/v1/form/detail":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Unique form code identifier.","examples":["contact-form"],"schema":{"type":"string"},"in":"query","name":"code","required":false}],"responses":{"200":{"description":"Form definition.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Form code (unique identifier).","examples":["contact-form"],"type":"string"},"name":{"description":"Display name of the form.","examples":["Contact Form"],"type":"string"},"description":{"description":"Form description or instructions.","type":"string"},"fields":{"description":"Ordered list of active form fields.","type":"array","items":{"type":"object","required":["key","type","label","required"],"properties":{"key":{"description":"Field key used for form submission.","examples":["email","message"],"type":"string"},"type":{"description":"Field type.","examples":["text","email","textarea","select","checkbox"],"type":"string"},"label":{"description":"Human-readable field label.","examples":["Your email"],"type":"string"},"helperText":{"description":"Additional helper text shown below the field.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"defaultValue":{"description":"Pre-filled default value.","type":"string"},"options":{"description":"Key-value map of options for select/radio fields.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}}}}}},"required":["id","name","fields"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Form code (unique identifier).","examples":["contact-form"],"type":"string"},"name":{"description":"Display name of the form.","examples":["Contact Form"],"type":"string"},"description":{"description":"Form description or instructions.","type":"string"},"fields":{"description":"Ordered list of active form fields.","type":"array","items":{"type":"object","required":["key","type","label","required"],"properties":{"key":{"description":"Field key used for form submission.","examples":["email","message"],"type":"string"},"type":{"description":"Field type.","examples":["text","email","textarea","select","checkbox"],"type":"string"},"label":{"description":"Human-readable field label.","examples":["Your email"],"type":"string"},"helperText":{"description":"Additional helper text shown below the field.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"defaultValue":{"description":"Pre-filled default value.","type":"string"},"options":{"description":"Key-value map of options for select/radio fields.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}}}}}},"required":["id","name","fields"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Form code (unique identifier).","examples":["contact-form"],"type":"string"},"name":{"description":"Display name of the form.","examples":["Contact Form"],"type":"string"},"description":{"description":"Form description or instructions.","type":"string"},"fields":{"description":"Ordered list of active form fields.","type":"array","items":{"type":"object","required":["key","type","label","required"],"properties":{"key":{"description":"Field key used for form submission.","examples":["email","message"],"type":"string"},"type":{"description":"Field type.","examples":["text","email","textarea","select","checkbox"],"type":"string"},"label":{"description":"Human-readable field label.","examples":["Your email"],"type":"string"},"helperText":{"description":"Additional helper text shown below the field.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"defaultValue":{"description":"Pre-filled default value.","type":"string"},"options":{"description":"Key-value map of options for select/radio fields.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}}}}}},"required":["id","name","fields"]}}}}},"operationId":"getApiV1FormDetail","tags":["form"],"summary":"Get form detail","description":"Returns form definition with all active fields, their types, labels, and validation rules. Throws PUBLIC_FORM_DOES_NOT_EXIST if the form is not found or inactive."}},"/api/v1/link-shorten/create-link":{"post":{"parameters":[],"responses":{"200":{"description":"Shortened link result.","content":{"application/json":{"schema":{"type":"object","properties":{"originalUrl":{"description":"The original URL that was shortened.","type":"string"},"shortUrl":{"description":"The generated short URL.","examples":["https://xhp.cz/my-link"],"type":"string"}},"required":["originalUrl","shortUrl"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"originalUrl":{"description":"The original URL that was shortened.","type":"string"},"shortUrl":{"description":"The generated short URL.","examples":["https://xhp.cz/my-link"],"type":"string"}},"required":["originalUrl","shortUrl"]}},"text/plain":{"schema":{"type":"object","properties":{"originalUrl":{"description":"The original URL that was shortened.","type":"string"},"shortUrl":{"description":"The generated short URL.","examples":["https://xhp.cz/my-link"],"type":"string"}},"required":["originalUrl","shortUrl"]}}}}},"operationId":"postApiV1Link-shortenCreate-link","tags":["linkShorten"],"summary":"Create a shortened link","description":"Creates a shortened URL. Optionally accepts a custom alias and expiration date. Returns both the original and the shortened URL.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"description":"The original URL to shorten.","examples":["https://example.com/very/long/path"],"type":"string"},"customAlias":{"description":"Custom short URL alias. If omitted, a random alias is generated.","examples":["my-link"],"type":"string"},"expiresAt":{"description":"Expiration date in ISO 8601 format. Link becomes invalid after this date.","examples":["2026-12-31T23:59:59Z"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["url"],"properties":{"url":{"description":"The original URL to shorten.","examples":["https://example.com/very/long/path"],"type":"string"},"customAlias":{"description":"Custom short URL alias. If omitted, a random alias is generated.","examples":["my-link"],"type":"string"},"expiresAt":{"description":"Expiration date in ISO 8601 format. Link becomes invalid after this date.","examples":["2026-12-31T23:59:59Z"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["url"],"properties":{"url":{"description":"The original URL to shorten.","examples":["https://example.com/very/long/path"],"type":"string"},"customAlias":{"description":"Custom short URL alias. If omitted, a random alias is generated.","examples":["my-link"],"type":"string"},"expiresAt":{"description":"Expiration date in ISO 8601 format. Link becomes invalid after this date.","examples":["2026-12-31T23:59:59Z"],"type":"string"}}}}}}}},"/api/v1/lock/list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["lockId","alias","hasGateway","active"],"properties":{"lockId":{"description":"TTLock lock ID (external identifier).","type":"string"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"hasGateway":{"description":"Whether the lock is connected to a Wi-Fi gateway.","type":"boolean"},"active":{"description":"Whether the lock is active in the system.","type":"boolean"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["lockId","alias","hasGateway","active"],"properties":{"lockId":{"description":"TTLock lock ID (external identifier).","type":"string"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"hasGateway":{"description":"Whether the lock is connected to a Wi-Fi gateway.","type":"boolean"},"active":{"description":"Whether the lock is active in the system.","type":"boolean"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["lockId","alias","hasGateway","active"],"properties":{"lockId":{"description":"TTLock lock ID (external identifier).","type":"string"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"hasGateway":{"description":"Whether the lock is connected to a Wi-Fi gateway.","type":"boolean"},"active":{"description":"Whether the lock is active in the system.","type":"boolean"}}}}},"required":["items"]}}}}},"operationId":"getApiV1LockList","tags":["IoT"],"summary":"List locks","description":"Returns a simple list of all non-deleted TTLock smart locks for the organisation. Designed for mobile app usage — returns only essential fields needed for lock selection and status display."}},"/api/v1/lock/unlock":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"TTLock lock ID (external identifier).","examples":["12345"],"schema":{"type":"string"},"in":"query","name":"lockId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"True if the unlock command was sent successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"True if the unlock command was sent successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"True if the unlock command was sent successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1LockUnlock","tags":["IoT"],"summary":"Unlock lock remotely","description":"Sends an immediate remote unlock command to the specified lock via the TTLock API. The lock is identified by its TTLock lock ID (external identifier). Requires an active, non-deleted lock connected to a Wi-Fi gateway."}},"/api/v1/newsletter/register-contact":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1NewsletterRegister-contact","tags":["newsletter"],"summary":"Register newsletter contact","description":"Registers a new contact for the newsletter. If the contact already exists, it is updated with the provided data. Optionally assigns the contact to one or more newsletter groups.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"source":{"examples":["web","footer","social"],"description":"Signup source identifier for analytics.","type":"string"},"groups":{"description":"Newsletter group tags to assign to the contact.","type":"array","items":{"examples":["trainer","student","b2b"],"type":"string"}},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"source":{"examples":["web","footer","social"],"description":"Signup source identifier for analytics.","type":"string"},"groups":{"description":"Newsletter group tags to assign to the contact.","type":"array","items":{"examples":["trainer","student","b2b"],"type":"string"}},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"source":{"examples":["web","footer","social"],"description":"Signup source identifier for analytics.","type":"string"},"groups":{"description":"Newsletter group tags to assign to the contact.","type":"array","items":{"examples":["trainer","student","b2b"],"type":"string"}},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"}}}}}}}},"/api/v1/ping/":{"get":{"responses":{"200":{"description":"Server info including request IDs, environment, location, and optional auth details.","content":{"application/json":{"schema":{"type":"object","patternProperties":{"^(.*)$":{}}}},"multipart/form-data":{"schema":{"type":"object","patternProperties":{"^(.*)$":{}}}},"text/plain":{"schema":{"type":"object","patternProperties":{"^(.*)$":{}}}}}}},"operationId":"getApiV1Ping","tags":["ping"],"summary":"Ping","description":"Returns basic server information (app name, version, uptime). If a valid session is present, also returns organisation ID and login status."}},"/api/v1/ping/error":{"get":{"operationId":"getApiV1PingError","tags":["ping"],"summary":"Test error endpoint","description":"This endpoint always fails with a sample error. Useful for testing error handling and monitoring.","responses":{"200":{}}}},"/api/v1/ping/health":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"True if all health checks passed.","const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"True if all health checks passed.","const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"True if all health checks passed.","const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"getApiV1PingHealth","tags":["ping"],"summary":"Health check","description":"Performs basic health checks (database connectivity, etc.) and returns success if all checks pass."}},"/api/v1/post/post":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"examples":["about"],"schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":false},{"examples":["asc","desc"],"schema":{"type":"string"},"in":"query","name":"sortDirection","required":false}],"responses":{"200":{"anyOf":[{"type":"object","required":["id","author","content","route","routes","anchorList","perex","metaDescription","mainCategory","breadcrumb","related","tagList"],"properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"type":"string"},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"examples":["Jan Barášek"],"type":"string"},"profileSlug":{"examples":["71E58E5SjdZN6ut3"],"type":"string"}}},"isStar":{"description":"True if the post is starred/pinned. Omitted when false.","type":"boolean"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"content":{"examples":["<p>Žijeme ve světě, kde je normální řídit...</p>"],"type":"string"},"route":{"type":"object","required":["slug","locale","canonical"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"}}},"routes":{"type":"array","items":{"type":"object","required":["slug","locale"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"anchorList":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"perex":{"type":"string"},"metaDescription":{"type":"string"},"publishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"mainCategory":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}}},"breadcrumb":{"type":"array","items":{"type":"object","required":["slug","children"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"children":{"type":"array","items":{}}}}},"related":{"type":"array","items":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"slug":{"type":"string"}}}},"tagList":{"description":"Array of tags assigned to this post. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag.","examples":["#3B82F6"],"type":"string"}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"examples":["Post \"about\" does not exist."],"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["id","author","content","route","routes","anchorList","perex","metaDescription","mainCategory","breadcrumb","related","tagList"],"properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"type":"string"},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"examples":["Jan Barášek"],"type":"string"},"profileSlug":{"examples":["71E58E5SjdZN6ut3"],"type":"string"}}},"isStar":{"description":"True if the post is starred/pinned. Omitted when false.","type":"boolean"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"content":{"examples":["<p>Žijeme ve světě, kde je normální řídit...</p>"],"type":"string"},"route":{"type":"object","required":["slug","locale","canonical"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"}}},"routes":{"type":"array","items":{"type":"object","required":["slug","locale"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"anchorList":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"perex":{"type":"string"},"metaDescription":{"type":"string"},"publishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"mainCategory":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}}},"breadcrumb":{"type":"array","items":{"type":"object","required":["slug","children"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"children":{"type":"array","items":{}}}}},"related":{"type":"array","items":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"slug":{"type":"string"}}}},"tagList":{"description":"Array of tags assigned to this post. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag.","examples":["#3B82F6"],"type":"string"}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"examples":["Post \"about\" does not exist."],"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["id","author","content","route","routes","anchorList","perex","metaDescription","mainCategory","breadcrumb","related","tagList"],"properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"type":"string"},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"examples":["Jan Barášek"],"type":"string"},"profileSlug":{"examples":["71E58E5SjdZN6ut3"],"type":"string"}}},"isStar":{"description":"True if the post is starred/pinned. Omitted when false.","type":"boolean"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"content":{"examples":["<p>Žijeme ve světě, kde je normální řídit...</p>"],"type":"string"},"route":{"type":"object","required":["slug","locale","canonical"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"}}},"routes":{"type":"array","items":{"type":"object","required":["slug","locale"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"anchorList":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"perex":{"type":"string"},"metaDescription":{"type":"string"},"publishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"mainCategory":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}}},"breadcrumb":{"type":"array","items":{"type":"object","required":["slug","children"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"children":{"type":"array","items":{}}}}},"related":{"type":"array","items":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"slug":{"type":"string"}}}},"tagList":{"description":"Array of tags assigned to this post. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag.","examples":["#3B82F6"],"type":"string"}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"examples":["Post \"about\" does not exist."],"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["id","author","content","route","routes","anchorList","perex","metaDescription","mainCategory","breadcrumb","related","tagList"],"properties":{"id":{"examples":["6IU2SWgP76FO2UXw"],"type":"string"},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"examples":["Jan Barášek"],"type":"string"},"profileSlug":{"examples":["71E58E5SjdZN6ut3"],"type":"string"}}},"isStar":{"description":"True if the post is starred/pinned. Omitted when false.","type":"boolean"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"content":{"examples":["<p>Žijeme ve světě, kde je normální řídit...</p>"],"type":"string"},"route":{"type":"object","required":["slug","locale","canonical"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"}}},"routes":{"type":"array","items":{"type":"object","required":["slug","locale"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"anchorList":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"perex":{"type":"string"},"metaDescription":{"type":"string"},"publishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"mainCategory":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}}},"breadcrumb":{"type":"array","items":{"type":"object","required":["slug","children"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"children":{"type":"array","items":{}}}}},"related":{"type":"array","items":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"slug":{"type":"string"}}}},"tagList":{"description":"Array of tags assigned to this post. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag.","examples":["#3B82F6"],"type":"string"}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"examples":["Post \"about\" does not exist."],"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"getApiV1PostPost","tags":["post"],"summary":"Get post detail","description":"Returns the full detail of a post identified by slug and locale, including content, routes, breadcrumbs, related posts, and tags. Returns an error object (state: error) if the post does not exist."}},"/api/v1/post/create":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"External id of the created or updated post (use this in /post, /feed, etc.).","type":"string"},"code":{"nullable":true,"anyOf":[{"examples":["chatspc-SUKL12345-2026-04-27"],"description":"Echo of the supplied `code`, or null when none was provided.","type":"string"},{"type":"null"}]},"created":{"description":"True when a new post was inserted; false when an existing post (matched by code) was updated.","type":"boolean"}},"required":["success","id","code","created"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"External id of the created or updated post (use this in /post, /feed, etc.).","type":"string"},"code":{"nullable":true,"anyOf":[{"examples":["chatspc-SUKL12345-2026-04-27"],"description":"Echo of the supplied `code`, or null when none was provided.","type":"string"},{"type":"null"}]},"created":{"description":"True when a new post was inserted; false when an existing post (matched by code) was updated.","type":"boolean"}},"required":["success","id","code","created"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"id":{"examples":["6IU2SWgP76FO2UXw"],"description":"External id of the created or updated post (use this in /post, /feed, etc.).","type":"string"},"code":{"nullable":true,"anyOf":[{"examples":["chatspc-SUKL12345-2026-04-27"],"description":"Echo of the supplied `code`, or null when none was provided.","type":"string"},{"type":"null"}]},"created":{"description":"True when a new post was inserted; false when an existing post (matched by code) was updated.","type":"boolean"}},"required":["success","id","code","created"]}}}}},"operationId":"postApiV1PostCreate","tags":["post"],"summary":"Create or update a post (idempotent upsert by code)","description":"Creates a new post for the authenticated organisation, or — when `code` is provided and a post with the same code already exists in the organisation — updates that post in place.\n\nOn update, the per-locale row (title, content, perex) is overwritten for the supplied `locale` via an upsert on `(post_id, locale_id)`; other locales are left untouched. `updatedDate` is bumped on every successful call. Visibility transitions out of `private` trigger a `publishedDate` stamp when one is not already set.\n\nThis endpoint is intended for batch importers (e.g. ChatSPC SPC ingestion) that need to push the same article repeatedly without producing duplicates.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content","locale"],"properties":{"code":{"maxLength":64,"examples":["chatspc-sukl12345-2026-04-27"],"description":"Optional caller-supplied stable identifier for this article. When omitted (or empty), a new post is always inserted. When provided, the post is matched within the organisation by `code`: an existing post with the same code is updated in place, a missing one is inserted with that code attached. This makes /create idempotent for batch importers — the same call with the same code can be safely retried or used to push content updates.","type":"string"},"title":{"minLength":1,"examples":["KYBER CENA ROKU 2025"],"description":"Post title (single-line plain text).","type":"string"},"content":{"examples":["<p>Žijeme ve světě, kde…</p>"],"description":"Post body. HTML is preserved; whitespace is normalized.","type":"string"},"perex":{"examples":["Třetí ročník vyhlášení proběhl 9. října 2025…"],"description":"Short summary / teaser. Stored in the locale row alongside title and content.","type":"string"},"visibility":{"default":"public","description":"Post visibility. Defaults to `public`. Updates may change visibility; transitioning out of `private` triggers a publishedDate stamp if not already set.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"mainCategory":{"examples":["novinky"],"description":"External id of the category to assign as `mainCategory`. On insert, when omitted the platform falls back to the first active category and attempts AI-based categorization in the background. On update, when omitted the existing category is left untouched.","type":"string"},"mainAuthorCuRefNo":{"maxLength":16,"minLength":16,"examples":["1cGIHvFoQDGLAbcA"],"description":"Optional cuRefNo of the contact to attribute as the main author on insert. When omitted the organisation’s internal customer is used. Ignored on update.","type":"string"},"commitMessage":{"examples":["Weekly SÚKL ingest 2026-04-27"],"description":"Optional human-readable commit message recorded on the version history entry for this call. When omitted, the system fills a sensible default (e.g. `Initial version via /api/v1/post/create (code=…)` or `Update via /api/v1/post/create (code=…)`).","type":"string"},"metadata":{"examples":[{"sukl_code":"SUKL12345","version_date":"2026-04-27","pdf_sha256":"8f2c…","page_count":"42","ingested_at":"2026-04-27T10:11:12Z"}],"description":"Optional structured key/value metadata bag merged into `content__post_meta` after the post upsert. Designed for external integrations (e.g. ChatSPC) that need to attach provenance — `sukl_code`, `version_date`, `pdf_sha256`, `page_count`, `suspicious_pages`, `ingested_at`, … — without operating their own database. Read it back via `/api/v1/post/meta`. Pass `null` for a key to clear it. Keys must fit 64 chars; values are strings — stringify your numbers/booleans before sending.","type":"object","patternProperties":{"^(.*)$":{}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["title","content","locale"],"properties":{"code":{"maxLength":64,"examples":["chatspc-sukl12345-2026-04-27"],"description":"Optional caller-supplied stable identifier for this article. When omitted (or empty), a new post is always inserted. When provided, the post is matched within the organisation by `code`: an existing post with the same code is updated in place, a missing one is inserted with that code attached. This makes /create idempotent for batch importers — the same call with the same code can be safely retried or used to push content updates.","type":"string"},"title":{"minLength":1,"examples":["KYBER CENA ROKU 2025"],"description":"Post title (single-line plain text).","type":"string"},"content":{"examples":["<p>Žijeme ve světě, kde…</p>"],"description":"Post body. HTML is preserved; whitespace is normalized.","type":"string"},"perex":{"examples":["Třetí ročník vyhlášení proběhl 9. října 2025…"],"description":"Short summary / teaser. Stored in the locale row alongside title and content.","type":"string"},"visibility":{"default":"public","description":"Post visibility. Defaults to `public`. Updates may change visibility; transitioning out of `private` triggers a publishedDate stamp if not already set.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"mainCategory":{"examples":["novinky"],"description":"External id of the category to assign as `mainCategory`. On insert, when omitted the platform falls back to the first active category and attempts AI-based categorization in the background. On update, when omitted the existing category is left untouched.","type":"string"},"mainAuthorCuRefNo":{"maxLength":16,"minLength":16,"examples":["1cGIHvFoQDGLAbcA"],"description":"Optional cuRefNo of the contact to attribute as the main author on insert. When omitted the organisation’s internal customer is used. Ignored on update.","type":"string"},"commitMessage":{"examples":["Weekly SÚKL ingest 2026-04-27"],"description":"Optional human-readable commit message recorded on the version history entry for this call. When omitted, the system fills a sensible default (e.g. `Initial version via /api/v1/post/create (code=…)` or `Update via /api/v1/post/create (code=…)`).","type":"string"},"metadata":{"examples":[{"sukl_code":"SUKL12345","version_date":"2026-04-27","pdf_sha256":"8f2c…","page_count":"42","ingested_at":"2026-04-27T10:11:12Z"}],"description":"Optional structured key/value metadata bag merged into `content__post_meta` after the post upsert. Designed for external integrations (e.g. ChatSPC) that need to attach provenance — `sukl_code`, `version_date`, `pdf_sha256`, `page_count`, `suspicious_pages`, `ingested_at`, … — without operating their own database. Read it back via `/api/v1/post/meta`. Pass `null` for a key to clear it. Keys must fit 64 chars; values are strings — stringify your numbers/booleans before sending.","type":"object","patternProperties":{"^(.*)$":{}}}}}},"text/plain":{"schema":{"type":"object","required":["title","content","locale"],"properties":{"code":{"maxLength":64,"examples":["chatspc-sukl12345-2026-04-27"],"description":"Optional caller-supplied stable identifier for this article. When omitted (or empty), a new post is always inserted. When provided, the post is matched within the organisation by `code`: an existing post with the same code is updated in place, a missing one is inserted with that code attached. This makes /create idempotent for batch importers — the same call with the same code can be safely retried or used to push content updates.","type":"string"},"title":{"minLength":1,"examples":["KYBER CENA ROKU 2025"],"description":"Post title (single-line plain text).","type":"string"},"content":{"examples":["<p>Žijeme ve světě, kde…</p>"],"description":"Post body. HTML is preserved; whitespace is normalized.","type":"string"},"perex":{"examples":["Třetí ročník vyhlášení proběhl 9. října 2025…"],"description":"Short summary / teaser. Stored in the locale row alongside title and content.","type":"string"},"visibility":{"default":"public","description":"Post visibility. Defaults to `public`. Updates may change visibility; transitioning out of `private` triggers a publishedDate stamp if not already set.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"mainCategory":{"examples":["novinky"],"description":"External id of the category to assign as `mainCategory`. On insert, when omitted the platform falls back to the first active category and attempts AI-based categorization in the background. On update, when omitted the existing category is left untouched.","type":"string"},"mainAuthorCuRefNo":{"maxLength":16,"minLength":16,"examples":["1cGIHvFoQDGLAbcA"],"description":"Optional cuRefNo of the contact to attribute as the main author on insert. When omitted the organisation’s internal customer is used. Ignored on update.","type":"string"},"commitMessage":{"examples":["Weekly SÚKL ingest 2026-04-27"],"description":"Optional human-readable commit message recorded on the version history entry for this call. When omitted, the system fills a sensible default (e.g. `Initial version via /api/v1/post/create (code=…)` or `Update via /api/v1/post/create (code=…)`).","type":"string"},"metadata":{"examples":[{"sukl_code":"SUKL12345","version_date":"2026-04-27","pdf_sha256":"8f2c…","page_count":"42","ingested_at":"2026-04-27T10:11:12Z"}],"description":"Optional structured key/value metadata bag merged into `content__post_meta` after the post upsert. Designed for external integrations (e.g. ChatSPC) that need to attach provenance — `sukl_code`, `version_date`, `pdf_sha256`, `page_count`, `suspicious_pages`, `ingested_at`, … — without operating their own database. Read it back via `/api/v1/post/meta`. Pass `null` for a key to clear it. Keys must fit 64 chars; values are strings — stringify your numbers/booleans before sending.","type":"object","patternProperties":{"^(.*)$":{}}}}}}}}}},"/api/v1/post/history":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Post public id (content__post.external_id).","examples":["6IU2SWgP76FO2UXw"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"anyOf":[{"type":"object","required":["postId","locale","items"],"properties":{"postId":{"description":"Echo of the post external id.","type":"string"},"locale":{"nullable":true,"anyOf":[{"description":"Echo of the locale filter, or null when none was applied.","type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["id","insertedDate","locale","title","commitMessage","contentSize","author"],"properties":{"id":{"examples":["vErSiOnHaNdLe123"],"description":"Version handle (16 chars). Pass to /history/version to read the body.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locale":{"description":"Locale code of this revision (e.g. \"cs\", \"en\").","type":"string"},"title":{"description":"Snapshot of the post title at this revision.","type":"string"},"commitMessage":{"nullable":true,"anyOf":[{"description":"Optional human commit message; null for auto-versions.","type":"string"},{"type":"null"}]},"contentSize":{"description":"Byte size of the content blob.","type":"number"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"description":"cuRefNo of the author contact.","type":"string"},{"type":"null"}]},"name":{"description":"Display name of the author.","type":"string"}}}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["postId","locale","items"],"properties":{"postId":{"description":"Echo of the post external id.","type":"string"},"locale":{"nullable":true,"anyOf":[{"description":"Echo of the locale filter, or null when none was applied.","type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["id","insertedDate","locale","title","commitMessage","contentSize","author"],"properties":{"id":{"examples":["vErSiOnHaNdLe123"],"description":"Version handle (16 chars). Pass to /history/version to read the body.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locale":{"description":"Locale code of this revision (e.g. \"cs\", \"en\").","type":"string"},"title":{"description":"Snapshot of the post title at this revision.","type":"string"},"commitMessage":{"nullable":true,"anyOf":[{"description":"Optional human commit message; null for auto-versions.","type":"string"},{"type":"null"}]},"contentSize":{"description":"Byte size of the content blob.","type":"number"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"description":"cuRefNo of the author contact.","type":"string"},{"type":"null"}]},"name":{"description":"Display name of the author.","type":"string"}}}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["postId","locale","items"],"properties":{"postId":{"description":"Echo of the post external id.","type":"string"},"locale":{"nullable":true,"anyOf":[{"description":"Echo of the locale filter, or null when none was applied.","type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["id","insertedDate","locale","title","commitMessage","contentSize","author"],"properties":{"id":{"examples":["vErSiOnHaNdLe123"],"description":"Version handle (16 chars). Pass to /history/version to read the body.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locale":{"description":"Locale code of this revision (e.g. \"cs\", \"en\").","type":"string"},"title":{"description":"Snapshot of the post title at this revision.","type":"string"},"commitMessage":{"nullable":true,"anyOf":[{"description":"Optional human commit message; null for auto-versions.","type":"string"},{"type":"null"}]},"contentSize":{"description":"Byte size of the content blob.","type":"number"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"description":"cuRefNo of the author contact.","type":"string"},{"type":"null"}]},"name":{"description":"Display name of the author.","type":"string"}}}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["postId","locale","items"],"properties":{"postId":{"description":"Echo of the post external id.","type":"string"},"locale":{"nullable":true,"anyOf":[{"description":"Echo of the locale filter, or null when none was applied.","type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["id","insertedDate","locale","title","commitMessage","contentSize","author"],"properties":{"id":{"examples":["vErSiOnHaNdLe123"],"description":"Version handle (16 chars). Pass to /history/version to read the body.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locale":{"description":"Locale code of this revision (e.g. \"cs\", \"en\").","type":"string"},"title":{"description":"Snapshot of the post title at this revision.","type":"string"},"commitMessage":{"nullable":true,"anyOf":[{"description":"Optional human commit message; null for auto-versions.","type":"string"},{"type":"null"}]},"contentSize":{"description":"Byte size of the content blob.","type":"number"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"description":"cuRefNo of the author contact.","type":"string"},{"type":"null"}]},"name":{"description":"Display name of the author.","type":"string"}}}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"getApiV1PostHistory","tags":["post"],"summary":"List post version history","description":"Returns the commit log for a post: every revision recorded in `content__post_history`, newest first.\n\nA post with multi-locale content (e.g. cs + en + de) has independent revision streams per language. Pass `locale=cs` to scope to one language, omit to get all languages mixed; either way each item exposes its own `locale` field.\n\nDesigned so external consumers (e.g. ChatSPC) can present a version timeline without operating their own database. Each entry carries the version handle, timestamp, locale, snapshot title, optional commit message and the byte size of the stored content blob. The HTML body itself is fetched on demand via `/api/v1/post/history/version`."}},"/api/v1/post/history/version":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Version handle returned by /api/v1/post/history.","examples":["vErSiOnHaNdLe123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["id","postId","locale","insertedDate","title","content","contentSize","commitMessage","author"],"properties":{"id":{"description":"Version handle (echo).","type":"string"},"postId":{"description":"External id of the parent post.","type":"string"},"locale":{"description":"Locale code of this revision.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"content":{"description":"Full HTML content snapshot at this revision.","type":"string"},"contentSize":{"type":"number"},"commitMessage":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["id","postId","locale","insertedDate","title","content","contentSize","commitMessage","author"],"properties":{"id":{"description":"Version handle (echo).","type":"string"},"postId":{"description":"External id of the parent post.","type":"string"},"locale":{"description":"Locale code of this revision.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"content":{"description":"Full HTML content snapshot at this revision.","type":"string"},"contentSize":{"type":"number"},"commitMessage":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["id","postId","locale","insertedDate","title","content","contentSize","commitMessage","author"],"properties":{"id":{"description":"Version handle (echo).","type":"string"},"postId":{"description":"External id of the parent post.","type":"string"},"locale":{"description":"Locale code of this revision.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"content":{"description":"Full HTML content snapshot at this revision.","type":"string"},"contentSize":{"type":"number"},"commitMessage":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["id","postId","locale","insertedDate","title","content","contentSize","commitMessage","author"],"properties":{"id":{"description":"Version handle (echo).","type":"string"},"postId":{"description":"External id of the parent post.","type":"string"},"locale":{"description":"Locale code of this revision.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"content":{"description":"Full HTML content snapshot at this revision.","type":"string"},"contentSize":{"type":"number"},"commitMessage":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"getApiV1PostHistoryVersion","tags":["post"],"summary":"Get post history version detail","description":"Returns one specific revision in full, including the HTML content snapshot (body is loaded from blob storage on demand). Use this when an external consumer needs to render a historical version of a post body or compute a diff against another version."}},"/api/v1/post/history/diff":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Older revision handle (left side of the diff).","examples":["vErSiOnHaNdLe123"],"schema":{"type":"string"},"in":"query","name":"from","required":true},{"description":"Newer revision handle (right side of the diff).","examples":["vErSiOnHaNdLe456"],"schema":{"type":"string"},"in":"query","name":"to","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["from","to","titleDiff","contentDiff","stats"],"properties":{"from":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"to":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"titleDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"type":"string"}}}},"contentDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"type":"string"}}}},"stats":{"type":"object","required":["titleAdded","titleRemoved","contentAddedLines","contentRemovedLines"],"properties":{"titleAdded":{"type":"number"},"titleRemoved":{"type":"number"},"contentAddedLines":{"type":"number"},"contentRemovedLines":{"type":"number"}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["from","to","titleDiff","contentDiff","stats"],"properties":{"from":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"to":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"titleDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"type":"string"}}}},"contentDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"type":"string"}}}},"stats":{"type":"object","required":["titleAdded","titleRemoved","contentAddedLines","contentRemovedLines"],"properties":{"titleAdded":{"type":"number"},"titleRemoved":{"type":"number"},"contentAddedLines":{"type":"number"},"contentRemovedLines":{"type":"number"}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["from","to","titleDiff","contentDiff","stats"],"properties":{"from":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"to":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"titleDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"type":"string"}}}},"contentDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"type":"string"}}}},"stats":{"type":"object","required":["titleAdded","titleRemoved","contentAddedLines","contentRemovedLines"],"properties":{"titleAdded":{"type":"number"},"titleRemoved":{"type":"number"},"contentAddedLines":{"type":"number"},"contentRemovedLines":{"type":"number"}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["from","to","titleDiff","contentDiff","stats"],"properties":{"from":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"to":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"titleDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"type":"string"}}}},"contentDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"type":"string"}}}},"stats":{"type":"object","required":["titleAdded","titleRemoved","contentAddedLines","contentRemovedLines"],"properties":{"titleAdded":{"type":"number"},"titleRemoved":{"type":"number"},"contentAddedLines":{"type":"number"},"contentRemovedLines":{"type":"number"}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"getApiV1PostHistoryDiff","tags":["post"],"summary":"Diff two post revisions","description":"Returns a structured diff between two revisions of the same post and locale.\n\nTitle is word-grain (titles are short, word grain reads naturally), content is line-grain (HTML/markdown bodies — line grain keeps block edits readable). Each diff segment is tagged `add` / `remove` / `context`; concatenating context+add produces the `to` document, concatenating context+remove produces the `from` document.\n\nBoth revisions must belong to the same post and same locale; cross-post or cross-locale diffs return an error envelope."}},"/api/v1/post/meta":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Post public id (content__post.external_id).","examples":["6IU2SWgP76FO2UXw"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["postId","metadata"],"properties":{"postId":{"description":"Echo of the post external id.","type":"string"},"metadata":{"description":"Free-form key/value bag, keyed by string and valued by string. Clients parse numbers/booleans/dates as needed."}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["postId","metadata"],"properties":{"postId":{"description":"Echo of the post external id.","type":"string"},"metadata":{"description":"Free-form key/value bag, keyed by string and valued by string. Clients parse numbers/booleans/dates as needed."}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["postId","metadata"],"properties":{"postId":{"description":"Echo of the post external id.","type":"string"},"metadata":{"description":"Free-form key/value bag, keyed by string and valued by string. Clients parse numbers/booleans/dates as needed."}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["postId","metadata"],"properties":{"postId":{"description":"Echo of the post external id.","type":"string"},"metadata":{"description":"Free-form key/value bag, keyed by string and valued by string. Clients parse numbers/booleans/dates as needed."}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"getApiV1PostMeta","tags":["post"],"summary":"Get post structured metadata","description":"Returns the key/value metadata bag attached to a post via /api/v1/post/create.\n\nUseful for external integrations (e.g. ChatSPC) that store provenance — sukl_code, version_date, pdf_sha256, page_count, suspicious_pages, ingested_at, … — alongside the post and need to read it back without owning their own database. Posts with no metadata return an empty `metadata` object (not an error)."}},"/api/v1/post/category":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"examples":["novinky"],"schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":false}],"responses":{"200":{"anyOf":[{"type":"object","required":["name","description","route","routes","children","breadcrumb","postFeed"],"properties":{"name":{"examples":["Novinky"],"type":"string"},"description":{"examples":["Nejnovější zprávy a aktuality ze světa kyberbezpečnosti."],"type":"string"},"route":{"type":"object","required":["slug","locale","canonical"],"properties":{"slug":{"examples":["Novinky"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"}}},"routes":{"type":"array","items":{"type":"object","required":["slug","locale"],"properties":{"slug":{"examples":["novinky"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"children":{"type":"array","items":{"type":"object","required":["slug","name","description","postCount"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"postCount":{"type":"number"}}}},"breadcrumb":{"type":"array","items":{"type":"object","required":["slug","children"],"properties":{"name":{"examples":["Novinky"],"type":"string"},"slug":{"examples":["novinky"],"type":"string"},"children":{"type":"array","items":{}}}}},"postFeed":{"type":"array","items":{"type":"object","required":["slug","title","content","perex","publishedDate"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"content":{"examples":["Žijeme ve světě, kde je..."],"type":"string"},"perex":{"nullable":true,"anyOf":[{"examples":["Třetí ročník vyhlášení proběhl..."],"type":"string"},{"type":"null"}]},"publishedDate":{"nullable":true,"anyOf":[{"examples":["2025-11-05T15:54:44.280Z"],"anyOf":[{"examples":["2025-11-05T15:54:44.280Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"parent":{"type":"object","required":["name","slug","description"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"examples":["Category \"about\" does not exist."],"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["name","description","route","routes","children","breadcrumb","postFeed"],"properties":{"name":{"examples":["Novinky"],"type":"string"},"description":{"examples":["Nejnovější zprávy a aktuality ze světa kyberbezpečnosti."],"type":"string"},"route":{"type":"object","required":["slug","locale","canonical"],"properties":{"slug":{"examples":["Novinky"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"}}},"routes":{"type":"array","items":{"type":"object","required":["slug","locale"],"properties":{"slug":{"examples":["novinky"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"children":{"type":"array","items":{"type":"object","required":["slug","name","description","postCount"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"postCount":{"type":"number"}}}},"breadcrumb":{"type":"array","items":{"type":"object","required":["slug","children"],"properties":{"name":{"examples":["Novinky"],"type":"string"},"slug":{"examples":["novinky"],"type":"string"},"children":{"type":"array","items":{}}}}},"postFeed":{"type":"array","items":{"type":"object","required":["slug","title","content","perex","publishedDate"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"content":{"examples":["Žijeme ve světě, kde je..."],"type":"string"},"perex":{"nullable":true,"anyOf":[{"examples":["Třetí ročník vyhlášení proběhl..."],"type":"string"},{"type":"null"}]},"publishedDate":{"nullable":true,"anyOf":[{"examples":["2025-11-05T15:54:44.280Z"],"anyOf":[{"examples":["2025-11-05T15:54:44.280Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"parent":{"type":"object","required":["name","slug","description"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"examples":["Category \"about\" does not exist."],"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["name","description","route","routes","children","breadcrumb","postFeed"],"properties":{"name":{"examples":["Novinky"],"type":"string"},"description":{"examples":["Nejnovější zprávy a aktuality ze světa kyberbezpečnosti."],"type":"string"},"route":{"type":"object","required":["slug","locale","canonical"],"properties":{"slug":{"examples":["Novinky"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"}}},"routes":{"type":"array","items":{"type":"object","required":["slug","locale"],"properties":{"slug":{"examples":["novinky"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"children":{"type":"array","items":{"type":"object","required":["slug","name","description","postCount"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"postCount":{"type":"number"}}}},"breadcrumb":{"type":"array","items":{"type":"object","required":["slug","children"],"properties":{"name":{"examples":["Novinky"],"type":"string"},"slug":{"examples":["novinky"],"type":"string"},"children":{"type":"array","items":{}}}}},"postFeed":{"type":"array","items":{"type":"object","required":["slug","title","content","perex","publishedDate"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"content":{"examples":["Žijeme ve světě, kde je..."],"type":"string"},"perex":{"nullable":true,"anyOf":[{"examples":["Třetí ročník vyhlášení proběhl..."],"type":"string"},{"type":"null"}]},"publishedDate":{"nullable":true,"anyOf":[{"examples":["2025-11-05T15:54:44.280Z"],"anyOf":[{"examples":["2025-11-05T15:54:44.280Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"parent":{"type":"object","required":["name","slug","description"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"examples":["Category \"about\" does not exist."],"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["name","description","route","routes","children","breadcrumb","postFeed"],"properties":{"name":{"examples":["Novinky"],"type":"string"},"description":{"examples":["Nejnovější zprávy a aktuality ze světa kyberbezpečnosti."],"type":"string"},"route":{"type":"object","required":["slug","locale","canonical"],"properties":{"slug":{"examples":["Novinky"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"}}},"routes":{"type":"array","items":{"type":"object","required":["slug","locale"],"properties":{"slug":{"examples":["novinky"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"children":{"type":"array","items":{"type":"object","required":["slug","name","description","postCount"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"postCount":{"type":"number"}}}},"breadcrumb":{"type":"array","items":{"type":"object","required":["slug","children"],"properties":{"name":{"examples":["Novinky"],"type":"string"},"slug":{"examples":["novinky"],"type":"string"},"children":{"type":"array","items":{}}}}},"postFeed":{"type":"array","items":{"type":"object","required":["slug","title","content","perex","publishedDate"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"content":{"examples":["Žijeme ve světě, kde je..."],"type":"string"},"perex":{"nullable":true,"anyOf":[{"examples":["Třetí ročník vyhlášení proběhl..."],"type":"string"},{"type":"null"}]},"publishedDate":{"nullable":true,"anyOf":[{"examples":["2025-11-05T15:54:44.280Z"],"anyOf":[{"examples":["2025-11-05T15:54:44.280Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"parent":{"type":"object","required":["name","slug","description"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"examples":["Category \"about\" does not exist."],"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"getApiV1PostCategory","tags":["post"],"summary":"Get post category detail","description":"Returns category detail with child categories, breadcrumb, post feed, and routing info. Returns an error object if the category does not exist."}},"/api/v1/post/search":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Full-text search query entered by the client. Can contain words, phrases or year numbers, e.g. \"2025\".","examples":["2025"],"schema":{"type":"string"},"in":"query","name":"query","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"examples":["2025"],"description":"Normalized form of the search query actually used by the search engine (e.g. trimmed and lower-cased).","type":"string"},"title":{"examples":["2025"],"description":"Human-readable version of the query intended for UI headings (typically first letter upper-cased).","type":"string"},"countResults":{"examples":[1],"description":"Number of search results included in the \"items\" array for this response.","type":"number"},"didYouMean":{"nullable":true,"anyOf":[{"examples":["2024"],"description":"Optional alternative query suggestion when a likely typo or more relevant variant is detected. Null if no suggestion is available.","type":"string"},{"type":"null"}]},"items":{"description":"List of search results for the given query, ordered by relevance (highest score first). Limited to a maximum of 100 items.","type":"array","items":{"type":"object","required":["slug","title","snippet","titleHighlighted","snippetHighlighted","tagList","score"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"description":"Canonical URL slug of the matched post in the requested locale. Append to your site base URL to create a link.","type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"description":"Plain-text title of the post, normalized for search but without HTML highlighting.","type":"string"},"snippet":{"examples":["proto vznikla soutěž KYBER CENA ROKU: aby ukázala lidi a projekty, kteří dělají Českou republiku bezpečnější. Třetí ročník vyhlášení proběhl 9. října 2025 na slavnostním galavečeru za účasti odborné poroty, partnerů a finalistů ze školství, státní správy, průmyslu i komerční bezpečnosti. Letos šlo m"],"description":"Plain-text excerpt from the post content around the matched query, shortened for use in the search results list.","type":"string"},"titleHighlighted":{"examples":["KYBER CENA ROKU <strong style=\"color:#003F99;background:#CCE0FF\">2025</strong>: největší večer české kyberbezpečnosti letošního roku."],"description":"Post title with all occurrences of the query wrapped in a `<strong>` tag with inline highlight styles. Contains HTML and should be rendered as HTML, not escaped.","type":"string"},"snippetHighlighted":{"examples":["proto vznikla soutěž KYBER CENA ROKU: aby ukázala lidi a projekty, kteří dělají Českou republiku bezpečnější. Třetí ročník vyhlášení proběhl 9. října <strong style=\"color:#003F99;background:#CCE0FF\">2025</strong> na slavnostním galavečeru za účasti odborné poroty, partnerů a finalistů ze školství, státní správy, průmyslu i komerční bezpečnosti. Letos šlo m"],"description":"Content snippet with matched query terms highlighted using a `<strong>` tag with inline styles. Contains HTML and should be rendered as HTML, not escaped.","type":"string"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"tagList":{"description":"Array of tags assigned to this post. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag.","examples":["#3B82F6"],"type":"string"}}}},"score":{"examples":[195],"description":"Relative relevance score computed from the text match and year-based boosting. Higher values indicate more relevant results and are used to sort items in descending order. The absolute range is not fixed and should be treated as an internal ranking hint.","type":"number"}}}}},"required":["query","title","countResults","didYouMean","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"query":{"examples":["2025"],"description":"Normalized form of the search query actually used by the search engine (e.g. trimmed and lower-cased).","type":"string"},"title":{"examples":["2025"],"description":"Human-readable version of the query intended for UI headings (typically first letter upper-cased).","type":"string"},"countResults":{"examples":[1],"description":"Number of search results included in the \"items\" array for this response.","type":"number"},"didYouMean":{"nullable":true,"anyOf":[{"examples":["2024"],"description":"Optional alternative query suggestion when a likely typo or more relevant variant is detected. Null if no suggestion is available.","type":"string"},{"type":"null"}]},"items":{"description":"List of search results for the given query, ordered by relevance (highest score first). Limited to a maximum of 100 items.","type":"array","items":{"type":"object","required":["slug","title","snippet","titleHighlighted","snippetHighlighted","tagList","score"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"description":"Canonical URL slug of the matched post in the requested locale. Append to your site base URL to create a link.","type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"description":"Plain-text title of the post, normalized for search but without HTML highlighting.","type":"string"},"snippet":{"examples":["proto vznikla soutěž KYBER CENA ROKU: aby ukázala lidi a projekty, kteří dělají Českou republiku bezpečnější. Třetí ročník vyhlášení proběhl 9. října 2025 na slavnostním galavečeru za účasti odborné poroty, partnerů a finalistů ze školství, státní správy, průmyslu i komerční bezpečnosti. Letos šlo m"],"description":"Plain-text excerpt from the post content around the matched query, shortened for use in the search results list.","type":"string"},"titleHighlighted":{"examples":["KYBER CENA ROKU <strong style=\"color:#003F99;background:#CCE0FF\">2025</strong>: největší večer české kyberbezpečnosti letošního roku."],"description":"Post title with all occurrences of the query wrapped in a `<strong>` tag with inline highlight styles. Contains HTML and should be rendered as HTML, not escaped.","type":"string"},"snippetHighlighted":{"examples":["proto vznikla soutěž KYBER CENA ROKU: aby ukázala lidi a projekty, kteří dělají Českou republiku bezpečnější. Třetí ročník vyhlášení proběhl 9. října <strong style=\"color:#003F99;background:#CCE0FF\">2025</strong> na slavnostním galavečeru za účasti odborné poroty, partnerů a finalistů ze školství, státní správy, průmyslu i komerční bezpečnosti. Letos šlo m"],"description":"Content snippet with matched query terms highlighted using a `<strong>` tag with inline styles. Contains HTML and should be rendered as HTML, not escaped.","type":"string"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"tagList":{"description":"Array of tags assigned to this post. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag.","examples":["#3B82F6"],"type":"string"}}}},"score":{"examples":[195],"description":"Relative relevance score computed from the text match and year-based boosting. Higher values indicate more relevant results and are used to sort items in descending order. The absolute range is not fixed and should be treated as an internal ranking hint.","type":"number"}}}}},"required":["query","title","countResults","didYouMean","items"]}},"text/plain":{"schema":{"type":"object","properties":{"query":{"examples":["2025"],"description":"Normalized form of the search query actually used by the search engine (e.g. trimmed and lower-cased).","type":"string"},"title":{"examples":["2025"],"description":"Human-readable version of the query intended for UI headings (typically first letter upper-cased).","type":"string"},"countResults":{"examples":[1],"description":"Number of search results included in the \"items\" array for this response.","type":"number"},"didYouMean":{"nullable":true,"anyOf":[{"examples":["2024"],"description":"Optional alternative query suggestion when a likely typo or more relevant variant is detected. Null if no suggestion is available.","type":"string"},{"type":"null"}]},"items":{"description":"List of search results for the given query, ordered by relevance (highest score first). Limited to a maximum of 100 items.","type":"array","items":{"type":"object","required":["slug","title","snippet","titleHighlighted","snippetHighlighted","tagList","score"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"description":"Canonical URL slug of the matched post in the requested locale. Append to your site base URL to create a link.","type":"string"},"title":{"examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"description":"Plain-text title of the post, normalized for search but without HTML highlighting.","type":"string"},"snippet":{"examples":["proto vznikla soutěž KYBER CENA ROKU: aby ukázala lidi a projekty, kteří dělají Českou republiku bezpečnější. Třetí ročník vyhlášení proběhl 9. října 2025 na slavnostním galavečeru za účasti odborné poroty, partnerů a finalistů ze školství, státní správy, průmyslu i komerční bezpečnosti. Letos šlo m"],"description":"Plain-text excerpt from the post content around the matched query, shortened for use in the search results list.","type":"string"},"titleHighlighted":{"examples":["KYBER CENA ROKU <strong style=\"color:#003F99;background:#CCE0FF\">2025</strong>: největší večer české kyberbezpečnosti letošního roku."],"description":"Post title with all occurrences of the query wrapped in a `<strong>` tag with inline highlight styles. Contains HTML and should be rendered as HTML, not escaped.","type":"string"},"snippetHighlighted":{"examples":["proto vznikla soutěž KYBER CENA ROKU: aby ukázala lidi a projekty, kteří dělají Českou republiku bezpečnější. Třetí ročník vyhlášení proběhl 9. října <strong style=\"color:#003F99;background:#CCE0FF\">2025</strong> na slavnostním galavečeru za účasti odborné poroty, partnerů a finalistů ze školství, státní správy, průmyslu i komerční bezpečnosti. Letos šlo m"],"description":"Content snippet with matched query terms highlighted using a `<strong>` tag with inline styles. Contains HTML and should be rendered as HTML, not escaped.","type":"string"},"mainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"tagList":{"description":"Array of tags assigned to this post. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag.","examples":["#3B82F6"],"type":"string"}}}},"score":{"examples":[195],"description":"Relative relevance score computed from the text match and year-based boosting. Higher values indicate more relevant results and are used to sort items in descending order. The absolute range is not fixed and should be treated as an internal ranking hint.","type":"number"}}}}},"required":["query","title","countResults","didYouMean","items"]}}}}},"operationId":"getApiV1PostSearch","tags":["post"],"summary":"Search posts","description":"Full-text search across posts. Returns matching posts with highlighted title and snippet, relevance score, and optional \"did you mean\" suggestions."}},"/api/v1/post/feed":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true},{"description":"Comma-separated list of additional fields to include in the response. Only the listed fields will be attached to each item. Example: `content,id`.","examples":["content","id"],"schema":{"type":"string"},"in":"query","name":"fields","required":false},{"description":"Maximum number of items to return. If omitted, a default internal limit is applied.","examples":[64],"schema":{"type":"number"},"in":"query","name":"limit","required":false},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":false},{"description":"Optional tag code to filter posts. Only posts that have this tag assigned will be returned. The tag must be active and belong to the same organisation.","examples":["novinky","bezpecnost"],"schema":{"type":"string"},"in":"query","name":"tag","required":false},{"description":"Optional main category route slug to filter posts. Only posts that have this category set as their main category will be returned.","examples":["novinky","clanky"],"schema":{"type":"string"},"in":"query","name":"mainCategory","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["slug","title","last_modification_date","commentCount","tagList"],"properties":{"slug":{"description":"Unique URL-friendly identifier of the article. Used to construct the public route.","examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"title":{"description":"Human-readable article title. Returned in the language specified in the locale parameter.","examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"mainImageUrl":{"description":"URL of the main/featured image for the post. Null if no main image is set.","examples":["https://storage.xhp.cz/..."],"type":"string"},"last_modification_date":{"description":"Timestamp of the last modification of the article. ISO 8601 format.","examples":["2025-11-05T15:54:44.280Z"],"anyOf":[{"description":"Timestamp of the last modification of the article. ISO 8601 format.","examples":["2025-11-05T15:54:44.280Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"commentCount":{"examples":[12],"description":"Number of comments associated with the article.","type":"number"},"isStar":{"description":"True if the post is starred/pinned. Omitted when false.","type":"boolean"},"content":{"description":"Full article content in plain text or HTML. Returned only if the field is explicitly requested via the `fields` query parameter.","examples":["Žijeme ve světě, kde je normální..."],"type":"string"},"mainCategory":{"description":"Main category of the post. Null if no main category is assigned or if the category has no route/locale data for the requested locale.","type":"object","required":["slug","title"],"properties":{"slug":{"description":"URL-friendly slug of the main category route in the requested locale. Use this to construct links to the category page.","examples":["novinky"],"type":"string"},"title":{"description":"Localized display name of the main category.","examples":["Novinky"],"type":"string"}}},"tagList":{"description":"Array of tags assigned to this post. Empty array if no tags are assigned. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag. Can be used to filter posts by tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag (e.g., \"#FF5733\"). Null if no color is set.","examples":["#3B82F6"],"type":"string"}}}}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["slug","title","last_modification_date","commentCount","tagList"],"properties":{"slug":{"description":"Unique URL-friendly identifier of the article. Used to construct the public route.","examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"title":{"description":"Human-readable article title. Returned in the language specified in the locale parameter.","examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"mainImageUrl":{"description":"URL of the main/featured image for the post. Null if no main image is set.","examples":["https://storage.xhp.cz/..."],"type":"string"},"last_modification_date":{"description":"Timestamp of the last modification of the article. ISO 8601 format.","examples":["2025-11-05T15:54:44.280Z"],"anyOf":[{"description":"Timestamp of the last modification of the article. ISO 8601 format.","examples":["2025-11-05T15:54:44.280Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"commentCount":{"examples":[12],"description":"Number of comments associated with the article.","type":"number"},"isStar":{"description":"True if the post is starred/pinned. Omitted when false.","type":"boolean"},"content":{"description":"Full article content in plain text or HTML. Returned only if the field is explicitly requested via the `fields` query parameter.","examples":["Žijeme ve světě, kde je normální..."],"type":"string"},"mainCategory":{"description":"Main category of the post. Null if no main category is assigned or if the category has no route/locale data for the requested locale.","type":"object","required":["slug","title"],"properties":{"slug":{"description":"URL-friendly slug of the main category route in the requested locale. Use this to construct links to the category page.","examples":["novinky"],"type":"string"},"title":{"description":"Localized display name of the main category.","examples":["Novinky"],"type":"string"}}},"tagList":{"description":"Array of tags assigned to this post. Empty array if no tags are assigned. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag. Can be used to filter posts by tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag (e.g., \"#FF5733\"). Null if no color is set.","examples":["#3B82F6"],"type":"string"}}}}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["slug","title","last_modification_date","commentCount","tagList"],"properties":{"slug":{"description":"Unique URL-friendly identifier of the article. Used to construct the public route.","examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"title":{"description":"Human-readable article title. Returned in the language specified in the locale parameter.","examples":["KYBER CENA ROKU 2025: největší večer české kyberbezpečnosti letošního roku."],"type":"string"},"mainImageUrl":{"description":"URL of the main/featured image for the post. Null if no main image is set.","examples":["https://storage.xhp.cz/..."],"type":"string"},"last_modification_date":{"description":"Timestamp of the last modification of the article. ISO 8601 format.","examples":["2025-11-05T15:54:44.280Z"],"anyOf":[{"description":"Timestamp of the last modification of the article. ISO 8601 format.","examples":["2025-11-05T15:54:44.280Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"commentCount":{"examples":[12],"description":"Number of comments associated with the article.","type":"number"},"isStar":{"description":"True if the post is starred/pinned. Omitted when false.","type":"boolean"},"content":{"description":"Full article content in plain text or HTML. Returned only if the field is explicitly requested via the `fields` query parameter.","examples":["Žijeme ve světě, kde je normální..."],"type":"string"},"mainCategory":{"description":"Main category of the post. Null if no main category is assigned or if the category has no route/locale data for the requested locale.","type":"object","required":["slug","title"],"properties":{"slug":{"description":"URL-friendly slug of the main category route in the requested locale. Use this to construct links to the category page.","examples":["novinky"],"type":"string"},"title":{"description":"Localized display name of the main category.","examples":["Novinky"],"type":"string"}}},"tagList":{"description":"Array of tags assigned to this post. Empty array if no tags are assigned. Only active tags are included.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"URL-friendly code/slug of the tag. Can be used to filter posts by tag.","examples":["bezpecnost"],"type":"string"},"name":{"description":"Human-readable display name of the tag.","examples":["Bezpečnost"],"type":"string"},"color":{"description":"Hex color code for the tag (e.g., \"#FF5733\"). Null if no color is set.","examples":["#3B82F6"],"type":"string"}}}}}}}},"required":["items"]}}}}},"operationId":"getApiV1PostFeed","tags":["post"],"summary":"Get post feed","description":"Returns a feed of the most recent posts. Posts are filtered by the requested locale and ordered by their last modification date. The limit parameter controls how many items are returned, and the optional fields parameter lets you request additional properties (for example content). When requested, the content field is returned as a sanitized, single-line teaser truncated to a fixed length suitable for listing views. You can filter posts by tag (using tag code) or by main category (using category route slug)."}},"/api/v1/post/last-update":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"examples":["2025-11-25 14:11:59"],"type":"string"}},"required":["date"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"date":{"examples":["2025-11-25 14:11:59"],"type":"string"}},"required":["date"]}},"text/plain":{"schema":{"type":"object","properties":{"date":{"examples":["2025-11-25 14:11:59"],"type":"string"}},"required":["date"]}}}}},"operationId":"getApiV1PostLast-update","tags":["post"],"summary":"Get last post update timestamp","description":"Returns the timestamp of the most recently published post for the organisation identified by the API key. Use this endpoint to quickly check whether any content has changed since your last sync (e.g. for cache invalidation or incremental updates).\n\nThe result is based on the `publishedDate` of posts that are already visible (`publishedDate < NOW()` on the server). If no post is found, the current server time is returned."}},"/api/v1/post/rss":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"operationId":"getApiV1PostRss","tags":["post"],"summary":"Get RSS feed","description":"Returns an RSS 2.0 XML feed of published posts for the given locale. Response Content-Type is application/rss+xml.","responses":{"200":{}}}},"/api/v1/post/comment/list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Post public id (content__post.external_id).","examples":["6IU2SWgP76FO2UXw"],"schema":{"type":"string"},"in":"query","name":"postId","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":false},{"description":"Internal only. If true, includes deleted comments (deletedDate not null).","schema":{"type":"boolean","default":false},"in":"query","name":"includeDeleted","required":false}],"responses":{"200":{"anyOf":[{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","parentId","content","insertedDate","deletedDate","author"],"properties":{"id":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"parentId":{"nullable":true,"anyOf":[{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},{"type":"null"}]},"content":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"deletedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"type":"string"},"profileSlug":{"type":"string"}}},"usingSubscriptionService":{"description":"True if the author is using a subscription service (has active subscription).","type":"boolean"},"isMine":{"description":"True if identityId belongs to the comment author.","type":"boolean"}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","parentId","content","insertedDate","deletedDate","author"],"properties":{"id":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"parentId":{"nullable":true,"anyOf":[{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},{"type":"null"}]},"content":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"deletedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"type":"string"},"profileSlug":{"type":"string"}}},"usingSubscriptionService":{"description":"True if the author is using a subscription service (has active subscription).","type":"boolean"},"isMine":{"description":"True if identityId belongs to the comment author.","type":"boolean"}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","parentId","content","insertedDate","deletedDate","author"],"properties":{"id":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"parentId":{"nullable":true,"anyOf":[{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},{"type":"null"}]},"content":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"deletedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"type":"string"},"profileSlug":{"type":"string"}}},"usingSubscriptionService":{"description":"True if the author is using a subscription service (has active subscription).","type":"boolean"},"isMine":{"description":"True if identityId belongs to the comment author.","type":"boolean"}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","parentId","content","insertedDate","deletedDate","author"],"properties":{"id":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"parentId":{"nullable":true,"anyOf":[{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},{"type":"null"}]},"content":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"deletedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"type":"string"},"profileSlug":{"type":"string"}}},"usingSubscriptionService":{"description":"True if the author is using a subscription service (has active subscription).","type":"boolean"},"isMine":{"description":"True if identityId belongs to the comment author.","type":"boolean"}}}}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"getApiV1PostCommentList","tags":["post"],"summary":"List post comments","description":"Returns a flat list of comments for a post (no nested structure). Frontend can build parent/child UI using parentId."}},"/api/v1/post/comment/count":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Post public id (content__post.external_id).","examples":["6IU2SWgP76FO2UXw"],"schema":{"type":"string"},"in":"query","name":"postId","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["count"],"properties":{"count":{"examples":[12],"type":"number"}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["count"],"properties":{"count":{"examples":[12],"type":"number"}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["count"],"properties":{"count":{"examples":[12],"type":"number"}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["count"],"properties":{"count":{"examples":[12],"type":"number"}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"getApiV1PostCommentCount","tags":["post"],"summary":"Count post comments","description":"Returns number of non-deleted comments for a post."}},"/api/v1/post/comment/create":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success","comment"],"properties":{"success":{"const":true,"type":"boolean"},"comment":{"type":"object","required":["id","parentId","content","insertedDate","deletedDate","author"],"properties":{"id":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"parentId":{"nullable":true,"anyOf":[{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},{"type":"null"}]},"content":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"deletedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"type":"string"},"profileSlug":{"type":"string"}}},"usingSubscriptionService":{"description":"True if the author is using a subscription service (has active subscription).","type":"boolean"},"isMine":{"description":"True if identityId belongs to the comment author.","type":"boolean"}}}}},{"type":"object","required":["success","isSpam","reason"],"properties":{"success":{"const":false,"type":"boolean"},"isSpam":{"const":true,"type":"boolean"},"reason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success","comment"],"properties":{"success":{"const":true,"type":"boolean"},"comment":{"type":"object","required":["id","parentId","content","insertedDate","deletedDate","author"],"properties":{"id":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"parentId":{"nullable":true,"anyOf":[{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},{"type":"null"}]},"content":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"deletedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"type":"string"},"profileSlug":{"type":"string"}}},"usingSubscriptionService":{"description":"True if the author is using a subscription service (has active subscription).","type":"boolean"},"isMine":{"description":"True if identityId belongs to the comment author.","type":"boolean"}}}}},{"type":"object","required":["success","isSpam","reason"],"properties":{"success":{"const":false,"type":"boolean"},"isSpam":{"const":true,"type":"boolean"},"reason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success","comment"],"properties":{"success":{"const":true,"type":"boolean"},"comment":{"type":"object","required":["id","parentId","content","insertedDate","deletedDate","author"],"properties":{"id":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"parentId":{"nullable":true,"anyOf":[{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},{"type":"null"}]},"content":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"deletedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"type":"string"},"profileSlug":{"type":"string"}}},"usingSubscriptionService":{"description":"True if the author is using a subscription service (has active subscription).","type":"boolean"},"isMine":{"description":"True if identityId belongs to the comment author.","type":"boolean"}}}}},{"type":"object","required":["success","isSpam","reason"],"properties":{"success":{"const":false,"type":"boolean"},"isSpam":{"const":true,"type":"boolean"},"reason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success","comment"],"properties":{"success":{"const":true,"type":"boolean"},"comment":{"type":"object","required":["id","parentId","content","insertedDate","deletedDate","author"],"properties":{"id":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"parentId":{"nullable":true,"anyOf":[{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},{"type":"null"}]},"content":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"deletedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"author":{"type":"object","required":["name","profileSlug"],"properties":{"name":{"type":"string"},"profileSlug":{"type":"string"}}},"usingSubscriptionService":{"description":"True if the author is using a subscription service (has active subscription).","type":"boolean"},"isMine":{"description":"True if identityId belongs to the comment author.","type":"boolean"}}}}},{"type":"object","required":["success","isSpam","reason"],"properties":{"success":{"const":false,"type":"boolean"},"isSpam":{"const":true,"type":"boolean"},"reason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"object","required":["state","message","code","hint"],"properties":{"state":{"const":"error","type":"string"},"message":{"type":"string"},"code":{"const":200,"type":"number"},"hint":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}]}}}}},"operationId":"postApiV1PostCommentCreate","tags":["post"],"summary":"Create post comment","description":"Create a new post comment. Always resolves contact via identityId and stores GEO IP. Runs spam detection before insert; spam comments are NOT stored.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["postId","identityId","content"],"properties":{"postId":{"examples":["6IU2SWgP76FO2UXw"],"description":"Post public id (content__post.external_id).","type":"string"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"content":{"minLength":1,"maxLength":5000,"examples":["Super článek, díky!"],"description":"Plain text comment content.","type":"string"},"parentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["postId","identityId","content"],"properties":{"postId":{"examples":["6IU2SWgP76FO2UXw"],"description":"Post public id (content__post.external_id).","type":"string"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"content":{"minLength":1,"maxLength":5000,"examples":["Super článek, díky!"],"description":"Plain text comment content.","type":"string"},"parentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["postId","identityId","content"],"properties":{"postId":{"examples":["6IU2SWgP76FO2UXw"],"description":"Post public id (content__post.external_id).","type":"string"},"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"content":{"minLength":1,"maxLength":5000,"examples":["Super článek, díky!"],"description":"Plain text comment content.","type":"string"},"parentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"}}}}}}}},"/api/v1/post/comment/edit":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","isSpam","reason"],"properties":{"success":{"const":false,"type":"boolean"},"isSpam":{"const":true,"type":"boolean"},"reason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","isSpam","reason"],"properties":{"success":{"const":false,"type":"boolean"},"isSpam":{"const":true,"type":"boolean"},"reason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","isSpam","reason"],"properties":{"success":{"const":false,"type":"boolean"},"isSpam":{"const":true,"type":"boolean"},"reason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","isSpam","reason"],"properties":{"success":{"const":false,"type":"boolean"},"isSpam":{"const":true,"type":"boolean"},"reason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}}}}},"operationId":"postApiV1PostCommentEdit","tags":["post"],"summary":"Edit post comment","description":"INTERNAL. Edit an existing comment (content only). Note: table has no updated_date; consider adding it if you want \"edited\" UI.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["commentId","content"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"content":{"minLength":1,"maxLength":5000,"examples":["Super článek, díky!"],"description":"Plain text comment content.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["commentId","content"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"content":{"minLength":1,"maxLength":5000,"examples":["Super článek, díky!"],"description":"Plain text comment content.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["commentId","content"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"},"content":{"minLength":1,"maxLength":5000,"examples":["Super článek, díky!"],"description":"Plain text comment content.","type":"string"}}}}}}}},"/api/v1/post/comment/delete":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}}}}},"operationId":"postApiV1PostCommentDelete","tags":["post"],"summary":"Delete post comment","description":"INTERNAL. Soft delete a comment by setting deleted_date.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["commentId"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["commentId"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["commentId"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"}}}}}}}},"/api/v1/post/comment/restore":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}}}}},"operationId":"postApiV1PostCommentRestore","tags":["post"],"summary":"Restore post comment","description":"INTERNAL. Restore a soft-deleted comment (sets deleted_date = null).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["commentId"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["commentId"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["commentId"],"properties":{"commentId":{"examples":["Abc1dEf2gHiJ3kL4"],"description":"Comment external ID (content__post_comment.external_id), 16-char string.","type":"string"}}}}}}}},"/api/v1/product/detail":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Locale code (e.g. \"cs\", \"en\"). Returns translated read model for the given locale with fallback.","examples":["cs","en"],"schema":{"type":"string"},"in":"query","name":"locale","required":false},{"description":"Add extra on demand properties separated by semicolon.\n\nSupported values:\n\n| Property | Description |\n|----------|-------------|\n| `orderStatistics` | Extra statistics data like `totalQuantitySold` and count of orders in states. |\n| `galleryItemsCount` | Count of public images in product detail. |","examples":["orderStatistics;galleryItemsCount","galleryItemsCount"],"schema":{"type":"string"},"in":"query","name":"properties","required":false}],"responses":{"200":{"description":"Full product detail from the read model.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Product code identifier.","examples":["burger"],"type":"string"},"code":{"description":"Product code identifier (same as id).","examples":["burger"],"type":"string"},"name":{"description":"Localized product name.","examples":["Cheese Burger"],"type":"string"},"slug":{"description":"URL-friendly product identifier.","examples":["cheese-burger"],"type":"string"},"shortDescription":{"description":"Short HTML description for listings. Returned as sanitized HTML string.","type":"string"},"longDescription":{"description":"Full HTML description for product detail page. Returned as sanitized HTML string.","type":"string"},"mainImageUrl":{"description":"URL of the main product image.","examples":["https://storage.xhp.cz/..."],"type":"string"},"galleryItems":{"description":"List of product gallery media items.","type":"array","items":{"description":"Product gallery media item.","type":"object","required":["type","id","url"],"properties":{"type":{"default":"image","description":"Media type of the gallery item.","type":"string","enum":["image","video"]},"id":{"description":"Gallery item ID.","type":"number"},"url":{"description":"Public URL of the media file.","examples":["https://storage.xhp.cz/..."],"type":"string"},"title":{"description":"Optional title of the gallery item.","type":"string"},"tag":{"description":"Optional tag for grouping or filtering.","type":"string"}}}},"galleryItemsCount":{"description":"Total count of gallery items.","type":"number"},"isVariantProduct":{"description":"Whether the product has variants.","type":"boolean"},"variantItems":{"description":"List of product variants (only non-sold-out).","type":"array","items":{"description":"Product variant item.","type":"object","required":["id","code","name","price"],"properties":{"id":{"description":"Variant relation hash.","examples":["abc123"],"type":"string"},"code":{"description":"Variant code identifier.","examples":["cheese-burger"],"type":"string"},"name":{"description":"Variant display name.","examples":["Cheese Burger"],"type":"string"},"ean":{"description":"EAN barcode.","examples":["8594000000001"],"type":"string"},"price":{"description":"Variant price (base product price + variant addition).","examples":[250],"type":"number"},"warehouseAllQuantity":{"description":"Available warehouse quantity for this variant.","type":"number"}}}},"active":{"description":"Whether the product is active and visible.","type":"boolean"},"b2b":{"description":"Whether this is a B2B-only product.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in public feed.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"position":{"description":"Display position for sorting.","examples":[1],"type":"number"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"categoryPathItems":{"description":"Breadcrumb path from root to main category.","type":"array","items":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}}},"categoryItems":{"description":"All categories the product belongs to.","type":"array","items":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}}},"brandId":{"description":"Associated brand ID.","type":"number"},"price":{"description":"Final product price including VAT.","examples":[250],"type":"number"},"priceWithoutVat":{"description":"Product price excluding VAT.","examples":[206.61],"type":"number"},"vat":{"description":"VAT percentage rate.","examples":[21],"type":"number"},"standardPricePercentage":{"description":"Standard price percentage (e.g. for discounts).","type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","type":"number"},"weightGrams":{"description":"Product weight in grams.","type":"number"},"warehouseAllQuantity":{"description":"Total available warehouse quantity.","type":"number"},"warehouseLimit":{"description":"Minimum warehouse quantity threshold.","type":"number"},"event":{"description":"Calendar event linked to the product.","type":"object","required":["id","startTime","endTime","isAllDay","isBlocking","title"],"properties":{"id":{"description":"Event code identifier.","type":"string"},"startTime":{"description":"Event start date and time.","anyOf":[{"description":"Event start date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end date and time.","anyOf":[{"description":"Event end date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks other bookings.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"description":{"description":"Event description text.","type":"string"},"agenda":{"description":"Event agenda or schedule.","type":"string"},"url":{"description":"External URL for the event.","type":"string"},"locationTitle":{"description":"Name of the event location.","type":"string"}}},"advance":{"description":"Advanced product data.","type":"object","required":["relatedCustomers"],"properties":{"relatedCustomers":{"description":"External IDs of related customers.","type":"array","items":{"type":"string"}}}},"relatedProducts":{"description":"List of related products.","type":"array","items":{"description":"Related product reference.","type":"object","required":["slug","name","price"],"properties":{"slug":{"description":"URL slug of the related product.","type":"string"},"name":{"description":"Related product name.","type":"string"},"mainImageUrl":{"description":"URL of the main image.","type":"string"},"price":{"description":"Product price.","type":"number"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"shortDescription":{"description":"Short HTML description. Returned as sanitized HTML string.","type":"string"}}}},"customFields":{"description":"Custom key-value fields defined by the organisation.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"lastUpdate":{"description":"Timestamp of the last read model update.","anyOf":[{"description":"Timestamp of the last read model update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderStatistics":{"description":"Aggregated order statistics for the product.","type":"object","required":["totalQuantitySold","statusNew","statusProcessing","statusStorno","statusDone"],"properties":{"totalQuantitySold":{"description":"Total quantity sold across all order statuses.","type":"number"},"statusNew":{"description":"Quantity in new orders.","type":"number"},"statusProcessing":{"description":"Quantity in processing orders.","type":"number"},"statusStorno":{"description":"Quantity in canceled orders.","type":"number"},"statusDone":{"description":"Quantity in completed orders.","type":"number"}}}},"required":["id","code","name","slug","shortDescription","longDescription","galleryItems","galleryItemsCount","isVariantProduct","variantItems","active","b2b","showInFeed","soldOut","position","categoryPathItems","categoryItems","price","priceWithoutVat","vat","advance","relatedProducts","customFields","lastUpdate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Product code identifier.","examples":["burger"],"type":"string"},"code":{"description":"Product code identifier (same as id).","examples":["burger"],"type":"string"},"name":{"description":"Localized product name.","examples":["Cheese Burger"],"type":"string"},"slug":{"description":"URL-friendly product identifier.","examples":["cheese-burger"],"type":"string"},"shortDescription":{"description":"Short HTML description for listings. Returned as sanitized HTML string.","type":"string"},"longDescription":{"description":"Full HTML description for product detail page. Returned as sanitized HTML string.","type":"string"},"mainImageUrl":{"description":"URL of the main product image.","examples":["https://storage.xhp.cz/..."],"type":"string"},"galleryItems":{"description":"List of product gallery media items.","type":"array","items":{"description":"Product gallery media item.","type":"object","required":["type","id","url"],"properties":{"type":{"default":"image","description":"Media type of the gallery item.","type":"string","enum":["image","video"]},"id":{"description":"Gallery item ID.","type":"number"},"url":{"description":"Public URL of the media file.","examples":["https://storage.xhp.cz/..."],"type":"string"},"title":{"description":"Optional title of the gallery item.","type":"string"},"tag":{"description":"Optional tag for grouping or filtering.","type":"string"}}}},"galleryItemsCount":{"description":"Total count of gallery items.","type":"number"},"isVariantProduct":{"description":"Whether the product has variants.","type":"boolean"},"variantItems":{"description":"List of product variants (only non-sold-out).","type":"array","items":{"description":"Product variant item.","type":"object","required":["id","code","name","price"],"properties":{"id":{"description":"Variant relation hash.","examples":["abc123"],"type":"string"},"code":{"description":"Variant code identifier.","examples":["cheese-burger"],"type":"string"},"name":{"description":"Variant display name.","examples":["Cheese Burger"],"type":"string"},"ean":{"description":"EAN barcode.","examples":["8594000000001"],"type":"string"},"price":{"description":"Variant price (base product price + variant addition).","examples":[250],"type":"number"},"warehouseAllQuantity":{"description":"Available warehouse quantity for this variant.","type":"number"}}}},"active":{"description":"Whether the product is active and visible.","type":"boolean"},"b2b":{"description":"Whether this is a B2B-only product.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in public feed.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"position":{"description":"Display position for sorting.","examples":[1],"type":"number"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"categoryPathItems":{"description":"Breadcrumb path from root to main category.","type":"array","items":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}}},"categoryItems":{"description":"All categories the product belongs to.","type":"array","items":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}}},"brandId":{"description":"Associated brand ID.","type":"number"},"price":{"description":"Final product price including VAT.","examples":[250],"type":"number"},"priceWithoutVat":{"description":"Product price excluding VAT.","examples":[206.61],"type":"number"},"vat":{"description":"VAT percentage rate.","examples":[21],"type":"number"},"standardPricePercentage":{"description":"Standard price percentage (e.g. for discounts).","type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","type":"number"},"weightGrams":{"description":"Product weight in grams.","type":"number"},"warehouseAllQuantity":{"description":"Total available warehouse quantity.","type":"number"},"warehouseLimit":{"description":"Minimum warehouse quantity threshold.","type":"number"},"event":{"description":"Calendar event linked to the product.","type":"object","required":["id","startTime","endTime","isAllDay","isBlocking","title"],"properties":{"id":{"description":"Event code identifier.","type":"string"},"startTime":{"description":"Event start date and time.","anyOf":[{"description":"Event start date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end date and time.","anyOf":[{"description":"Event end date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks other bookings.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"description":{"description":"Event description text.","type":"string"},"agenda":{"description":"Event agenda or schedule.","type":"string"},"url":{"description":"External URL for the event.","type":"string"},"locationTitle":{"description":"Name of the event location.","type":"string"}}},"advance":{"description":"Advanced product data.","type":"object","required":["relatedCustomers"],"properties":{"relatedCustomers":{"description":"External IDs of related customers.","type":"array","items":{"type":"string"}}}},"relatedProducts":{"description":"List of related products.","type":"array","items":{"description":"Related product reference.","type":"object","required":["slug","name","price"],"properties":{"slug":{"description":"URL slug of the related product.","type":"string"},"name":{"description":"Related product name.","type":"string"},"mainImageUrl":{"description":"URL of the main image.","type":"string"},"price":{"description":"Product price.","type":"number"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"shortDescription":{"description":"Short HTML description. Returned as sanitized HTML string.","type":"string"}}}},"customFields":{"description":"Custom key-value fields defined by the organisation.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"lastUpdate":{"description":"Timestamp of the last read model update.","anyOf":[{"description":"Timestamp of the last read model update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderStatistics":{"description":"Aggregated order statistics for the product.","type":"object","required":["totalQuantitySold","statusNew","statusProcessing","statusStorno","statusDone"],"properties":{"totalQuantitySold":{"description":"Total quantity sold across all order statuses.","type":"number"},"statusNew":{"description":"Quantity in new orders.","type":"number"},"statusProcessing":{"description":"Quantity in processing orders.","type":"number"},"statusStorno":{"description":"Quantity in canceled orders.","type":"number"},"statusDone":{"description":"Quantity in completed orders.","type":"number"}}}},"required":["id","code","name","slug","shortDescription","longDescription","galleryItems","galleryItemsCount","isVariantProduct","variantItems","active","b2b","showInFeed","soldOut","position","categoryPathItems","categoryItems","price","priceWithoutVat","vat","advance","relatedProducts","customFields","lastUpdate"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Product code identifier.","examples":["burger"],"type":"string"},"code":{"description":"Product code identifier (same as id).","examples":["burger"],"type":"string"},"name":{"description":"Localized product name.","examples":["Cheese Burger"],"type":"string"},"slug":{"description":"URL-friendly product identifier.","examples":["cheese-burger"],"type":"string"},"shortDescription":{"description":"Short HTML description for listings. Returned as sanitized HTML string.","type":"string"},"longDescription":{"description":"Full HTML description for product detail page. Returned as sanitized HTML string.","type":"string"},"mainImageUrl":{"description":"URL of the main product image.","examples":["https://storage.xhp.cz/..."],"type":"string"},"galleryItems":{"description":"List of product gallery media items.","type":"array","items":{"description":"Product gallery media item.","type":"object","required":["type","id","url"],"properties":{"type":{"default":"image","description":"Media type of the gallery item.","type":"string","enum":["image","video"]},"id":{"description":"Gallery item ID.","type":"number"},"url":{"description":"Public URL of the media file.","examples":["https://storage.xhp.cz/..."],"type":"string"},"title":{"description":"Optional title of the gallery item.","type":"string"},"tag":{"description":"Optional tag for grouping or filtering.","type":"string"}}}},"galleryItemsCount":{"description":"Total count of gallery items.","type":"number"},"isVariantProduct":{"description":"Whether the product has variants.","type":"boolean"},"variantItems":{"description":"List of product variants (only non-sold-out).","type":"array","items":{"description":"Product variant item.","type":"object","required":["id","code","name","price"],"properties":{"id":{"description":"Variant relation hash.","examples":["abc123"],"type":"string"},"code":{"description":"Variant code identifier.","examples":["cheese-burger"],"type":"string"},"name":{"description":"Variant display name.","examples":["Cheese Burger"],"type":"string"},"ean":{"description":"EAN barcode.","examples":["8594000000001"],"type":"string"},"price":{"description":"Variant price (base product price + variant addition).","examples":[250],"type":"number"},"warehouseAllQuantity":{"description":"Available warehouse quantity for this variant.","type":"number"}}}},"active":{"description":"Whether the product is active and visible.","type":"boolean"},"b2b":{"description":"Whether this is a B2B-only product.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in public feed.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"position":{"description":"Display position for sorting.","examples":[1],"type":"number"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"categoryPathItems":{"description":"Breadcrumb path from root to main category.","type":"array","items":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}}},"categoryItems":{"description":"All categories the product belongs to.","type":"array","items":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}}},"brandId":{"description":"Associated brand ID.","type":"number"},"price":{"description":"Final product price including VAT.","examples":[250],"type":"number"},"priceWithoutVat":{"description":"Product price excluding VAT.","examples":[206.61],"type":"number"},"vat":{"description":"VAT percentage rate.","examples":[21],"type":"number"},"standardPricePercentage":{"description":"Standard price percentage (e.g. for discounts).","type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","type":"number"},"weightGrams":{"description":"Product weight in grams.","type":"number"},"warehouseAllQuantity":{"description":"Total available warehouse quantity.","type":"number"},"warehouseLimit":{"description":"Minimum warehouse quantity threshold.","type":"number"},"event":{"description":"Calendar event linked to the product.","type":"object","required":["id","startTime","endTime","isAllDay","isBlocking","title"],"properties":{"id":{"description":"Event code identifier.","type":"string"},"startTime":{"description":"Event start date and time.","anyOf":[{"description":"Event start date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end date and time.","anyOf":[{"description":"Event end date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks other bookings.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"description":{"description":"Event description text.","type":"string"},"agenda":{"description":"Event agenda or schedule.","type":"string"},"url":{"description":"External URL for the event.","type":"string"},"locationTitle":{"description":"Name of the event location.","type":"string"}}},"advance":{"description":"Advanced product data.","type":"object","required":["relatedCustomers"],"properties":{"relatedCustomers":{"description":"External IDs of related customers.","type":"array","items":{"type":"string"}}}},"relatedProducts":{"description":"List of related products.","type":"array","items":{"description":"Related product reference.","type":"object","required":["slug","name","price"],"properties":{"slug":{"description":"URL slug of the related product.","type":"string"},"name":{"description":"Related product name.","type":"string"},"mainImageUrl":{"description":"URL of the main image.","type":"string"},"price":{"description":"Product price.","type":"number"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"shortDescription":{"description":"Short HTML description. Returned as sanitized HTML string.","type":"string"}}}},"customFields":{"description":"Custom key-value fields defined by the organisation.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"lastUpdate":{"description":"Timestamp of the last read model update.","anyOf":[{"description":"Timestamp of the last read model update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderStatistics":{"description":"Aggregated order statistics for the product.","type":"object","required":["totalQuantitySold","statusNew","statusProcessing","statusStorno","statusDone"],"properties":{"totalQuantitySold":{"description":"Total quantity sold across all order statuses.","type":"number"},"statusNew":{"description":"Quantity in new orders.","type":"number"},"statusProcessing":{"description":"Quantity in processing orders.","type":"number"},"statusStorno":{"description":"Quantity in canceled orders.","type":"number"},"statusDone":{"description":"Quantity in completed orders.","type":"number"}}}},"required":["id","code","name","slug","shortDescription","longDescription","galleryItems","galleryItemsCount","isVariantProduct","variantItems","active","b2b","showInFeed","soldOut","position","categoryPathItems","categoryItems","price","priceWithoutVat","vat","advance","relatedProducts","customFields","lastUpdate"]}}}}},"operationId":"getApiV1ProductDetail","tags":["product"]}},"/api/v1/product/feed":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Search query","examples":["iphone"],"schema":{"type":"string"},"in":"query","name":"query","required":false},{"description":"Locale code (e.g. \"cs\", \"en\"). Returns translated read models for the given locale with fallback to default.","examples":["cs","en"],"schema":{"type":"string"},"in":"query","name":"locale","required":false},{"description":"Order by indexed internal field.\n\nSupported values: `position`, `price`, `priceDesc`, `eventDate`.","examples":["position","price","priceDesc","eventDate"],"schema":{"type":"string","default":"position"},"in":"query","name":"orderBy","required":false},{"description":"Filter products from category by slug.","examples":["smartphone"],"schema":{"type":"string"},"in":"query","name":"category","required":false},{"schema":{"type":"string","default":"1"},"in":"query","name":"page","required":false},{"schema":{"type":"string","default":"32"},"in":"query","name":"limit","required":false},{"description":"Add extra on demand properties separated by semicolon.\n\nSupported values:\n\n| Property | Description |\n|----------|-------------|\n| `orderStatistics` | Extra statistics data like `totalQuantitySold` and count of orders in states. |\n| `galleryItemsCount` | Count of public images in product detail. |","examples":["orderStatistics;galleryItemsCount","galleryItemsCount"],"schema":{"type":"string"},"in":"query","name":"properties","required":false}],"responses":{"200":{"description":"Paginated product feed response.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"description":"Number of items returned on this page. For the total number of items matching the filter across all pages use `totalCount`.","type":"number"},"totalCount":{"description":"Total number of products matching the filter (query + category), independent of page and limit. Use `Math.ceil(totalCount / limit)` to compute the page count.","type":"number"},"items":{"description":"List of product feed items.","type":"array","items":{"additionalProperties":true,"description":"Product feed item. Returned properties depend on the properties query parameter.","type":"object","required":["id","name","slug","price","position","active","soldOut"],"properties":{"id":{"description":"Internal product ID.","examples":[42],"type":"number"},"name":{"description":"Localized product name.","examples":["Cheese Burger"],"type":"string"},"slug":{"description":"URL-friendly product identifier.","examples":["cheese-burger"],"type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"price":{"description":"Product price including VAT.","examples":[250],"type":"number"},"priceWithoutVat":{"description":"Product price excluding VAT.","type":"number"},"vat":{"description":"VAT percentage rate.","type":"number"},"position":{"description":"Display position for sorting.","examples":[1],"type":"number"},"active":{"description":"Whether the product is active.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"warehouseAllQuantity":{"description":"Total available warehouse quantity.","type":"number"},"warehouseLimit":{"description":"Minimum warehouse quantity threshold.","type":"number"},"customFields":{"description":"Custom key-value fields.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"event":{"description":"Calendar event linked to the product.","type":"object","required":["id","startTime","endTime","isAllDay","isBlocking","title"],"properties":{"id":{"description":"Event code identifier.","type":"string"},"startTime":{"description":"Event start date and time.","anyOf":[{"description":"Event start date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end date and time.","anyOf":[{"description":"Event end date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks other bookings.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"description":{"description":"Event description text.","type":"string"},"agenda":{"description":"Event agenda or schedule.","type":"string"},"url":{"description":"External URL for the event.","type":"string"},"locationTitle":{"description":"Name of the event location.","type":"string"}}},"orderStatistics":{"description":"Aggregated order statistics for the product.","type":"object","required":["totalQuantitySold","statusNew","statusProcessing","statusStorno","statusDone"],"properties":{"totalQuantitySold":{"description":"Total quantity sold across all order statuses.","type":"number"},"statusNew":{"description":"Quantity in new orders.","type":"number"},"statusProcessing":{"description":"Quantity in processing orders.","type":"number"},"statusStorno":{"description":"Quantity in canceled orders.","type":"number"},"statusDone":{"description":"Quantity in completed orders.","type":"number"}}},"galleryItemsCount":{"description":"Count of public images in product detail.","type":"number"}}}}},"required":["count","totalCount","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"count":{"description":"Number of items returned on this page. For the total number of items matching the filter across all pages use `totalCount`.","type":"number"},"totalCount":{"description":"Total number of products matching the filter (query + category), independent of page and limit. Use `Math.ceil(totalCount / limit)` to compute the page count.","type":"number"},"items":{"description":"List of product feed items.","type":"array","items":{"additionalProperties":true,"description":"Product feed item. Returned properties depend on the properties query parameter.","type":"object","required":["id","name","slug","price","position","active","soldOut"],"properties":{"id":{"description":"Internal product ID.","examples":[42],"type":"number"},"name":{"description":"Localized product name.","examples":["Cheese Burger"],"type":"string"},"slug":{"description":"URL-friendly product identifier.","examples":["cheese-burger"],"type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"price":{"description":"Product price including VAT.","examples":[250],"type":"number"},"priceWithoutVat":{"description":"Product price excluding VAT.","type":"number"},"vat":{"description":"VAT percentage rate.","type":"number"},"position":{"description":"Display position for sorting.","examples":[1],"type":"number"},"active":{"description":"Whether the product is active.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"warehouseAllQuantity":{"description":"Total available warehouse quantity.","type":"number"},"warehouseLimit":{"description":"Minimum warehouse quantity threshold.","type":"number"},"customFields":{"description":"Custom key-value fields.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"event":{"description":"Calendar event linked to the product.","type":"object","required":["id","startTime","endTime","isAllDay","isBlocking","title"],"properties":{"id":{"description":"Event code identifier.","type":"string"},"startTime":{"description":"Event start date and time.","anyOf":[{"description":"Event start date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end date and time.","anyOf":[{"description":"Event end date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks other bookings.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"description":{"description":"Event description text.","type":"string"},"agenda":{"description":"Event agenda or schedule.","type":"string"},"url":{"description":"External URL for the event.","type":"string"},"locationTitle":{"description":"Name of the event location.","type":"string"}}},"orderStatistics":{"description":"Aggregated order statistics for the product.","type":"object","required":["totalQuantitySold","statusNew","statusProcessing","statusStorno","statusDone"],"properties":{"totalQuantitySold":{"description":"Total quantity sold across all order statuses.","type":"number"},"statusNew":{"description":"Quantity in new orders.","type":"number"},"statusProcessing":{"description":"Quantity in processing orders.","type":"number"},"statusStorno":{"description":"Quantity in canceled orders.","type":"number"},"statusDone":{"description":"Quantity in completed orders.","type":"number"}}},"galleryItemsCount":{"description":"Count of public images in product detail.","type":"number"}}}}},"required":["count","totalCount","items"]}},"text/plain":{"schema":{"type":"object","properties":{"count":{"description":"Number of items returned on this page. For the total number of items matching the filter across all pages use `totalCount`.","type":"number"},"totalCount":{"description":"Total number of products matching the filter (query + category), independent of page and limit. Use `Math.ceil(totalCount / limit)` to compute the page count.","type":"number"},"items":{"description":"List of product feed items.","type":"array","items":{"additionalProperties":true,"description":"Product feed item. Returned properties depend on the properties query parameter.","type":"object","required":["id","name","slug","price","position","active","soldOut"],"properties":{"id":{"description":"Internal product ID.","examples":[42],"type":"number"},"name":{"description":"Localized product name.","examples":["Cheese Burger"],"type":"string"},"slug":{"description":"URL-friendly product identifier.","examples":["cheese-burger"],"type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"mainCategory":{"description":"Product category reference.","type":"object","required":["slug","code","name"],"properties":{"slug":{"description":"URL-friendly category identifier.","examples":["smartphone"],"type":"string"},"code":{"description":"Internal category code.","examples":["CAT-001"],"type":"string"},"name":{"description":"Localized category name.","examples":["Smartphones"],"type":"string"}}},"price":{"description":"Product price including VAT.","examples":[250],"type":"number"},"priceWithoutVat":{"description":"Product price excluding VAT.","type":"number"},"vat":{"description":"VAT percentage rate.","type":"number"},"position":{"description":"Display position for sorting.","examples":[1],"type":"number"},"active":{"description":"Whether the product is active.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"warehouseAllQuantity":{"description":"Total available warehouse quantity.","type":"number"},"warehouseLimit":{"description":"Minimum warehouse quantity threshold.","type":"number"},"customFields":{"description":"Custom key-value fields.","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"event":{"description":"Calendar event linked to the product.","type":"object","required":["id","startTime","endTime","isAllDay","isBlocking","title"],"properties":{"id":{"description":"Event code identifier.","type":"string"},"startTime":{"description":"Event start date and time.","anyOf":[{"description":"Event start date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end date and time.","anyOf":[{"description":"Event end date and time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks other bookings.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"description":{"description":"Event description text.","type":"string"},"agenda":{"description":"Event agenda or schedule.","type":"string"},"url":{"description":"External URL for the event.","type":"string"},"locationTitle":{"description":"Name of the event location.","type":"string"}}},"orderStatistics":{"description":"Aggregated order statistics for the product.","type":"object","required":["totalQuantitySold","statusNew","statusProcessing","statusStorno","statusDone"],"properties":{"totalQuantitySold":{"description":"Total quantity sold across all order statuses.","type":"number"},"statusNew":{"description":"Quantity in new orders.","type":"number"},"statusProcessing":{"description":"Quantity in processing orders.","type":"number"},"statusStorno":{"description":"Quantity in canceled orders.","type":"number"},"statusDone":{"description":"Quantity in completed orders.","type":"number"}}},"galleryItemsCount":{"description":"Count of public images in product detail.","type":"number"}}}}},"required":["count","totalCount","items"]}}}}},"operationId":"getApiV1ProductFeed","tags":["product"],"description":"Load full list of products from organisation database. By default, we only return basic properties for all products. If you want to return entire products, you need to specify additional properties.\n\nDefault properties (contains in all returned products): `id`, `name`, `slug`, `shortDescription`, `mainImageUrl`, `mainCategory`, `price`, `priceWithoutVat`, `vat`, `position`, `active`, `soldOut`, `warehouseAllQuantity`, `warehouseLimit`, `customFields`, `event`."}},"/api/v1/product-category/detail":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"URL slug of the product category.","examples":["electronics"],"schema":{"type":"string"},"in":"query","name":"slug","required":true}],"responses":{"200":{"anyOf":[{"description":"Category detail.","type":"object","required":["id","name","slug","b2b"],"properties":{"id":{"description":"Category code (unique identifier).","examples":["cat_electronics"],"type":"string"},"name":{"description":"Display name of the category.","examples":["Electronics"],"type":"string"},"slug":{"description":"URL-friendly slug.","examples":["electronics"],"type":"string"},"description":{"description":"HTML description formatted for frontend display.","type":"string"},"b2b":{"description":"Whether the category is B2B-only.","type":"boolean"}}},{"description":"Error response when category does not exist.","type":"object","required":["state","code","message"],"properties":{"state":{"type":"string"},"code":{"type":"number"},"message":{"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"description":"Category detail.","type":"object","required":["id","name","slug","b2b"],"properties":{"id":{"description":"Category code (unique identifier).","examples":["cat_electronics"],"type":"string"},"name":{"description":"Display name of the category.","examples":["Electronics"],"type":"string"},"slug":{"description":"URL-friendly slug.","examples":["electronics"],"type":"string"},"description":{"description":"HTML description formatted for frontend display.","type":"string"},"b2b":{"description":"Whether the category is B2B-only.","type":"boolean"}}},{"description":"Error response when category does not exist.","type":"object","required":["state","code","message"],"properties":{"state":{"type":"string"},"code":{"type":"number"},"message":{"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"description":"Category detail.","type":"object","required":["id","name","slug","b2b"],"properties":{"id":{"description":"Category code (unique identifier).","examples":["cat_electronics"],"type":"string"},"name":{"description":"Display name of the category.","examples":["Electronics"],"type":"string"},"slug":{"description":"URL-friendly slug.","examples":["electronics"],"type":"string"},"description":{"description":"HTML description formatted for frontend display.","type":"string"},"b2b":{"description":"Whether the category is B2B-only.","type":"boolean"}}},{"description":"Error response when category does not exist.","type":"object","required":["state","code","message"],"properties":{"state":{"type":"string"},"code":{"type":"number"},"message":{"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"description":"Category detail.","type":"object","required":["id","name","slug","b2b"],"properties":{"id":{"description":"Category code (unique identifier).","examples":["cat_electronics"],"type":"string"},"name":{"description":"Display name of the category.","examples":["Electronics"],"type":"string"},"slug":{"description":"URL-friendly slug.","examples":["electronics"],"type":"string"},"description":{"description":"HTML description formatted for frontend display.","type":"string"},"b2b":{"description":"Whether the category is B2B-only.","type":"boolean"}}},{"description":"Error response when category does not exist.","type":"object","required":["state","code","message"],"properties":{"state":{"type":"string"},"code":{"type":"number"},"message":{"type":"string"}}}]}}}}},"operationId":"getApiV1Product-categoryDetail","tags":["productCategory"],"summary":"Get product category detail","description":"Returns detail of a single product category identified by its URL slug. Returns error PUBLIC_CATEGORY_DOES_NOT_EXIST if the category is deleted, internal, or not found."}},"/api/v1/product-category/list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Slug of the parent category to filter children. Omit for root categories.","schema":{"type":"string"},"in":"query","name":"parentSlug","required":false}],"responses":{"200":{"description":"Paginated list of product categories.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"description":"Total number of categories matching the filter.","type":"number"},"items":{"description":"Array of category items.","type":"array","items":{"type":"object","required":["id","name","slug"],"properties":{"id":{"description":"Category code.","type":"string"},"name":{"description":"Display name.","type":"string"},"slug":{"description":"URL-friendly slug.","type":"string"}}}}},"required":["count","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"count":{"description":"Total number of categories matching the filter.","type":"number"},"items":{"description":"Array of category items.","type":"array","items":{"type":"object","required":["id","name","slug"],"properties":{"id":{"description":"Category code.","type":"string"},"name":{"description":"Display name.","type":"string"},"slug":{"description":"URL-friendly slug.","type":"string"}}}}},"required":["count","items"]}},"text/plain":{"schema":{"type":"object","properties":{"count":{"description":"Total number of categories matching the filter.","type":"number"},"items":{"description":"Array of category items.","type":"array","items":{"type":"object","required":["id","name","slug"],"properties":{"id":{"description":"Category code.","type":"string"},"name":{"description":"Display name.","type":"string"},"slug":{"description":"URL-friendly slug.","type":"string"}}}}},"required":["count","items"]}}}}},"operationId":"getApiV1Product-categoryList","tags":["productCategory"],"summary":"List product categories","description":"Returns a list of product categories for the organisation. Optionally filter by parent category slug to get only direct children."}},"/api/v1/product-category/tree":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Maximum tree depth, counted inclusively from the root. `1` returns only roots, `2` returns roots and their direct children (default), up to 10. Nodes at the maximum depth always have `children: []`.","schema":{"minimum":1,"maximum":10,"default":2,"anyOf":[{"format":"integer","default":0,"type":"string"},{"minimum":1,"maximum":10,"default":2,"description":"Maximum tree depth, counted inclusively from the root. `1` returns only roots, `2` returns roots and their direct children (default), up to 10. Nodes at the maximum depth always have `children: []`.","type":"integer"}]},"in":"query","name":"maxDepth","required":false}],"responses":{"200":{"description":"Product category tree.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Root categories with nested descendants up to maxDepth levels.","type":"array","items":{"$id":"T0","type":"object","required":["id","name","slug","b2b","children"],"properties":{"id":{"description":"Category code (unique identifier).","examples":["cat_lighting"],"type":"string"},"name":{"description":"Display name of the category.","examples":["Lighting"],"type":"string"},"slug":{"description":"URL-friendly slug.","examples":["lighting"],"type":"string"},"description":{"description":"HTML description formatted for frontend display (only present when filled in admin).","type":"string"},"b2b":{"description":"Whether the category is B2B-only.","type":"boolean"},"children":{"description":"Direct child categories. Always present as an array (empty when no children or at maxDepth).","type":"array","items":{"$ref":"T0"}}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Root categories with nested descendants up to maxDepth levels.","type":"array","items":{"$id":"T0","type":"object","required":["id","name","slug","b2b","children"],"properties":{"id":{"description":"Category code (unique identifier).","examples":["cat_lighting"],"type":"string"},"name":{"description":"Display name of the category.","examples":["Lighting"],"type":"string"},"slug":{"description":"URL-friendly slug.","examples":["lighting"],"type":"string"},"description":{"description":"HTML description formatted for frontend display (only present when filled in admin).","type":"string"},"b2b":{"description":"Whether the category is B2B-only.","type":"boolean"},"children":{"description":"Direct child categories. Always present as an array (empty when no children or at maxDepth).","type":"array","items":{"$ref":"T0"}}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Root categories with nested descendants up to maxDepth levels.","type":"array","items":{"$id":"T0","type":"object","required":["id","name","slug","b2b","children"],"properties":{"id":{"description":"Category code (unique identifier).","examples":["cat_lighting"],"type":"string"},"name":{"description":"Display name of the category.","examples":["Lighting"],"type":"string"},"slug":{"description":"URL-friendly slug.","examples":["lighting"],"type":"string"},"description":{"description":"HTML description formatted for frontend display (only present when filled in admin).","type":"string"},"b2b":{"description":"Whether the category is B2B-only.","type":"boolean"},"children":{"description":"Direct child categories. Always present as an array (empty when no children or at maxDepth).","type":"array","items":{"$ref":"T0"}}}}}},"required":["items"]}}}}},"operationId":"getApiV1Product-categoryTree","tags":["productCategory"],"summary":"Get full product category tree","description":"Returns the full category tree for the organisation in a single call, suitable for rendering navigation menus during server-side rendering. Root categories appear in `items`; their descendants are nested under `children` up to `maxDepth` levels deep. Deleted, inactive, and internal categories are excluded. Within each level items are ordered by `position`."}},"/api/v1/rate-limit-status/":{"get":{"responses":{"200":{"description":"Rate limit status.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the request would be allowed under the current rate limit.","type":"boolean"},"limit":{"description":"Maximum number of requests allowed in the window.","examples":[100],"type":"number"},"remaining":{"description":"Number of requests remaining in the current window.","examples":[97],"type":"number"},"reset":{"description":"Unix timestamp (ms) when the rate limit window resets.","type":"number"}},"required":["success","limit","remaining","reset"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the request would be allowed under the current rate limit.","type":"boolean"},"limit":{"description":"Maximum number of requests allowed in the window.","examples":[100],"type":"number"},"remaining":{"description":"Number of requests remaining in the current window.","examples":[97],"type":"number"},"reset":{"description":"Unix timestamp (ms) when the rate limit window resets.","type":"number"}},"required":["success","limit","remaining","reset"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the request would be allowed under the current rate limit.","type":"boolean"},"limit":{"description":"Maximum number of requests allowed in the window.","examples":[100],"type":"number"},"remaining":{"description":"Number of requests remaining in the current window.","examples":[97],"type":"number"},"reset":{"description":"Unix timestamp (ms) when the rate limit window resets.","type":"number"}},"required":["success","limit","remaining","reset"]}}}}},"operationId":"getApiV1Rate-limit-status","tags":["rateLimitStatus"],"summary":"Check rate limit status","description":"Returns the current rate limit state for a test endpoint. Useful for debugging and monitoring rate limit configuration."}},"/api/v1/referral/referred-customers":{"get":{"parameters":[{"description":"cuRefNo = customer reference number.","examples":["1cGIHvFoQDGLAbcA"],"schema":{"type":"string","maxLength":16,"minLength":16},"in":"query","name":"cuRefNo","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["cuRefNo","email","insertedDate","lastActivityDate"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["cuRefNo","email","insertedDate","lastActivityDate"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["cuRefNo","email","insertedDate","lastActivityDate"],"properties":{"cuRefNo":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["items"]}}}}},"operationId":"getApiV1ReferralReferred-customers","tags":["referral"],"summary":"List referred customers","description":"Returns a list of customers referred by the given customer (identified by cuRefNo)."}},"/api/v1/routing/route":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"URL slug to resolve.","examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"anyOf":[{"type":"object","required":["route"],"properties":{"route":{"type":"object","required":["slug","type","canonical","related_entity_id","inserted_date","error"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"type":{"examples":["product-detail","article","post-category","tag"],"description":"Route type. Possible values: `product-detail`, `article`, `post-category`, `tag`.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"},"related_entity_id":{"examples":["570"],"type":"string"},"inserted_date":{"examples":["2025-11-05T15:54:44.493Z"],"anyOf":[{"examples":["2025-11-05T15:54:44.493Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"error":{"examples":[false],"type":"boolean"},"link":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"}}}}},{"type":"object","required":["route"],"properties":{"route":{"type":"object","required":["error"],"properties":{"error":{"examples":[true],"type":"boolean"}}}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["route"],"properties":{"route":{"type":"object","required":["slug","type","canonical","related_entity_id","inserted_date","error"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"type":{"examples":["product-detail","article","post-category","tag"],"description":"Route type. Possible values: `product-detail`, `article`, `post-category`, `tag`.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"},"related_entity_id":{"examples":["570"],"type":"string"},"inserted_date":{"examples":["2025-11-05T15:54:44.493Z"],"anyOf":[{"examples":["2025-11-05T15:54:44.493Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"error":{"examples":[false],"type":"boolean"},"link":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"}}}}},{"type":"object","required":["route"],"properties":{"route":{"type":"object","required":["error"],"properties":{"error":{"examples":[true],"type":"boolean"}}}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["route"],"properties":{"route":{"type":"object","required":["slug","type","canonical","related_entity_id","inserted_date","error"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"type":{"examples":["product-detail","article","post-category","tag"],"description":"Route type. Possible values: `product-detail`, `article`, `post-category`, `tag`.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"},"related_entity_id":{"examples":["570"],"type":"string"},"inserted_date":{"examples":["2025-11-05T15:54:44.493Z"],"anyOf":[{"examples":["2025-11-05T15:54:44.493Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"error":{"examples":[false],"type":"boolean"},"link":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"}}}}},{"type":"object","required":["route"],"properties":{"route":{"type":"object","required":["error"],"properties":{"error":{"examples":[true],"type":"boolean"}}}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["route"],"properties":{"route":{"type":"object","required":["slug","type","canonical","related_entity_id","inserted_date","error"],"properties":{"slug":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"},"type":{"examples":["product-detail","article","post-category","tag"],"description":"Route type. Possible values: `product-detail`, `article`, `post-category`, `tag`.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"canonical":{"type":"boolean"},"related_entity_id":{"examples":["570"],"type":"string"},"inserted_date":{"examples":["2025-11-05T15:54:44.493Z"],"anyOf":[{"examples":["2025-11-05T15:54:44.493Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"error":{"examples":[false],"type":"boolean"},"link":{"examples":["kyber-cena-roku-2025-nejvetsi-vecer-ceske-kyberbezpecnosti-letos"],"type":"string"}}}}},{"type":"object","required":["route"],"properties":{"route":{"type":"object","required":["error"],"properties":{"error":{"examples":[true],"type":"boolean"}}}}}]}}}}},"operationId":"getApiV1RoutingRoute","tags":["routing"],"summary":"Resolve URL route","description":"Resolves a URL slug to its corresponding route, returning the entity type, ID, and locale. Returns error: true if the slug is invalid or not found."}},"/api/v1/security/captcha":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"examples":["mfuunpqsqa1rw8ft"],"type":"string"},"imageBase64":{"examples":["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAV4AAAC..."],"type":"string"}},"required":["token","imageBase64"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"token":{"examples":["mfuunpqsqa1rw8ft"],"type":"string"},"imageBase64":{"examples":["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAV4AAAC..."],"type":"string"}},"required":["token","imageBase64"]}},"text/plain":{"schema":{"type":"object","properties":{"token":{"examples":["mfuunpqsqa1rw8ft"],"type":"string"},"imageBase64":{"examples":["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAV4AAAC..."],"type":"string"}},"required":["token","imageBase64"]}}}}},"operationId":"getApiV1SecurityCaptcha","tags":["security"],"summary":"Generate captcha","description":"Render a random captcha image as base64.\n\nExample:\n\n![captcha](https://cdn.bizkithub.com/images/captcha-nu3bx.webp)"}},"/api/v1/security/captcha-verify":{"get":{"parameters":[{"description":"Captcha token returned by the /captcha endpoint.","examples":["mfuunpqsqa1rw8ft"],"schema":{"type":"string"},"in":"query","name":"token","required":true},{"description":"User-entered captcha code.","examples":["NU3BX"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"examples":["mfuunpqsqa1rw8ft"],"description":"The token that was verified.","type":"string"},"code":{"examples":["NU3BX"],"description":"The code that was submitted.","type":"string"},"status":{"examples":["match","miss","expired-token"],"description":"Verification result.","type":"string"}},"required":["token","code","status"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"token":{"examples":["mfuunpqsqa1rw8ft"],"description":"The token that was verified.","type":"string"},"code":{"examples":["NU3BX"],"description":"The code that was submitted.","type":"string"},"status":{"examples":["match","miss","expired-token"],"description":"Verification result.","type":"string"}},"required":["token","code","status"]}},"text/plain":{"schema":{"type":"object","properties":{"token":{"examples":["mfuunpqsqa1rw8ft"],"description":"The token that was verified.","type":"string"},"code":{"examples":["NU3BX"],"description":"The code that was submitted.","type":"string"},"status":{"examples":["match","miss","expired-token"],"description":"Verification result.","type":"string"}},"required":["token","code","status"]}}}}},"operationId":"getApiV1SecurityCaptcha-verify","tags":["security"],"summary":"Verify captcha code","description":"Verifies whether the user-entered captcha code matches the generated one. Returns status: \"match\" (correct), \"miss\" (wrong code), or \"expired-token\" (token no longer valid)."}},"/api/v1/service-status/":{"get":{"parameters":[{"examples":["php.baraja.cz"],"schema":{"type":"string"},"in":"query","name":"domain","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"host":{"examples":["baraja.cz"],"type":"string"},"domain":{"examples":["php.baraja.cz"],"type":"string"},"status":{"examples":["ok"],"anyOf":[{"const":"ok","type":"string"},{"const":"error","type":"string"}]},"message":{"examples":["Vše v pořádku."],"type":"string"},"color":{"examples":["#4CAF50"],"type":"string"},"httpCode":{"examples":[200],"type":"number"},"lastCheckDate":{"examples":["2024-05-01T10:00:00.000Z"],"anyOf":[{"examples":["2024-05-01T10:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"statusPageUrl":{"examples":["https://status.baraja.cz"],"type":"string"}},"required":["host","domain","status","message","color","statusPageUrl"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"host":{"examples":["baraja.cz"],"type":"string"},"domain":{"examples":["php.baraja.cz"],"type":"string"},"status":{"examples":["ok"],"anyOf":[{"const":"ok","type":"string"},{"const":"error","type":"string"}]},"message":{"examples":["Vše v pořádku."],"type":"string"},"color":{"examples":["#4CAF50"],"type":"string"},"httpCode":{"examples":[200],"type":"number"},"lastCheckDate":{"examples":["2024-05-01T10:00:00.000Z"],"anyOf":[{"examples":["2024-05-01T10:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"statusPageUrl":{"examples":["https://status.baraja.cz"],"type":"string"}},"required":["host","domain","status","message","color","statusPageUrl"]}},"text/plain":{"schema":{"type":"object","properties":{"host":{"examples":["baraja.cz"],"type":"string"},"domain":{"examples":["php.baraja.cz"],"type":"string"},"status":{"examples":["ok"],"anyOf":[{"const":"ok","type":"string"},{"const":"error","type":"string"}]},"message":{"examples":["Vše v pořádku."],"type":"string"},"color":{"examples":["#4CAF50"],"type":"string"},"httpCode":{"examples":[200],"type":"number"},"lastCheckDate":{"examples":["2024-05-01T10:00:00.000Z"],"anyOf":[{"examples":["2024-05-01T10:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"statusPageUrl":{"examples":["https://status.baraja.cz"],"type":"string"}},"required":["host","domain","status","message","color","statusPageUrl"]}}}}},"operationId":"getApiV1Service-status","tags":["serviceStatus"],"description":"The service retrieves information about the domain's availability based on regular crawler scans. If the domain is not already tracked, it will be automatically included for crawling.\n\nThe crawling rules are described on the page [VikiTron Bot](https://vikitron.com/bot).\n\nDomain availability scanning is not subject to robots.txt rules, and we can crawl all domains on the internet. We use multiple signals for scanning, such as downloading the homepage via HTTP request, checking DNS records, requesting HTTP headers, completely loading and rendering the page in Handles Chrome, and more.."}},"/api/v1/shop/order/create":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"links":{"type":"object","required":["orderPageLink","payLink"],"properties":{"orderPageLink":{"examples":["https://bizkithub.com/order?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"payLink":{"examples":["https://bizkithub.com/order/pay?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}},"required":["orderNumber","hash","links"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"links":{"type":"object","required":["orderPageLink","payLink"],"properties":{"orderPageLink":{"examples":["https://bizkithub.com/order?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"payLink":{"examples":["https://bizkithub.com/order/pay?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}},"required":["orderNumber","hash","links"]}},"text/plain":{"schema":{"type":"object","properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"links":{"type":"object","required":["orderPageLink","payLink"],"properties":{"orderPageLink":{"examples":["https://bizkithub.com/order?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"payLink":{"examples":["https://bizkithub.com/order/pay?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}},"required":["orderNumber","hash","links"]}}}}},"operationId":"postApiV1ShopOrderCreate","tags":["order"],"description":"Create a new order. After create a order, please redirect customer to `links.orderPageLink`.\n\n`customer` is the payer; `issuerCustomer` (optional) is the issuer — if omitted, the issuer is the organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customer","items"],"properties":{"customer":{"description":"Paying customer (payer). This customer pays the order and is used as the primary billing entity. If the specified customer account does not exist, the system will automatically create a new customer and link it to the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}},"issuerCustomer":{"description":"Order issuer. The party that issues the order (e.g. delegated purchase or invoicing). Use only when the order is issued by a specific customer. For common e-shop orders, this field should be omitted — the issuer is the organisation by default. If the specified customer does not exist, the system will automatically create one.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}},"copyCustomers":{"description":"List of alternative e-mails of customers for e-mail copy.","type":"array","items":{"examples":["janbarasek@gmail.com"],"type":"string"}},"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["label"],"properties":{"label":{"examples":["Cheese burger"],"description":"Main order items label used in order detail and as invoice line.","type":"string"},"price":{"examples":250,"description":"Absolute value in order-defined currency.\n\nThe item price can be zero. Enter the price as a real value and do not use multiplication. We also accept decimal numbers and handle them safely with a precision of up to two decimal places.\n\nThe price value is determined dynamically based on hierarchy. First, the price you set is used. If no price is set, we attempt to retrieve it from the product variant or the core product. If no price is found there either, the price will be zero.","type":"number"},"vat":{"examples":21,"description":"Percentage VAT rate.","type":"number"},"count":{"examples":1,"description":"Integer value. Quantity, count, hours, ...","type":"number"},"sale":{"examples":[10],"description":"Absolute value in order-defined currency.","type":"number"},"unit":{"examples":["ks","h","m","kg"],"type":"string"},"productCode":{"examples":["burger"],"description":"Link order item to product when product code has been defined.","type":"string"},"variantCode":{"examples":["cheese-burger"],"description":"Link order item to product variant when product code AND variant code has been defined.","type":"string"},"eventCode":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"description":"Link order item to calendar event when event code has been defined.","type":"string"},"creditAmount":{"examples":[100],"description":"How many credits should be added to customer account when order will be paid?","type":"number"},"specialActions":{"examples":["create-voucher:fixed:500;add-credit:15"],"anyOf":[{"examples":["create-voucher:fixed:500"],"type":"string"},{"examples":[["create-voucher:fixed:500","add-credit:20"]],"type":"array","items":{"type":"string"}}]},"branch":{"examples":["gymroom-plzen"],"description":"Slug of the branch (pobočka) that processed this line item. When set, the item is bound to the branch via shop__order_item.branch_id and any credit grant/debit derived from this item is attributed to the branch (shop__contact_credit.payer_branch_id). Omit to leave the item at organisation level.","type":"string"}}}},"orderGroupId":{"examples":["branch-vinohrady"],"description":"Organisation defined order group code.","type":"string"},"kind":{"default":"commerce","description":"Behavioral category of the order. Decides which automatic workflows apply:\n- `commerce` (default): standard order; invoice/receipt is auto-issued by the status rule engine when the chosen status configures it. The customer receives the standard order-status notification.\n- `registration`: order represents a sign-up for an event / form-style admission. No tax document is ever auto-issued (manual admin action via BFF can still issue one). The status rule engine will NOT auto-fire `mark_as_paid` / `create_invoice` / `create_receipt` for this order. The customer receives a registration-confirmation email when the per-group or kind-specific notification template is configured (falls back to standard order-status template if not). Typically combined with all items priced at 0 and a dedicated organisation-defined order group for pairing.","type":"string","enum":["commerce","registration"]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"sale":{"examples":0,"description":"Absolute value in order-defined currency.","type":"number"},"voucherList":{"description":"List of voucher codes to apply to the order.","type":"array","items":{"examples":["SUMMER-15"],"type":"string"}},"paymentMethod":{"default":"credits","description":"Payment strategy.\n- `credits` (default): Uses customer credits first, remaining amount is paid with money.\n- `money`: Forces full payment with money only; customer credits are ignored.","type":"string","enum":["credits","money"]},"deliveryPrice":{"examples":[10],"description":"Absolute value in order-defined currency.","type":"number"},"paymentPrice":{"examples":[0],"description":"Absolute value in order-defined currency.","type":"number"},"expirationDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"type":"string"},"dueDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"type":"string"},"internalNotice":{"description":"Your internal notice for organisation members. Customer should never see this notice.","type":"string"},"publicNotice":{"description":"Public notice defined by customer in cart. This notice can be displayed in e-mail and order detail page.","type":"string"},"tags":{"type":"object","patternProperties":{"^(.*)$":{}}},"returnUrl":{"examples":["https://gymroom.cz/rezervace/dekujeme"],"type":"string"},"notificationUrl":{"type":"string"},"formData":{"type":"object","required":["code","data"],"properties":{"code":{"type":"string"},"data":{"type":"object","patternProperties":{"^(.*)$":{}}}}},"forceIgnoreNegativeCreditBalance":{"default":false,"description":"Mark the order as paid immediately. The customer can go into negative credit. Payment will not be processed.","type":"boolean"},"forceIssueInvoice":{"default":false,"type":"boolean"},"parentId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Hash of the parent order. The parent order must belong to the same organisation.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customer","items"],"properties":{"customer":{"description":"Paying customer (payer). This customer pays the order and is used as the primary billing entity. If the specified customer account does not exist, the system will automatically create a new customer and link it to the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}},"issuerCustomer":{"description":"Order issuer. The party that issues the order (e.g. delegated purchase or invoicing). Use only when the order is issued by a specific customer. For common e-shop orders, this field should be omitted — the issuer is the organisation by default. If the specified customer does not exist, the system will automatically create one.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}},"copyCustomers":{"description":"List of alternative e-mails of customers for e-mail copy.","type":"array","items":{"examples":["janbarasek@gmail.com"],"type":"string"}},"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["label"],"properties":{"label":{"examples":["Cheese burger"],"description":"Main order items label used in order detail and as invoice line.","type":"string"},"price":{"examples":250,"description":"Absolute value in order-defined currency.\n\nThe item price can be zero. Enter the price as a real value and do not use multiplication. We also accept decimal numbers and handle them safely with a precision of up to two decimal places.\n\nThe price value is determined dynamically based on hierarchy. First, the price you set is used. If no price is set, we attempt to retrieve it from the product variant or the core product. If no price is found there either, the price will be zero.","type":"number"},"vat":{"examples":21,"description":"Percentage VAT rate.","type":"number"},"count":{"examples":1,"description":"Integer value. Quantity, count, hours, ...","type":"number"},"sale":{"examples":[10],"description":"Absolute value in order-defined currency.","type":"number"},"unit":{"examples":["ks","h","m","kg"],"type":"string"},"productCode":{"examples":["burger"],"description":"Link order item to product when product code has been defined.","type":"string"},"variantCode":{"examples":["cheese-burger"],"description":"Link order item to product variant when product code AND variant code has been defined.","type":"string"},"eventCode":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"description":"Link order item to calendar event when event code has been defined.","type":"string"},"creditAmount":{"examples":[100],"description":"How many credits should be added to customer account when order will be paid?","type":"number"},"specialActions":{"examples":["create-voucher:fixed:500;add-credit:15"],"anyOf":[{"examples":["create-voucher:fixed:500"],"type":"string"},{"examples":[["create-voucher:fixed:500","add-credit:20"]],"type":"array","items":{"type":"string"}}]},"branch":{"examples":["gymroom-plzen"],"description":"Slug of the branch (pobočka) that processed this line item. When set, the item is bound to the branch via shop__order_item.branch_id and any credit grant/debit derived from this item is attributed to the branch (shop__contact_credit.payer_branch_id). Omit to leave the item at organisation level.","type":"string"}}}},"orderGroupId":{"examples":["branch-vinohrady"],"description":"Organisation defined order group code.","type":"string"},"kind":{"default":"commerce","description":"Behavioral category of the order. Decides which automatic workflows apply:\n- `commerce` (default): standard order; invoice/receipt is auto-issued by the status rule engine when the chosen status configures it. The customer receives the standard order-status notification.\n- `registration`: order represents a sign-up for an event / form-style admission. No tax document is ever auto-issued (manual admin action via BFF can still issue one). The status rule engine will NOT auto-fire `mark_as_paid` / `create_invoice` / `create_receipt` for this order. The customer receives a registration-confirmation email when the per-group or kind-specific notification template is configured (falls back to standard order-status template if not). Typically combined with all items priced at 0 and a dedicated organisation-defined order group for pairing.","type":"string","enum":["commerce","registration"]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"sale":{"examples":0,"description":"Absolute value in order-defined currency.","type":"number"},"voucherList":{"description":"List of voucher codes to apply to the order.","type":"array","items":{"examples":["SUMMER-15"],"type":"string"}},"paymentMethod":{"default":"credits","description":"Payment strategy.\n- `credits` (default): Uses customer credits first, remaining amount is paid with money.\n- `money`: Forces full payment with money only; customer credits are ignored.","type":"string","enum":["credits","money"]},"deliveryPrice":{"examples":[10],"description":"Absolute value in order-defined currency.","type":"number"},"paymentPrice":{"examples":[0],"description":"Absolute value in order-defined currency.","type":"number"},"expirationDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"type":"string"},"dueDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"type":"string"},"internalNotice":{"description":"Your internal notice for organisation members. Customer should never see this notice.","type":"string"},"publicNotice":{"description":"Public notice defined by customer in cart. This notice can be displayed in e-mail and order detail page.","type":"string"},"tags":{"type":"object","patternProperties":{"^(.*)$":{}}},"returnUrl":{"examples":["https://gymroom.cz/rezervace/dekujeme"],"type":"string"},"notificationUrl":{"type":"string"},"formData":{"type":"object","required":["code","data"],"properties":{"code":{"type":"string"},"data":{"type":"object","patternProperties":{"^(.*)$":{}}}}},"forceIgnoreNegativeCreditBalance":{"default":false,"description":"Mark the order as paid immediately. The customer can go into negative credit. Payment will not be processed.","type":"boolean"},"forceIssueInvoice":{"default":false,"type":"boolean"},"parentId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Hash of the parent order. The parent order must belong to the same organisation.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["customer","items"],"properties":{"customer":{"description":"Paying customer (payer). This customer pays the order and is used as the primary billing entity. If the specified customer account does not exist, the system will automatically create a new customer and link it to the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}},"issuerCustomer":{"description":"Order issuer. The party that issues the order (e.g. delegated purchase or invoicing). Use only when the order is issued by a specific customer. For common e-shop orders, this field should be omitted — the issuer is the organisation by default. If the specified customer does not exist, the system will automatically create one.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"examples":["Jan Barášek"],"type":"string"},"firstName":{"examples":["Jan"],"type":"string"},"lastName":{"examples":["Barášek"],"type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"companyName":{"examples":["BizKitHub"],"type":"string"},"companyRegistrationNumber":{"examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"examples":["CZ9609040727"],"type":"string"},"streetAddress":{"examples":["R. Novotného 1505"],"type":"string"},"city":{"examples":["Kladno"],"type":"string"},"cityPart":{"examples":["Kročehlavy"],"type":"string"},"stateRegion":{"examples":["Středočeský kraj"],"type":"string"},"postalCode":{"examples":["272 01"],"type":"string"},"country":{"examples":["CZ","Česká republika","Czechia","Czech"],"type":"string"},"newsletter":{"default":false,"type":"boolean"},"primaryLocale":{"examples":["cs"],"type":"string"},"groups":{"type":"array","items":{"type":"string"}},"customerRealIp":{"examples":["1.1.1.1","2001:4860:4860::8888"],"description":"User IP address used for GEO/IP intelligence.  \n**Accepted formats:** IPv4 (e.g. `1.1.1.1`), IPv6 (e.g. `2001:4860:4860::8888`)  \n**Normalization:**\n- `::1`, `0.0.0.0`, `localhost` (or empty value) is normalized to `127.0.0.1`\n- Invalid values are rejected (the API expects a valid IP string).\n\nIf provided, the system can resolve additional context (reverse DNS, geolocation, ASN, proxy/hosting flags) via our internal VikiTron GEO/IP resolver. [Learn more](https://vikitron.com/ip-lookup)","type":"string"},"referralId":{"examples":["1cGIHvFoQDGLAbcA"],"description":"cuRefNo = customer reference number.","maxLength":16,"minLength":16,"type":"string"}}},"copyCustomers":{"description":"List of alternative e-mails of customers for e-mail copy.","type":"array","items":{"examples":["janbarasek@gmail.com"],"type":"string"}},"cartId":{"examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["label"],"properties":{"label":{"examples":["Cheese burger"],"description":"Main order items label used in order detail and as invoice line.","type":"string"},"price":{"examples":250,"description":"Absolute value in order-defined currency.\n\nThe item price can be zero. Enter the price as a real value and do not use multiplication. We also accept decimal numbers and handle them safely with a precision of up to two decimal places.\n\nThe price value is determined dynamically based on hierarchy. First, the price you set is used. If no price is set, we attempt to retrieve it from the product variant or the core product. If no price is found there either, the price will be zero.","type":"number"},"vat":{"examples":21,"description":"Percentage VAT rate.","type":"number"},"count":{"examples":1,"description":"Integer value. Quantity, count, hours, ...","type":"number"},"sale":{"examples":[10],"description":"Absolute value in order-defined currency.","type":"number"},"unit":{"examples":["ks","h","m","kg"],"type":"string"},"productCode":{"examples":["burger"],"description":"Link order item to product when product code has been defined.","type":"string"},"variantCode":{"examples":["cheese-burger"],"description":"Link order item to product variant when product code AND variant code has been defined.","type":"string"},"eventCode":{"examples":["2WRp6X5rSqQa321EjHB2mxZz74u74H84"],"description":"Link order item to calendar event when event code has been defined.","type":"string"},"creditAmount":{"examples":[100],"description":"How many credits should be added to customer account when order will be paid?","type":"number"},"specialActions":{"examples":["create-voucher:fixed:500;add-credit:15"],"anyOf":[{"examples":["create-voucher:fixed:500"],"type":"string"},{"examples":[["create-voucher:fixed:500","add-credit:20"]],"type":"array","items":{"type":"string"}}]},"branch":{"examples":["gymroom-plzen"],"description":"Slug of the branch (pobočka) that processed this line item. When set, the item is bound to the branch via shop__order_item.branch_id and any credit grant/debit derived from this item is attributed to the branch (shop__contact_credit.payer_branch_id). Omit to leave the item at organisation level.","type":"string"}}}},"orderGroupId":{"examples":["branch-vinohrady"],"description":"Organisation defined order group code.","type":"string"},"kind":{"default":"commerce","description":"Behavioral category of the order. Decides which automatic workflows apply:\n- `commerce` (default): standard order; invoice/receipt is auto-issued by the status rule engine when the chosen status configures it. The customer receives the standard order-status notification.\n- `registration`: order represents a sign-up for an event / form-style admission. No tax document is ever auto-issued (manual admin action via BFF can still issue one). The status rule engine will NOT auto-fire `mark_as_paid` / `create_invoice` / `create_receipt` for this order. The customer receives a registration-confirmation email when the per-group or kind-specific notification template is configured (falls back to standard order-status template if not). Typically combined with all items priced at 0 and a dedicated organisation-defined order group for pairing.","type":"string","enum":["commerce","registration"]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"sale":{"examples":0,"description":"Absolute value in order-defined currency.","type":"number"},"voucherList":{"description":"List of voucher codes to apply to the order.","type":"array","items":{"examples":["SUMMER-15"],"type":"string"}},"paymentMethod":{"default":"credits","description":"Payment strategy.\n- `credits` (default): Uses customer credits first, remaining amount is paid with money.\n- `money`: Forces full payment with money only; customer credits are ignored.","type":"string","enum":["credits","money"]},"deliveryPrice":{"examples":[10],"description":"Absolute value in order-defined currency.","type":"number"},"paymentPrice":{"examples":[0],"description":"Absolute value in order-defined currency.","type":"number"},"expirationDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"type":"string"},"dueDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"type":"string"},"internalNotice":{"description":"Your internal notice for organisation members. Customer should never see this notice.","type":"string"},"publicNotice":{"description":"Public notice defined by customer in cart. This notice can be displayed in e-mail and order detail page.","type":"string"},"tags":{"type":"object","patternProperties":{"^(.*)$":{}}},"returnUrl":{"examples":["https://gymroom.cz/rezervace/dekujeme"],"type":"string"},"notificationUrl":{"type":"string"},"formData":{"type":"object","required":["code","data"],"properties":{"code":{"type":"string"},"data":{"type":"object","patternProperties":{"^(.*)$":{}}}}},"forceIgnoreNegativeCreditBalance":{"default":false,"description":"Mark the order as paid immediately. The customer can go into negative credit. Payment will not be processed.","type":"boolean"},"forceIssueInvoice":{"default":false,"type":"boolean"},"parentId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Hash of the parent order. The parent order must belong to the same organisation.","type":"string"}}}}}}}},"/api/v1/shop/order/detail":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["exist","id","hash","locale","status","variableSymbol","insertedDate","updatedDate","price","sale","items","vouchers","tags","links"],"properties":{"exist":{"description":"Indicator of whether the order exists.","const":true,"type":"boolean"},"id":{"examples":["25000087"],"description":"Order number for system identification.","type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Unique hash of the order.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"payDate":{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of order payment.","anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of order payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"type":"object","required":["label","color","onlinePaymentChecking"],"properties":{"label":{"examples":["Paid"],"description":"Public status label defined by the organization and order group.","type":"string"},"color":{"examples":["#1e90ff"],"type":"string"},"onlinePaymentStatus":{"examples":["CREATED","PAID","CANCELED","PAYMENT_METHOD_CHOSEN","TIMEOUTED","AUTHORIZED","REFUNDED","PARTIALLY_REFUNDED"],"type":"string"},"onlinePaymentStatusLabel":{"examples":["Platba vytvořena","Platba uhrazena","Platba zamítnuta","Platební metoda potvrzena","Platbě vypršela životnost","Platba předautorizována","Platba vrácena","Platba částečně vrácena"],"type":"string"},"onlinePaymentChecking":{"examples":[false],"description":"Indicator of whether online payment checking is in progress.","type":"boolean"}}},"variableSymbol":{"examples":["25000087"],"description":"Unique bank/invoice variable symbol across all organisation.","type":"string"},"publicNotice":{"examples":["Thank you for your order."],"description":"Public note for the order.","type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"description":"Date and time the order was created.","anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"description":"Date and time the order was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:30:07.172Z"],"description":"Date and time the order was last updated.","anyOf":[{"examples":["2025-01-10T16:30:07.172Z"],"description":"Date and time the order was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"examples":["2025-01-12T16:19:40.150Z"],"description":"Date and time of order expiration. If this time is reached and the order is not paid, it will be automatically canceled.","anyOf":[{"examples":["2025-01-12T16:19:40.150Z"],"description":"Date and time of order expiration. If this time is reached and the order is not paid, it will be automatically canceled.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"sale":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"customer":{"type":"object","required":["premium"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Customer phone number.","type":"string"},"firstName":{"examples":["Jan"],"description":"Customer first name.","type":"string"},"lastName":{"examples":["Barášek"],"description":"Customer last name.","type":"string"},"companyName":{"examples":["Company Ltd."],"description":"Name of the customer's company.","type":"string"},"premium":{"examples":[false],"description":"Indicator of whether the customer is premium.","type":"boolean"}}},"items":{"type":"array","items":{"type":"object","required":["id","isStorno","label","count","price","unit","creditAmount"],"properties":{"id":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S_4186"],"description":"Order item ID.","type":"string"},"isStorno":{"examples":[false],"description":"Indicator of whether the item is canceled.","type":"boolean"},"label":{"examples":["GymRoom reservation"],"description":"Order item description as HTML.","type":"string"},"count":{"examples":[1],"description":"Number of items.","type":"number"},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"unit":{"examples":["ks"],"description":"Item units.","type":"string"},"vat":{"type":"number"},"creditAmount":{"examples":[0],"description":"Credit value of the item.","type":"number"},"productCode":{"type":"string"},"productName":{"type":"string"},"productMainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"variantCode":{"type":"string"},"variantName":{"type":"string"},"eventCalendarCode":{"type":"string"},"eventCode":{"type":"string"},"eventTitle":{"type":"string"},"branch":{"examples":["gymroom-plzen"],"description":"Slug of the branch (pobočka) this line item was attributed to.","type":"string"}}}},"vouchers":{"description":"Vouchers redeemed on this order. Their monetary effect (if any) is already reflected in `items` as a negative-priced row; this field is the canonical audit list of the codes themselves.","type":"array","items":{"type":"object","required":["code","type","value","isOrderSingleton","currency"],"properties":{"code":{"examples":["SUMMER-15"],"description":"Voucher code that was redeemed on the order.","type":"string"},"type":{"default":"fixed","description":"Voucher type. `fixed` / `percentage` discount the order total (visible as a negative line item); `free-credit` grants credits to the customer account; `free-product` grants a product line item.","type":"string","enum":["fixed","percentage","free-credit","free-product"]},"value":{"examples":["150","10","3000"],"description":"Type-dependent payload value. For `fixed` the discount amount in order currency, for `percentage` the percentage rate, for `free-credit` the credit amount.","type":"string"},"isOrderSingleton":{"examples":[false],"description":"Whether this voucher cannot be combined with other vouchers on the same order.","type":"boolean"},"currency":{"examples":["CZK"],"type":"string"}}}},"tags":{"type":"object","patternProperties":{"^(.*)$":{}}},"links":{"type":"object","properties":{"onlinePaymentLink":{"examples":["https://bizkithub.com/order/pay?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Link to online payment of the order.","type":"string"},"returnUrl":{"examples":["https://gymroom.cz/eshop/dekujeme-eshop"],"description":"URL to which the customer is redirected after successful payment.","type":"string"}}}}},{"type":"object","required":["exist"],"properties":{"exist":{"const":false,"type":"boolean"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["exist","id","hash","locale","status","variableSymbol","insertedDate","updatedDate","price","sale","items","vouchers","tags","links"],"properties":{"exist":{"description":"Indicator of whether the order exists.","const":true,"type":"boolean"},"id":{"examples":["25000087"],"description":"Order number for system identification.","type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Unique hash of the order.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"payDate":{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of order payment.","anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of order payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"type":"object","required":["label","color","onlinePaymentChecking"],"properties":{"label":{"examples":["Paid"],"description":"Public status label defined by the organization and order group.","type":"string"},"color":{"examples":["#1e90ff"],"type":"string"},"onlinePaymentStatus":{"examples":["CREATED","PAID","CANCELED","PAYMENT_METHOD_CHOSEN","TIMEOUTED","AUTHORIZED","REFUNDED","PARTIALLY_REFUNDED"],"type":"string"},"onlinePaymentStatusLabel":{"examples":["Platba vytvořena","Platba uhrazena","Platba zamítnuta","Platební metoda potvrzena","Platbě vypršela životnost","Platba předautorizována","Platba vrácena","Platba částečně vrácena"],"type":"string"},"onlinePaymentChecking":{"examples":[false],"description":"Indicator of whether online payment checking is in progress.","type":"boolean"}}},"variableSymbol":{"examples":["25000087"],"description":"Unique bank/invoice variable symbol across all organisation.","type":"string"},"publicNotice":{"examples":["Thank you for your order."],"description":"Public note for the order.","type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"description":"Date and time the order was created.","anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"description":"Date and time the order was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:30:07.172Z"],"description":"Date and time the order was last updated.","anyOf":[{"examples":["2025-01-10T16:30:07.172Z"],"description":"Date and time the order was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"examples":["2025-01-12T16:19:40.150Z"],"description":"Date and time of order expiration. If this time is reached and the order is not paid, it will be automatically canceled.","anyOf":[{"examples":["2025-01-12T16:19:40.150Z"],"description":"Date and time of order expiration. If this time is reached and the order is not paid, it will be automatically canceled.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"sale":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"customer":{"type":"object","required":["premium"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Customer phone number.","type":"string"},"firstName":{"examples":["Jan"],"description":"Customer first name.","type":"string"},"lastName":{"examples":["Barášek"],"description":"Customer last name.","type":"string"},"companyName":{"examples":["Company Ltd."],"description":"Name of the customer's company.","type":"string"},"premium":{"examples":[false],"description":"Indicator of whether the customer is premium.","type":"boolean"}}},"items":{"type":"array","items":{"type":"object","required":["id","isStorno","label","count","price","unit","creditAmount"],"properties":{"id":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S_4186"],"description":"Order item ID.","type":"string"},"isStorno":{"examples":[false],"description":"Indicator of whether the item is canceled.","type":"boolean"},"label":{"examples":["GymRoom reservation"],"description":"Order item description as HTML.","type":"string"},"count":{"examples":[1],"description":"Number of items.","type":"number"},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"unit":{"examples":["ks"],"description":"Item units.","type":"string"},"vat":{"type":"number"},"creditAmount":{"examples":[0],"description":"Credit value of the item.","type":"number"},"productCode":{"type":"string"},"productName":{"type":"string"},"productMainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"variantCode":{"type":"string"},"variantName":{"type":"string"},"eventCalendarCode":{"type":"string"},"eventCode":{"type":"string"},"eventTitle":{"type":"string"},"branch":{"examples":["gymroom-plzen"],"description":"Slug of the branch (pobočka) this line item was attributed to.","type":"string"}}}},"vouchers":{"description":"Vouchers redeemed on this order. Their monetary effect (if any) is already reflected in `items` as a negative-priced row; this field is the canonical audit list of the codes themselves.","type":"array","items":{"type":"object","required":["code","type","value","isOrderSingleton","currency"],"properties":{"code":{"examples":["SUMMER-15"],"description":"Voucher code that was redeemed on the order.","type":"string"},"type":{"default":"fixed","description":"Voucher type. `fixed` / `percentage` discount the order total (visible as a negative line item); `free-credit` grants credits to the customer account; `free-product` grants a product line item.","type":"string","enum":["fixed","percentage","free-credit","free-product"]},"value":{"examples":["150","10","3000"],"description":"Type-dependent payload value. For `fixed` the discount amount in order currency, for `percentage` the percentage rate, for `free-credit` the credit amount.","type":"string"},"isOrderSingleton":{"examples":[false],"description":"Whether this voucher cannot be combined with other vouchers on the same order.","type":"boolean"},"currency":{"examples":["CZK"],"type":"string"}}}},"tags":{"type":"object","patternProperties":{"^(.*)$":{}}},"links":{"type":"object","properties":{"onlinePaymentLink":{"examples":["https://bizkithub.com/order/pay?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Link to online payment of the order.","type":"string"},"returnUrl":{"examples":["https://gymroom.cz/eshop/dekujeme-eshop"],"description":"URL to which the customer is redirected after successful payment.","type":"string"}}}}},{"type":"object","required":["exist"],"properties":{"exist":{"const":false,"type":"boolean"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["exist","id","hash","locale","status","variableSymbol","insertedDate","updatedDate","price","sale","items","vouchers","tags","links"],"properties":{"exist":{"description":"Indicator of whether the order exists.","const":true,"type":"boolean"},"id":{"examples":["25000087"],"description":"Order number for system identification.","type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Unique hash of the order.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"payDate":{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of order payment.","anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of order payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"type":"object","required":["label","color","onlinePaymentChecking"],"properties":{"label":{"examples":["Paid"],"description":"Public status label defined by the organization and order group.","type":"string"},"color":{"examples":["#1e90ff"],"type":"string"},"onlinePaymentStatus":{"examples":["CREATED","PAID","CANCELED","PAYMENT_METHOD_CHOSEN","TIMEOUTED","AUTHORIZED","REFUNDED","PARTIALLY_REFUNDED"],"type":"string"},"onlinePaymentStatusLabel":{"examples":["Platba vytvořena","Platba uhrazena","Platba zamítnuta","Platební metoda potvrzena","Platbě vypršela životnost","Platba předautorizována","Platba vrácena","Platba částečně vrácena"],"type":"string"},"onlinePaymentChecking":{"examples":[false],"description":"Indicator of whether online payment checking is in progress.","type":"boolean"}}},"variableSymbol":{"examples":["25000087"],"description":"Unique bank/invoice variable symbol across all organisation.","type":"string"},"publicNotice":{"examples":["Thank you for your order."],"description":"Public note for the order.","type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"description":"Date and time the order was created.","anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"description":"Date and time the order was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:30:07.172Z"],"description":"Date and time the order was last updated.","anyOf":[{"examples":["2025-01-10T16:30:07.172Z"],"description":"Date and time the order was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"examples":["2025-01-12T16:19:40.150Z"],"description":"Date and time of order expiration. If this time is reached and the order is not paid, it will be automatically canceled.","anyOf":[{"examples":["2025-01-12T16:19:40.150Z"],"description":"Date and time of order expiration. If this time is reached and the order is not paid, it will be automatically canceled.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"sale":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"customer":{"type":"object","required":["premium"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Customer phone number.","type":"string"},"firstName":{"examples":["Jan"],"description":"Customer first name.","type":"string"},"lastName":{"examples":["Barášek"],"description":"Customer last name.","type":"string"},"companyName":{"examples":["Company Ltd."],"description":"Name of the customer's company.","type":"string"},"premium":{"examples":[false],"description":"Indicator of whether the customer is premium.","type":"boolean"}}},"items":{"type":"array","items":{"type":"object","required":["id","isStorno","label","count","price","unit","creditAmount"],"properties":{"id":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S_4186"],"description":"Order item ID.","type":"string"},"isStorno":{"examples":[false],"description":"Indicator of whether the item is canceled.","type":"boolean"},"label":{"examples":["GymRoom reservation"],"description":"Order item description as HTML.","type":"string"},"count":{"examples":[1],"description":"Number of items.","type":"number"},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"unit":{"examples":["ks"],"description":"Item units.","type":"string"},"vat":{"type":"number"},"creditAmount":{"examples":[0],"description":"Credit value of the item.","type":"number"},"productCode":{"type":"string"},"productName":{"type":"string"},"productMainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"variantCode":{"type":"string"},"variantName":{"type":"string"},"eventCalendarCode":{"type":"string"},"eventCode":{"type":"string"},"eventTitle":{"type":"string"},"branch":{"examples":["gymroom-plzen"],"description":"Slug of the branch (pobočka) this line item was attributed to.","type":"string"}}}},"vouchers":{"description":"Vouchers redeemed on this order. Their monetary effect (if any) is already reflected in `items` as a negative-priced row; this field is the canonical audit list of the codes themselves.","type":"array","items":{"type":"object","required":["code","type","value","isOrderSingleton","currency"],"properties":{"code":{"examples":["SUMMER-15"],"description":"Voucher code that was redeemed on the order.","type":"string"},"type":{"default":"fixed","description":"Voucher type. `fixed` / `percentage` discount the order total (visible as a negative line item); `free-credit` grants credits to the customer account; `free-product` grants a product line item.","type":"string","enum":["fixed","percentage","free-credit","free-product"]},"value":{"examples":["150","10","3000"],"description":"Type-dependent payload value. For `fixed` the discount amount in order currency, for `percentage` the percentage rate, for `free-credit` the credit amount.","type":"string"},"isOrderSingleton":{"examples":[false],"description":"Whether this voucher cannot be combined with other vouchers on the same order.","type":"boolean"},"currency":{"examples":["CZK"],"type":"string"}}}},"tags":{"type":"object","patternProperties":{"^(.*)$":{}}},"links":{"type":"object","properties":{"onlinePaymentLink":{"examples":["https://bizkithub.com/order/pay?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Link to online payment of the order.","type":"string"},"returnUrl":{"examples":["https://gymroom.cz/eshop/dekujeme-eshop"],"description":"URL to which the customer is redirected after successful payment.","type":"string"}}}}},{"type":"object","required":["exist"],"properties":{"exist":{"const":false,"type":"boolean"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["exist","id","hash","locale","status","variableSymbol","insertedDate","updatedDate","price","sale","items","vouchers","tags","links"],"properties":{"exist":{"description":"Indicator of whether the order exists.","const":true,"type":"boolean"},"id":{"examples":["25000087"],"description":"Order number for system identification.","type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Unique hash of the order.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"payDate":{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of order payment.","anyOf":[{"examples":["2025-01-10T16:19:41.675Z"],"description":"Date and time of order payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"type":"object","required":["label","color","onlinePaymentChecking"],"properties":{"label":{"examples":["Paid"],"description":"Public status label defined by the organization and order group.","type":"string"},"color":{"examples":["#1e90ff"],"type":"string"},"onlinePaymentStatus":{"examples":["CREATED","PAID","CANCELED","PAYMENT_METHOD_CHOSEN","TIMEOUTED","AUTHORIZED","REFUNDED","PARTIALLY_REFUNDED"],"type":"string"},"onlinePaymentStatusLabel":{"examples":["Platba vytvořena","Platba uhrazena","Platba zamítnuta","Platební metoda potvrzena","Platbě vypršela životnost","Platba předautorizována","Platba vrácena","Platba částečně vrácena"],"type":"string"},"onlinePaymentChecking":{"examples":[false],"description":"Indicator of whether online payment checking is in progress.","type":"boolean"}}},"variableSymbol":{"examples":["25000087"],"description":"Unique bank/invoice variable symbol across all organisation.","type":"string"},"publicNotice":{"examples":["Thank you for your order."],"description":"Public note for the order.","type":"string"},"insertedDate":{"examples":["2025-01-10T16:19:40.150Z"],"description":"Date and time the order was created.","anyOf":[{"examples":["2025-01-10T16:19:40.150Z"],"description":"Date and time the order was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"examples":["2025-01-10T16:30:07.172Z"],"description":"Date and time the order was last updated.","anyOf":[{"examples":["2025-01-10T16:30:07.172Z"],"description":"Date and time the order was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"examples":["2025-01-12T16:19:40.150Z"],"description":"Date and time of order expiration. If this time is reached and the order is not paid, it will be automatically canceled.","anyOf":[{"examples":["2025-01-12T16:19:40.150Z"],"description":"Date and time of order expiration. If this time is reached and the order is not paid, it will be automatically canceled.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"sale":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"customer":{"type":"object","required":["premium"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Customer phone number.","type":"string"},"firstName":{"examples":["Jan"],"description":"Customer first name.","type":"string"},"lastName":{"examples":["Barášek"],"description":"Customer last name.","type":"string"},"companyName":{"examples":["Company Ltd."],"description":"Name of the customer's company.","type":"string"},"premium":{"examples":[false],"description":"Indicator of whether the customer is premium.","type":"boolean"}}},"items":{"type":"array","items":{"type":"object","required":["id","isStorno","label","count","price","unit","creditAmount"],"properties":{"id":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S_4186"],"description":"Order item ID.","type":"string"},"isStorno":{"examples":[false],"description":"Indicator of whether the item is canceled.","type":"boolean"},"label":{"examples":["GymRoom reservation"],"description":"Order item description as HTML.","type":"string"},"count":{"examples":[1],"description":"Number of items.","type":"number"},"price":{"type":"object","required":["priceWithVat","currency","priceWithoutVat","vat","currencyLocale"],"properties":{"priceWithVat":{"examples":[0],"description":"Cena s DPH.","type":"number"},"currency":{"examples":["CZK","EUR","USD"],"description":"Currency code. **Format:** 3-letter uppercase code (e.g. `CZK`).\n**Supported values:** `CZK`, `EUR`, `USD`.","type":"string"},"priceWithoutVat":{"examples":[0],"description":"Cena bez DPH.","type":"number"},"vat":{"examples":[21],"description":"Výše DPH v procentech.","type":"number"},"currencyLocale":{"examples":["Kč"],"description":"Místní označení měny.","type":"string"}}},"unit":{"examples":["ks"],"description":"Item units.","type":"string"},"vat":{"type":"number"},"creditAmount":{"examples":[0],"description":"Credit value of the item.","type":"number"},"productCode":{"type":"string"},"productName":{"type":"string"},"productMainImageUrl":{"examples":["https://storage.xhp.cz/..."],"type":"string"},"variantCode":{"type":"string"},"variantName":{"type":"string"},"eventCalendarCode":{"type":"string"},"eventCode":{"type":"string"},"eventTitle":{"type":"string"},"branch":{"examples":["gymroom-plzen"],"description":"Slug of the branch (pobočka) this line item was attributed to.","type":"string"}}}},"vouchers":{"description":"Vouchers redeemed on this order. Their monetary effect (if any) is already reflected in `items` as a negative-priced row; this field is the canonical audit list of the codes themselves.","type":"array","items":{"type":"object","required":["code","type","value","isOrderSingleton","currency"],"properties":{"code":{"examples":["SUMMER-15"],"description":"Voucher code that was redeemed on the order.","type":"string"},"type":{"default":"fixed","description":"Voucher type. `fixed` / `percentage` discount the order total (visible as a negative line item); `free-credit` grants credits to the customer account; `free-product` grants a product line item.","type":"string","enum":["fixed","percentage","free-credit","free-product"]},"value":{"examples":["150","10","3000"],"description":"Type-dependent payload value. For `fixed` the discount amount in order currency, for `percentage` the percentage rate, for `free-credit` the credit amount.","type":"string"},"isOrderSingleton":{"examples":[false],"description":"Whether this voucher cannot be combined with other vouchers on the same order.","type":"boolean"},"currency":{"examples":["CZK"],"type":"string"}}}},"tags":{"type":"object","patternProperties":{"^(.*)$":{}}},"links":{"type":"object","properties":{"onlinePaymentLink":{"examples":["https://bizkithub.com/order/pay?hash=sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Link to online payment of the order.","type":"string"},"returnUrl":{"examples":["https://gymroom.cz/eshop/dekujeme-eshop"],"description":"URL to which the customer is redirected after successful payment.","type":"string"}}}}},{"type":"object","required":["exist"],"properties":{"exist":{"const":false,"type":"boolean"}}}]}}}}},"operationId":"getApiV1ShopOrderDetail","tags":["order"]}},"/api/v1/shop/order/create-payment":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"redirectUrl":{"type":"string"}},"required":["redirectUrl"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"redirectUrl":{"type":"string"}},"required":["redirectUrl"]}},"text/plain":{"schema":{"type":"object","properties":{"redirectUrl":{"type":"string"}},"required":["redirectUrl"]}}}}},"operationId":"postApiV1ShopOrderCreate-payment","tags":["order"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}}}}}},"/api/v1/shop/order/check-payment-status":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"redirectUrl":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"redirectUrl":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"redirectUrl":{"type":"string"}}}}}}},"operationId":"postApiV1ShopOrderCheck-payment-status","tags":["order"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"}}}}}}}},"/api/v1/shop/order/storno":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"examples":["Customer does not exist."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"examples":["Customer does not exist."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"examples":["Customer does not exist."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"examples":["Customer does not exist."],"type":"string"}}}]}}}}},"operationId":"postApiV1ShopOrderStorno","tags":["order"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderId"],"properties":{"orderId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"orderItemId":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S_4186"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderId"],"properties":{"orderId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"orderItemId":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S_4186"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderId"],"properties":{"orderId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"orderItemId":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S_4186"],"type":"string"}}}}}}}},"/api/v1/shop/order/set-status":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"examples":["Customer does not exist."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"examples":["Customer does not exist."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"examples":["Customer does not exist."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"examples":["Customer does not exist."],"type":"string"}}}]}}}}},"operationId":"postApiV1ShopOrderSet-status","tags":["order"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderId","statusCode"],"properties":{"orderId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"statusCode":{"examples":["paid"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderId","statusCode"],"properties":{"orderId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"statusCode":{"examples":["paid"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderId","statusCode"],"properties":{"orderId":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"statusCode":{"examples":["paid"],"type":"string"}}}}}}}},"/api/v1/shop/payment/create":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Unique order hash identifier.","examples":["a1b2c3d4e5f6"],"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"responses":{"200":{"description":"Payment gateway redirect URL.","content":{"application/json":{"schema":{"type":"object","properties":{"gatewayUrl":{"description":"URL to redirect the customer to the payment gateway. Undefined if payment could not be created.","examples":["https://payments.comgate.cz/client/instructions/index?id=ABC123"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"gatewayUrl":{"description":"URL to redirect the customer to the payment gateway. Undefined if payment could not be created.","examples":["https://payments.comgate.cz/client/instructions/index?id=ABC123"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"gatewayUrl":{"description":"URL to redirect the customer to the payment gateway. Undefined if payment could not be created.","examples":["https://payments.comgate.cz/client/instructions/index?id=ABC123"],"type":"string"}}}}}}},"operationId":"getApiV1ShopPaymentCreate","tags":["payment"],"summary":"Create payment gateway session","description":"Initializes a payment gateway session for the given order and returns a redirect URL where the customer completes the payment."}},"/api/v1/shop/payment/process-notification":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Payment gateway transaction ID.","examples":["TXN-123456"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Order hash identifier (same as used in /create).","examples":["a1b2c3d4e5f6"],"schema":{"type":"string"},"in":"query","name":"orderId","required":true}],"responses":{"200":{"description":"Payment status check result.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"description":"Payment status from the gateway.","examples":["PAID","PENDING","CANCELLED"],"type":"string"},"redirectUrl":{"description":"URL to redirect the customer after payment processing.","type":"string"}},"required":["status"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"status":{"description":"Payment status from the gateway.","examples":["PAID","PENDING","CANCELLED"],"type":"string"},"redirectUrl":{"description":"URL to redirect the customer after payment processing.","type":"string"}},"required":["status"]}},"text/plain":{"schema":{"type":"object","properties":{"status":{"description":"Payment status from the gateway.","examples":["PAID","PENDING","CANCELLED"],"type":"string"},"redirectUrl":{"description":"URL to redirect the customer after payment processing.","type":"string"}},"required":["status"]}}}}},"operationId":"getApiV1ShopPaymentProcess-notification","tags":["payment"],"summary":"Process payment notification","description":"Processes a payment gateway callback/notification. Checks the current payment status with the gateway and returns the result with an optional redirect URL."}},"/api/v1/shop/complaint/create":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Unique complaint external ID. Use this ID for subsequent operations (status changes, detail lookup).","type":"string"}},"required":["id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Unique complaint external ID. Use this ID for subsequent operations (status changes, detail lookup).","type":"string"}},"required":["id"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Unique complaint external ID. Use this ID for subsequent operations (status changes, detail lookup).","type":"string"}},"required":["id"]}}}}},"operationId":"postApiV1ShopComplaintCreate","tags":["complaint"],"description":"Create a new complaint case.\n\nUse this endpoint to file a complaint, return request, or exchange request from your system. The complaint is automatically created with status `new` and an initial event is recorded in the timeline.\n\n**Typical flow:**\n1. Create complaint via this endpoint\n2. Poll status via `GET /detail`\n3. Optionally update status via `POST /set-status`\n\n**Linking to orders:** Provide `orderHash` to link the complaint to an existing order. The system will validate that the order belongs to your organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["variantCode","description","customerName"],"properties":{"variantCode":{"examples":["reklamace","vraceni","vymena"],"description":"Organisation-defined complaint variant code.\n\nEach organisation configures its own set of complaint types (e.g. `reklamace`, `vraceni`, `vymena`). The variant must exist and be active in the organisation settings before it can be used.","type":"string"},"orderHash":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Hash of the order this complaint is related to. The order must belong to the same organisation. If provided, the system automatically links the complaint to the order.","type":"string"},"orderNumber":{"examples":["25000087"],"description":"Human-readable order number for reference.\n\nUse this field when the order is external or when you want to store the order number without linking to an internal order. If `orderHash` is provided, this field is optional and will be used as a display label only.","type":"string"},"description":{"examples":["Product arrived damaged, visible scratch on the surface."],"description":"Customer-provided description and reason for the complaint.\n\nInclude as much detail as possible — product condition, circumstances, and what the customer expects. This text is visible to staff and can be shared with the customer.","type":"string"},"customerName":{"examples":["Jan Novák"],"description":"Full name of the customer filing the complaint.","type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Customer e-mail address for complaint communication.\n\nUsed for sending status updates and resolution notifications to the customer.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Customer phone number in international format.\n\n**Preferred format:** `+<country_code> <local_number>`\n**Example:** `+420 777123456`","type":"string"},"price":{"examples":[1500],"description":"Total claimed amount in the specified currency.\n\nThe claimed amount represents the value the customer is requesting as refund, credit, or compensation. Use decimal precision up to two places.","type":"number"},"currency":{"examples":["CZK","EUR"],"description":"ISO 4217 currency code for the claimed amount. Defaults to organisation currency if omitted.","type":"string"},"refundCountry":{"examples":["CZ","SK"],"description":"ISO 3166-1 alpha-2 country code for the refund bank account.","type":"string"},"refundBankAccount":{"examples":["123456789/0100"],"description":"Bank account number for refund transfer.\n\nUse the local bank account format (e.g. `123456789/0100` for CZ) or IBAN.","type":"string"},"refundVariableSymbol":{"examples":["25000087"],"description":"Variable symbol for the refund bank transfer. Typically the original order number.","type":"string"},"branchId":{"description":"Branch ID where the product should be sent for inspection or return.","type":"number"},"resolutionMethodCode":{"examples":["repair","exchange","refund"],"description":"Preferred resolution method code defined by the organisation.\n\nCommon values: `repair` (fix the product), `exchange` (replace with new), `refund` (return money), `credit` (issue store credit). The method must exist in the organisation settings.","type":"string"},"dueDate":{"format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"description":"Deadline for complaint resolution. If omitted, the organisation default applies.","type":"string"},"items":{"description":"List of items being complained about.\n\nEach item can optionally reference an original order item by ID. If the complaint covers the entire order, you can omit this field and set the total claimed amount in the `price` field instead.","type":"array","items":{"type":"object","required":["label"],"properties":{"orderItemId":{"description":"Internal order item ID to link the complained item to the original order line.","type":"number"},"label":{"examples":["Wireless headphones Model X"],"description":"Item description as displayed in the complaint.","type":"string"},"quantity":{"examples":[1],"description":"Number of items being complained about. Defaults to 1.","type":"number"},"price":{"examples":[2490],"description":"Claimed unit price of the item in the complaint currency.","type":"number"}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["variantCode","description","customerName"],"properties":{"variantCode":{"examples":["reklamace","vraceni","vymena"],"description":"Organisation-defined complaint variant code.\n\nEach organisation configures its own set of complaint types (e.g. `reklamace`, `vraceni`, `vymena`). The variant must exist and be active in the organisation settings before it can be used.","type":"string"},"orderHash":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Hash of the order this complaint is related to. The order must belong to the same organisation. If provided, the system automatically links the complaint to the order.","type":"string"},"orderNumber":{"examples":["25000087"],"description":"Human-readable order number for reference.\n\nUse this field when the order is external or when you want to store the order number without linking to an internal order. If `orderHash` is provided, this field is optional and will be used as a display label only.","type":"string"},"description":{"examples":["Product arrived damaged, visible scratch on the surface."],"description":"Customer-provided description and reason for the complaint.\n\nInclude as much detail as possible — product condition, circumstances, and what the customer expects. This text is visible to staff and can be shared with the customer.","type":"string"},"customerName":{"examples":["Jan Novák"],"description":"Full name of the customer filing the complaint.","type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Customer e-mail address for complaint communication.\n\nUsed for sending status updates and resolution notifications to the customer.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Customer phone number in international format.\n\n**Preferred format:** `+<country_code> <local_number>`\n**Example:** `+420 777123456`","type":"string"},"price":{"examples":[1500],"description":"Total claimed amount in the specified currency.\n\nThe claimed amount represents the value the customer is requesting as refund, credit, or compensation. Use decimal precision up to two places.","type":"number"},"currency":{"examples":["CZK","EUR"],"description":"ISO 4217 currency code for the claimed amount. Defaults to organisation currency if omitted.","type":"string"},"refundCountry":{"examples":["CZ","SK"],"description":"ISO 3166-1 alpha-2 country code for the refund bank account.","type":"string"},"refundBankAccount":{"examples":["123456789/0100"],"description":"Bank account number for refund transfer.\n\nUse the local bank account format (e.g. `123456789/0100` for CZ) or IBAN.","type":"string"},"refundVariableSymbol":{"examples":["25000087"],"description":"Variable symbol for the refund bank transfer. Typically the original order number.","type":"string"},"branchId":{"description":"Branch ID where the product should be sent for inspection or return.","type":"number"},"resolutionMethodCode":{"examples":["repair","exchange","refund"],"description":"Preferred resolution method code defined by the organisation.\n\nCommon values: `repair` (fix the product), `exchange` (replace with new), `refund` (return money), `credit` (issue store credit). The method must exist in the organisation settings.","type":"string"},"dueDate":{"format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"description":"Deadline for complaint resolution. If omitted, the organisation default applies.","type":"string"},"items":{"description":"List of items being complained about.\n\nEach item can optionally reference an original order item by ID. If the complaint covers the entire order, you can omit this field and set the total claimed amount in the `price` field instead.","type":"array","items":{"type":"object","required":["label"],"properties":{"orderItemId":{"description":"Internal order item ID to link the complained item to the original order line.","type":"number"},"label":{"examples":["Wireless headphones Model X"],"description":"Item description as displayed in the complaint.","type":"string"},"quantity":{"examples":[1],"description":"Number of items being complained about. Defaults to 1.","type":"number"},"price":{"examples":[2490],"description":"Claimed unit price of the item in the complaint currency.","type":"number"}}}}}}},"text/plain":{"schema":{"type":"object","required":["variantCode","description","customerName"],"properties":{"variantCode":{"examples":["reklamace","vraceni","vymena"],"description":"Organisation-defined complaint variant code.\n\nEach organisation configures its own set of complaint types (e.g. `reklamace`, `vraceni`, `vymena`). The variant must exist and be active in the organisation settings before it can be used.","type":"string"},"orderHash":{"minLength":32,"maxLength":32,"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"description":"Hash of the order this complaint is related to. The order must belong to the same organisation. If provided, the system automatically links the complaint to the order.","type":"string"},"orderNumber":{"examples":["25000087"],"description":"Human-readable order number for reference.\n\nUse this field when the order is external or when you want to store the order number without linking to an internal order. If `orderHash` is provided, this field is optional and will be used as a display label only.","type":"string"},"description":{"examples":["Product arrived damaged, visible scratch on the surface."],"description":"Customer-provided description and reason for the complaint.\n\nInclude as much detail as possible — product condition, circumstances, and what the customer expects. This text is visible to staff and can be shared with the customer.","type":"string"},"customerName":{"examples":["Jan Novák"],"description":"Full name of the customer filing the complaint.","type":"string"},"email":{"examples":["jan@barasek.com"],"description":"Customer e-mail address for complaint communication.\n\nUsed for sending status updates and resolution notifications to the customer.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Customer phone number in international format.\n\n**Preferred format:** `+<country_code> <local_number>`\n**Example:** `+420 777123456`","type":"string"},"price":{"examples":[1500],"description":"Total claimed amount in the specified currency.\n\nThe claimed amount represents the value the customer is requesting as refund, credit, or compensation. Use decimal precision up to two places.","type":"number"},"currency":{"examples":["CZK","EUR"],"description":"ISO 4217 currency code for the claimed amount. Defaults to organisation currency if omitted.","type":"string"},"refundCountry":{"examples":["CZ","SK"],"description":"ISO 3166-1 alpha-2 country code for the refund bank account.","type":"string"},"refundBankAccount":{"examples":["123456789/0100"],"description":"Bank account number for refund transfer.\n\nUse the local bank account format (e.g. `123456789/0100` for CZ) or IBAN.","type":"string"},"refundVariableSymbol":{"examples":["25000087"],"description":"Variable symbol for the refund bank transfer. Typically the original order number.","type":"string"},"branchId":{"description":"Branch ID where the product should be sent for inspection or return.","type":"number"},"resolutionMethodCode":{"examples":["repair","exchange","refund"],"description":"Preferred resolution method code defined by the organisation.\n\nCommon values: `repair` (fix the product), `exchange` (replace with new), `refund` (return money), `credit` (issue store credit). The method must exist in the organisation settings.","type":"string"},"dueDate":{"format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"description":"Deadline for complaint resolution. If omitted, the organisation default applies.","type":"string"},"items":{"description":"List of items being complained about.\n\nEach item can optionally reference an original order item by ID. If the complaint covers the entire order, you can omit this field and set the total claimed amount in the `price` field instead.","type":"array","items":{"type":"object","required":["label"],"properties":{"orderItemId":{"description":"Internal order item ID to link the complained item to the original order line.","type":"number"},"label":{"examples":["Wireless headphones Model X"],"description":"Item description as displayed in the complaint.","type":"string"},"quantity":{"examples":[1],"description":"Number of items being complained about. Defaults to 1.","type":"number"},"price":{"examples":[2490],"description":"Claimed unit price of the item in the complaint currency.","type":"number"}}}}}}}}}}},"/api/v1/shop/complaint/detail":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Complaint external ID returned from the create endpoint.","examples":["a1b2c3d4e5f6g7h8"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["exist","id","variant","status","isResolved","description","customerName","insertedDate","updatedDate","items","events"],"properties":{"exist":{"description":"Indicator of whether the complaint exists.","const":true,"type":"boolean"},"id":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Complaint external ID.","type":"string"},"orderNumber":{"examples":["25000087"],"description":"Linked order number.","type":"string"},"variant":{"type":"object","required":["id","code","label"],"properties":{"id":{"description":"Variant ID.","type":"number"},"code":{"examples":["reklamace"],"description":"Variant code.","type":"string"},"label":{"examples":["Reklamace"],"description":"Variant display label.","type":"string"}}},"status":{"examples":["new","open","wait","resolve","reject","closed"],"description":"Current complaint status.","type":"string"},"isResolved":{"examples":[false],"description":"Indicator of whether the complaint has been resolved.","type":"boolean"},"description":{"description":"Complaint description provided by the customer.","type":"string"},"customerName":{"examples":["Jan Novák"],"description":"Customer full name.","type":"string"},"email":{"description":"Customer e-mail.","type":"string"},"phone":{"description":"Customer phone number.","type":"string"},"refund":{"type":"object","properties":{"country":{"description":"Refund country code.","type":"string"},"bankAccount":{"description":"Refund bank account.","type":"string"},"variableSymbol":{"description":"Refund variable symbol.","type":"string"}}},"satisfaction":{"type":"object","required":["score"],"properties":{"score":{"examples":[8],"description":"Satisfaction score 1–10.","type":"number"},"message":{"description":"Customer feedback message.","type":"string"}}},"insertedDate":{"description":"Date and time the complaint was created.","anyOf":[{"description":"Date and time the complaint was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date and time the complaint was last updated.","anyOf":[{"description":"Date and time the complaint was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"dueDate":{"description":"Deadline for complaint resolution.","anyOf":[{"description":"Deadline for complaint resolution.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"resolvedDate":{"description":"Date and time the complaint was resolved.","anyOf":[{"description":"Date and time the complaint was resolved.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"items":{"type":"array","items":{"type":"object","required":["id","label","quantity"],"properties":{"id":{"description":"Complaint item ID.","type":"number"},"label":{"description":"Item description.","type":"string"},"quantity":{"description":"Item quantity.","type":"number"},"price":{"description":"Claimed item price.","type":"number"}}}},"events":{"description":"Complaint timeline — status changes, internal notes, and customer-facing messages.","type":"array","items":{"type":"object","required":["id","shareWithCustomer","insertedDate"],"properties":{"id":{"description":"Event ID.","type":"number"},"status":{"description":"Status at the time of this event.","type":"string"},"shareWithCustomer":{"description":"Indicator of whether this event is visible to the customer.","type":"boolean"},"subject":{"description":"Event subject.","type":"string"},"message":{"description":"Event message body.","type":"string"},"insertedDate":{"description":"Date and time the event was created.","anyOf":[{"description":"Date and time the event was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}}},{"type":"object","required":["exist"],"properties":{"exist":{"description":"Complaint does not exist or does not belong to this organisation.","const":false,"type":"boolean"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["exist","id","variant","status","isResolved","description","customerName","insertedDate","updatedDate","items","events"],"properties":{"exist":{"description":"Indicator of whether the complaint exists.","const":true,"type":"boolean"},"id":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Complaint external ID.","type":"string"},"orderNumber":{"examples":["25000087"],"description":"Linked order number.","type":"string"},"variant":{"type":"object","required":["id","code","label"],"properties":{"id":{"description":"Variant ID.","type":"number"},"code":{"examples":["reklamace"],"description":"Variant code.","type":"string"},"label":{"examples":["Reklamace"],"description":"Variant display label.","type":"string"}}},"status":{"examples":["new","open","wait","resolve","reject","closed"],"description":"Current complaint status.","type":"string"},"isResolved":{"examples":[false],"description":"Indicator of whether the complaint has been resolved.","type":"boolean"},"description":{"description":"Complaint description provided by the customer.","type":"string"},"customerName":{"examples":["Jan Novák"],"description":"Customer full name.","type":"string"},"email":{"description":"Customer e-mail.","type":"string"},"phone":{"description":"Customer phone number.","type":"string"},"refund":{"type":"object","properties":{"country":{"description":"Refund country code.","type":"string"},"bankAccount":{"description":"Refund bank account.","type":"string"},"variableSymbol":{"description":"Refund variable symbol.","type":"string"}}},"satisfaction":{"type":"object","required":["score"],"properties":{"score":{"examples":[8],"description":"Satisfaction score 1–10.","type":"number"},"message":{"description":"Customer feedback message.","type":"string"}}},"insertedDate":{"description":"Date and time the complaint was created.","anyOf":[{"description":"Date and time the complaint was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date and time the complaint was last updated.","anyOf":[{"description":"Date and time the complaint was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"dueDate":{"description":"Deadline for complaint resolution.","anyOf":[{"description":"Deadline for complaint resolution.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"resolvedDate":{"description":"Date and time the complaint was resolved.","anyOf":[{"description":"Date and time the complaint was resolved.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"items":{"type":"array","items":{"type":"object","required":["id","label","quantity"],"properties":{"id":{"description":"Complaint item ID.","type":"number"},"label":{"description":"Item description.","type":"string"},"quantity":{"description":"Item quantity.","type":"number"},"price":{"description":"Claimed item price.","type":"number"}}}},"events":{"description":"Complaint timeline — status changes, internal notes, and customer-facing messages.","type":"array","items":{"type":"object","required":["id","shareWithCustomer","insertedDate"],"properties":{"id":{"description":"Event ID.","type":"number"},"status":{"description":"Status at the time of this event.","type":"string"},"shareWithCustomer":{"description":"Indicator of whether this event is visible to the customer.","type":"boolean"},"subject":{"description":"Event subject.","type":"string"},"message":{"description":"Event message body.","type":"string"},"insertedDate":{"description":"Date and time the event was created.","anyOf":[{"description":"Date and time the event was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}}},{"type":"object","required":["exist"],"properties":{"exist":{"description":"Complaint does not exist or does not belong to this organisation.","const":false,"type":"boolean"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["exist","id","variant","status","isResolved","description","customerName","insertedDate","updatedDate","items","events"],"properties":{"exist":{"description":"Indicator of whether the complaint exists.","const":true,"type":"boolean"},"id":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Complaint external ID.","type":"string"},"orderNumber":{"examples":["25000087"],"description":"Linked order number.","type":"string"},"variant":{"type":"object","required":["id","code","label"],"properties":{"id":{"description":"Variant ID.","type":"number"},"code":{"examples":["reklamace"],"description":"Variant code.","type":"string"},"label":{"examples":["Reklamace"],"description":"Variant display label.","type":"string"}}},"status":{"examples":["new","open","wait","resolve","reject","closed"],"description":"Current complaint status.","type":"string"},"isResolved":{"examples":[false],"description":"Indicator of whether the complaint has been resolved.","type":"boolean"},"description":{"description":"Complaint description provided by the customer.","type":"string"},"customerName":{"examples":["Jan Novák"],"description":"Customer full name.","type":"string"},"email":{"description":"Customer e-mail.","type":"string"},"phone":{"description":"Customer phone number.","type":"string"},"refund":{"type":"object","properties":{"country":{"description":"Refund country code.","type":"string"},"bankAccount":{"description":"Refund bank account.","type":"string"},"variableSymbol":{"description":"Refund variable symbol.","type":"string"}}},"satisfaction":{"type":"object","required":["score"],"properties":{"score":{"examples":[8],"description":"Satisfaction score 1–10.","type":"number"},"message":{"description":"Customer feedback message.","type":"string"}}},"insertedDate":{"description":"Date and time the complaint was created.","anyOf":[{"description":"Date and time the complaint was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date and time the complaint was last updated.","anyOf":[{"description":"Date and time the complaint was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"dueDate":{"description":"Deadline for complaint resolution.","anyOf":[{"description":"Deadline for complaint resolution.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"resolvedDate":{"description":"Date and time the complaint was resolved.","anyOf":[{"description":"Date and time the complaint was resolved.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"items":{"type":"array","items":{"type":"object","required":["id","label","quantity"],"properties":{"id":{"description":"Complaint item ID.","type":"number"},"label":{"description":"Item description.","type":"string"},"quantity":{"description":"Item quantity.","type":"number"},"price":{"description":"Claimed item price.","type":"number"}}}},"events":{"description":"Complaint timeline — status changes, internal notes, and customer-facing messages.","type":"array","items":{"type":"object","required":["id","shareWithCustomer","insertedDate"],"properties":{"id":{"description":"Event ID.","type":"number"},"status":{"description":"Status at the time of this event.","type":"string"},"shareWithCustomer":{"description":"Indicator of whether this event is visible to the customer.","type":"boolean"},"subject":{"description":"Event subject.","type":"string"},"message":{"description":"Event message body.","type":"string"},"insertedDate":{"description":"Date and time the event was created.","anyOf":[{"description":"Date and time the event was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}}},{"type":"object","required":["exist"],"properties":{"exist":{"description":"Complaint does not exist or does not belong to this organisation.","const":false,"type":"boolean"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["exist","id","variant","status","isResolved","description","customerName","insertedDate","updatedDate","items","events"],"properties":{"exist":{"description":"Indicator of whether the complaint exists.","const":true,"type":"boolean"},"id":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Complaint external ID.","type":"string"},"orderNumber":{"examples":["25000087"],"description":"Linked order number.","type":"string"},"variant":{"type":"object","required":["id","code","label"],"properties":{"id":{"description":"Variant ID.","type":"number"},"code":{"examples":["reklamace"],"description":"Variant code.","type":"string"},"label":{"examples":["Reklamace"],"description":"Variant display label.","type":"string"}}},"status":{"examples":["new","open","wait","resolve","reject","closed"],"description":"Current complaint status.","type":"string"},"isResolved":{"examples":[false],"description":"Indicator of whether the complaint has been resolved.","type":"boolean"},"description":{"description":"Complaint description provided by the customer.","type":"string"},"customerName":{"examples":["Jan Novák"],"description":"Customer full name.","type":"string"},"email":{"description":"Customer e-mail.","type":"string"},"phone":{"description":"Customer phone number.","type":"string"},"refund":{"type":"object","properties":{"country":{"description":"Refund country code.","type":"string"},"bankAccount":{"description":"Refund bank account.","type":"string"},"variableSymbol":{"description":"Refund variable symbol.","type":"string"}}},"satisfaction":{"type":"object","required":["score"],"properties":{"score":{"examples":[8],"description":"Satisfaction score 1–10.","type":"number"},"message":{"description":"Customer feedback message.","type":"string"}}},"insertedDate":{"description":"Date and time the complaint was created.","anyOf":[{"description":"Date and time the complaint was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date and time the complaint was last updated.","anyOf":[{"description":"Date and time the complaint was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"dueDate":{"description":"Deadline for complaint resolution.","anyOf":[{"description":"Deadline for complaint resolution.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"resolvedDate":{"description":"Date and time the complaint was resolved.","anyOf":[{"description":"Date and time the complaint was resolved.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"items":{"type":"array","items":{"type":"object","required":["id","label","quantity"],"properties":{"id":{"description":"Complaint item ID.","type":"number"},"label":{"description":"Item description.","type":"string"},"quantity":{"description":"Item quantity.","type":"number"},"price":{"description":"Claimed item price.","type":"number"}}}},"events":{"description":"Complaint timeline — status changes, internal notes, and customer-facing messages.","type":"array","items":{"type":"object","required":["id","shareWithCustomer","insertedDate"],"properties":{"id":{"description":"Event ID.","type":"number"},"status":{"description":"Status at the time of this event.","type":"string"},"shareWithCustomer":{"description":"Indicator of whether this event is visible to the customer.","type":"boolean"},"subject":{"description":"Event subject.","type":"string"},"message":{"description":"Event message body.","type":"string"},"insertedDate":{"description":"Date and time the event was created.","anyOf":[{"description":"Date and time the event was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}}},{"type":"object","required":["exist"],"properties":{"exist":{"description":"Complaint does not exist or does not belong to this organisation.","const":false,"type":"boolean"}}}]}}}}},"operationId":"getApiV1ShopComplaintDetail","tags":["complaint"],"description":"Returns full complaint detail including items, events timeline, refund information, and satisfaction feedback.\n\nUse this endpoint to check the current status and history of a complaint. The `events` array contains the full timeline of status changes and messages."}},"/api/v1/shop/complaint/set-status":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1ShopComplaintSet-status","tags":["complaint"],"description":"Changes the complaint status.\n\nEach status transition is recorded in the complaint event timeline. Terminal statuses (`resolve`, `reject`, `closed`) mark the complaint as resolved.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["complaintId","status"],"properties":{"complaintId":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Complaint external ID to update.","type":"string"},"status":{"examples":["new","open","wait","resolve","reject","closed"],"description":"New complaint status.\n\n**Available statuses:**\n- `new` — Complaint has been filed, not yet reviewed\n- `open` — Complaint is being processed by staff\n- `wait` — Waiting for customer response or external input\n- `resolve` — Complaint has been resolved in favour of the customer\n- `reject` — Complaint has been rejected\n- `closed` — Complaint is closed (final state)\n\nSetting status to `resolve` or `closed` automatically marks the complaint as resolved and sets the `resolvedDate`.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["complaintId","status"],"properties":{"complaintId":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Complaint external ID to update.","type":"string"},"status":{"examples":["new","open","wait","resolve","reject","closed"],"description":"New complaint status.\n\n**Available statuses:**\n- `new` — Complaint has been filed, not yet reviewed\n- `open` — Complaint is being processed by staff\n- `wait` — Waiting for customer response or external input\n- `resolve` — Complaint has been resolved in favour of the customer\n- `reject` — Complaint has been rejected\n- `closed` — Complaint is closed (final state)\n\nSetting status to `resolve` or `closed` automatically marks the complaint as resolved and sets the `resolvedDate`.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["complaintId","status"],"properties":{"complaintId":{"examples":["a1b2c3d4e5f6g7h8"],"description":"Complaint external ID to update.","type":"string"},"status":{"examples":["new","open","wait","resolve","reject","closed"],"description":"New complaint status.\n\n**Available statuses:**\n- `new` — Complaint has been filed, not yet reviewed\n- `open` — Complaint is being processed by staff\n- `wait` — Waiting for customer response or external input\n- `resolve` — Complaint has been resolved in favour of the customer\n- `reject` — Complaint has been rejected\n- `closed` — Complaint is closed (final state)\n\nSetting status to `resolve` or `closed` automatically marks the complaint as resolved and sets the `resolvedDate`.","type":"string"}}}}}}}},"/api/v1/subscription/active-list":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"schema":{"type":"string"},"in":"query","name":"identityId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["runningSubscriptionList"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["runningSubscriptionList"]}},"text/plain":{"schema":{"type":"object","properties":{"runningSubscriptionList":{"type":"array","items":{"type":"object","required":["externalId","productSlug","productCode","orderNumber","orderHash","autoRenew","renewalDate"],"properties":{"externalId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"},"productSlug":{"examples":["predplatne-rocni"],"type":"string"},"productCode":{"examples":["predplatne-rocni"],"type":"string"},"orderNumber":{"examples":["25000001"],"type":"string"},"orderHash":{"examples":["CuS08iXV3cOwweQsQB3TwYXtDr67K4kW"],"type":"string"},"autoRenew":{"examples":[true],"type":"boolean"},"renewalDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"activeToDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastSuccessPaymentDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["runningSubscriptionList"]}}}}},"operationId":"getApiV1SubscriptionActive-list","tags":["subscription"]}},"/api/v1/subscription/cancel":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1SubscriptionCancel","tags":["subscription"],"summary":"Cancel subscription auto-renew","description":"Disables auto-renew for a customer subscription. Does NOT end access immediately: subscription stays active until `activeToDate`, but will not renew on `renewalDate` (sets `autoRenew=false`). Throws if subscription is not owned by the customer.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identityId","subscriptionId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"subscriptionId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["identityId","subscriptionId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"subscriptionId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["identityId","subscriptionId"],"properties":{"identityId":{"examples":["Z9CPkS2o3UV163VQn5OUv0T8BQi8Fvdg"],"description":"Logged user identity (from your frontend cookies). [Learn more](https://docs.bizkithub.com/identity-id)","type":"string"},"subscriptionId":{"examples":["d9DfQL3ZF01t7Ykk"],"type":"string"}}}}}}}},"/api/v1/support/contact-form":{"post":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1SupportContact-form","tags":["support"],"summary":"Submit contact form","description":"Creates a support ticket from a contact form submission. Includes anti-spam geolocation check. Optionally registers the customer as a contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"examples":["Hello, how are you?"],"description":"Message body from the customer.","type":"string"},"subject":{"examples":["Request from Jan"],"description":"Subject line for the support ticket.","type":"string"},"notice":{"examples":["Internal notice"],"description":"Internal note (not visible to customer).","type":"string"},"sendToEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"categorySlug":{"examples":["offer"],"description":"Category slug for routing the ticket.","type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"customerPhone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"customerFirstName":{"examples":["Jan"],"type":"string"},"customerLastName":{"examples":["Barášek"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["message"],"properties":{"message":{"examples":["Hello, how are you?"],"description":"Message body from the customer.","type":"string"},"subject":{"examples":["Request from Jan"],"description":"Subject line for the support ticket.","type":"string"},"notice":{"examples":["Internal notice"],"description":"Internal note (not visible to customer).","type":"string"},"sendToEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"categorySlug":{"examples":["offer"],"description":"Category slug for routing the ticket.","type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"customerPhone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"customerFirstName":{"examples":["Jan"],"type":"string"},"customerLastName":{"examples":["Barášek"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["message"],"properties":{"message":{"examples":["Hello, how are you?"],"description":"Message body from the customer.","type":"string"},"subject":{"examples":["Request from Jan"],"description":"Subject line for the support ticket.","type":"string"},"notice":{"examples":["Internal notice"],"description":"Internal note (not visible to customer).","type":"string"},"sendToEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"categorySlug":{"examples":["offer"],"description":"Category slug for routing the ticket.","type":"string"},"customerEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"customerPhone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"customerFirstName":{"examples":["Jan"],"type":"string"},"customerLastName":{"examples":["Barášek"],"type":"string"}}}}}}}},"/api/v1/tracking/email-pixel":{"get":{"parameters":[{"description":"External generated message ID, for example `v2.mail::p0xvq-1736628881328-n92ql8.gymroom`.\n\nSupported prefixes:\n\n- `v1` bulk newsletter e-mail message\n- `v2` individual e-mail message","schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"anyOf":[{"default":[1,2,3]},{"type":"Uint8Array"}],"content":{"application/json":{"schema":{"anyOf":[{"default":[1,2,3]},{"type":"Uint8Array"}]}},"multipart/form-data":{"schema":{"anyOf":[{"default":[1,2,3]},{"type":"Uint8Array"}]}},"text/plain":{"schema":{"anyOf":[{"default":[1,2,3]},{"type":"Uint8Array"}]}}}}},"operationId":"getApiV1TrackingEmail-pixel","tags":["tracking"],"description":"Render and return tracking pixel inside e-mail message."}},"/api/v1/tracking/log":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiV1TrackingLog","tags":["tracking"],"description":"Sentry-like logging endpoint for centralized log ingestion.\n\nAccepts log events from frontends (React/Next.js), backend services, workers and third-party systems. Each request creates a single log entry bound to the organisation, classified by severity and optionally eligible for notifications.\n\nDebouncing can be enabled to group repeated/noisy events. `useDebounce` supports a simple boolean or an advanced configuration with a custom key and a relative time window (`maxInterval`, e.g. `10m`, `1h 30m`, or minutes).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"description":"Log message payload. Intended for system/application logs coming from external services/websites. Keep it human-readable or JSON; include essential context (e.g., module, action, identifiers) to make triage easier. For structured data, serialize into the message or extend the endpoint to accept extra fields.","examples":["[checkout] Payment callback failed: missing transId (orderId=25000233)","Unhandled exception in worker: TypeError: Cannot read properties of undefined (jobId=abcd1234)"],"type":"string"},"level":{"enum":["info","success","error","warning","critical"],"description":"Severity level of the log entry. Used for filtering, alerting and retention rules.\n\n- `info` = diagnostic signal\n- `success` = positive milestone\n- `warning` = potential issue\n- `error` = failure that impacted a request/job\n- `critical` = high priority incident requiring immediate attention.\n\nIf omitted, the backend should treat it as a default level (commonly `info`).","examples":["error","warning"],"type":"string"},"sendNotification":{"description":"When `true`, the log entry is eligible to trigger notifications (e.g., email/Slack/push) according to organisation settings. Use sparingly for actionable events (typically `error`/`critical`). If omitted, the system decides based on `level` and notification rules.","examples":[true,false],"type":"boolean"},"useDebounce":{"anyOf":[{"description":"Advanced debounce configuration. `maxInterval` defines maximum grouping window for duplicates (if omitted, backend uses a default interval).","type":"object","required":["enabled","maxInterval"],"properties":{"enabled":{"description":"Enable/disable debouncing for this event. If omitted, the backend treats it as enabled.","examples":[true],"type":"boolean"},"key":{"description":"Optional custom debounce key. When provided, logs sharing the same key will be grouped together (useful for dynamic messages).","examples":["stripe-webhook-timeout","db-connection-failed"],"type":"string"},"maxInterval":{"anyOf":[{"examples":["3w 4d 12h","10m","0.5h","2.5","3,1"],"description":"Relative time interval expressed as a string.\n\nSupported units and conversion (`REAL_TIME_CHAR_TO_MINUTES`):\n\n| Unit | Name   | Minutes | Notes |\n|------|--------|---------|-------|\n| `m`  | minute | `1`     | |\n| `h`  | hour   | `60`    | |\n| `d`  | day    | `1440`  | 24h |\n| `w`  | week   | `10080` | 7d |\n| `y`  | year   | `525600`| 365d |\n\nRules:\n- Units are case-insensitive and can be combined: `3w 4d 12h`.\n- Decimal values are allowed: `0.5h`, `2.5d`.\n- Spaces and unit variants are tolerated: `10m`, `10 min`, `10 minutes`.\n- Numeric value without a unit is interpreted as **hours**.\n\nRounding:\n- Result is returned in minutes and rounded **up** (`Math.ceil`).\n\nInvalid or empty input returns `0`.","type":"string"},{"examples":[30,60,150,1440],"description":"Relative time interval expressed as a number of minutes.\n\nRules:\n- Value is taken directly as minutes (e.g. `30` = 30 minutes).\n- No unit parsing or conversion is applied.","type":"number"}]}}},{"description":"Simple debounce toggle. When `true`, repeated logs may be deduplicated/grouped within a backend-defined window. When `false`, debouncing is disabled and every event is stored.","examples":[true,false],"type":"boolean"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["message"],"properties":{"message":{"description":"Log message payload. Intended for system/application logs coming from external services/websites. Keep it human-readable or JSON; include essential context (e.g., module, action, identifiers) to make triage easier. For structured data, serialize into the message or extend the endpoint to accept extra fields.","examples":["[checkout] Payment callback failed: missing transId (orderId=25000233)","Unhandled exception in worker: TypeError: Cannot read properties of undefined (jobId=abcd1234)"],"type":"string"},"level":{"enum":["info","success","error","warning","critical"],"description":"Severity level of the log entry. Used for filtering, alerting and retention rules.\n\n- `info` = diagnostic signal\n- `success` = positive milestone\n- `warning` = potential issue\n- `error` = failure that impacted a request/job\n- `critical` = high priority incident requiring immediate attention.\n\nIf omitted, the backend should treat it as a default level (commonly `info`).","examples":["error","warning"],"type":"string"},"sendNotification":{"description":"When `true`, the log entry is eligible to trigger notifications (e.g., email/Slack/push) according to organisation settings. Use sparingly for actionable events (typically `error`/`critical`). If omitted, the system decides based on `level` and notification rules.","examples":[true,false],"type":"boolean"},"useDebounce":{"anyOf":[{"description":"Advanced debounce configuration. `maxInterval` defines maximum grouping window for duplicates (if omitted, backend uses a default interval).","type":"object","required":["enabled","maxInterval"],"properties":{"enabled":{"description":"Enable/disable debouncing for this event. If omitted, the backend treats it as enabled.","examples":[true],"type":"boolean"},"key":{"description":"Optional custom debounce key. When provided, logs sharing the same key will be grouped together (useful for dynamic messages).","examples":["stripe-webhook-timeout","db-connection-failed"],"type":"string"},"maxInterval":{"anyOf":[{"examples":["3w 4d 12h","10m","0.5h","2.5","3,1"],"description":"Relative time interval expressed as a string.\n\nSupported units and conversion (`REAL_TIME_CHAR_TO_MINUTES`):\n\n| Unit | Name   | Minutes | Notes |\n|------|--------|---------|-------|\n| `m`  | minute | `1`     | |\n| `h`  | hour   | `60`    | |\n| `d`  | day    | `1440`  | 24h |\n| `w`  | week   | `10080` | 7d |\n| `y`  | year   | `525600`| 365d |\n\nRules:\n- Units are case-insensitive and can be combined: `3w 4d 12h`.\n- Decimal values are allowed: `0.5h`, `2.5d`.\n- Spaces and unit variants are tolerated: `10m`, `10 min`, `10 minutes`.\n- Numeric value without a unit is interpreted as **hours**.\n\nRounding:\n- Result is returned in minutes and rounded **up** (`Math.ceil`).\n\nInvalid or empty input returns `0`.","type":"string"},{"examples":[30,60,150,1440],"description":"Relative time interval expressed as a number of minutes.\n\nRules:\n- Value is taken directly as minutes (e.g. `30` = 30 minutes).\n- No unit parsing or conversion is applied.","type":"number"}]}}},{"description":"Simple debounce toggle. When `true`, repeated logs may be deduplicated/grouped within a backend-defined window. When `false`, debouncing is disabled and every event is stored.","examples":[true,false],"type":"boolean"}]}}}},"text/plain":{"schema":{"type":"object","required":["message"],"properties":{"message":{"description":"Log message payload. Intended for system/application logs coming from external services/websites. Keep it human-readable or JSON; include essential context (e.g., module, action, identifiers) to make triage easier. For structured data, serialize into the message or extend the endpoint to accept extra fields.","examples":["[checkout] Payment callback failed: missing transId (orderId=25000233)","Unhandled exception in worker: TypeError: Cannot read properties of undefined (jobId=abcd1234)"],"type":"string"},"level":{"enum":["info","success","error","warning","critical"],"description":"Severity level of the log entry. Used for filtering, alerting and retention rules.\n\n- `info` = diagnostic signal\n- `success` = positive milestone\n- `warning` = potential issue\n- `error` = failure that impacted a request/job\n- `critical` = high priority incident requiring immediate attention.\n\nIf omitted, the backend should treat it as a default level (commonly `info`).","examples":["error","warning"],"type":"string"},"sendNotification":{"description":"When `true`, the log entry is eligible to trigger notifications (e.g., email/Slack/push) according to organisation settings. Use sparingly for actionable events (typically `error`/`critical`). If omitted, the system decides based on `level` and notification rules.","examples":[true,false],"type":"boolean"},"useDebounce":{"anyOf":[{"description":"Advanced debounce configuration. `maxInterval` defines maximum grouping window for duplicates (if omitted, backend uses a default interval).","type":"object","required":["enabled","maxInterval"],"properties":{"enabled":{"description":"Enable/disable debouncing for this event. If omitted, the backend treats it as enabled.","examples":[true],"type":"boolean"},"key":{"description":"Optional custom debounce key. When provided, logs sharing the same key will be grouped together (useful for dynamic messages).","examples":["stripe-webhook-timeout","db-connection-failed"],"type":"string"},"maxInterval":{"anyOf":[{"examples":["3w 4d 12h","10m","0.5h","2.5","3,1"],"description":"Relative time interval expressed as a string.\n\nSupported units and conversion (`REAL_TIME_CHAR_TO_MINUTES`):\n\n| Unit | Name   | Minutes | Notes |\n|------|--------|---------|-------|\n| `m`  | minute | `1`     | |\n| `h`  | hour   | `60`    | |\n| `d`  | day    | `1440`  | 24h |\n| `w`  | week   | `10080` | 7d |\n| `y`  | year   | `525600`| 365d |\n\nRules:\n- Units are case-insensitive and can be combined: `3w 4d 12h`.\n- Decimal values are allowed: `0.5h`, `2.5d`.\n- Spaces and unit variants are tolerated: `10m`, `10 min`, `10 minutes`.\n- Numeric value without a unit is interpreted as **hours**.\n\nRounding:\n- Result is returned in minutes and rounded **up** (`Math.ceil`).\n\nInvalid or empty input returns `0`.","type":"string"},{"examples":[30,60,150,1440],"description":"Relative time interval expressed as a number of minutes.\n\nRules:\n- Value is taken directly as minutes (e.g. `30` = 30 minutes).\n- No unit parsing or conversion is applied.","type":"number"}]}}},{"description":"Simple debounce toggle. When `true`, repeated logs may be deduplicated/grouped within a backend-defined window. When `false`, debouncing is disabled and every event is stored.","examples":[true,false],"type":"boolean"}]}}}}}}}},"/api/v1/vikitron/dns-records-checker":{"get":{"parameters":[{"description":"Domain name to check.","examples":["example.com"],"schema":{"type":"string"},"in":"query","name":"domain","required":true}],"responses":{"200":{"description":"DNS records for the domain.","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"description":"List of DNS records.","type":"array","items":{"type":"object","required":["name","type","value","createdAt","updatedAt","active"],"properties":{"name":{"description":"DNS record name (hostname).","examples":["example.com"],"type":"string"},"type":{"description":"DNS record type.","examples":["A","AAAA","MX","CNAME","TXT"],"type":"string"},"value":{"description":"DNS record value.","type":"string"},"hostname":{"description":"Resolved hostname.","type":"string"},"priority":{"description":"Record priority (relevant for MX records).","type":"number"},"ttl":{"description":"Time-to-live in seconds.","type":"number"},"createdAt":{"description":"When the record was first seen.","anyOf":[{"description":"When the record was first seen.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedAt":{"description":"When the record was last refreshed.","anyOf":[{"description":"When the record was last refreshed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the record is currently active.","type":"boolean"}}}}},"required":["records"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"records":{"description":"List of DNS records.","type":"array","items":{"type":"object","required":["name","type","value","createdAt","updatedAt","active"],"properties":{"name":{"description":"DNS record name (hostname).","examples":["example.com"],"type":"string"},"type":{"description":"DNS record type.","examples":["A","AAAA","MX","CNAME","TXT"],"type":"string"},"value":{"description":"DNS record value.","type":"string"},"hostname":{"description":"Resolved hostname.","type":"string"},"priority":{"description":"Record priority (relevant for MX records).","type":"number"},"ttl":{"description":"Time-to-live in seconds.","type":"number"},"createdAt":{"description":"When the record was first seen.","anyOf":[{"description":"When the record was first seen.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedAt":{"description":"When the record was last refreshed.","anyOf":[{"description":"When the record was last refreshed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the record is currently active.","type":"boolean"}}}}},"required":["records"]}},"text/plain":{"schema":{"type":"object","properties":{"records":{"description":"List of DNS records.","type":"array","items":{"type":"object","required":["name","type","value","createdAt","updatedAt","active"],"properties":{"name":{"description":"DNS record name (hostname).","examples":["example.com"],"type":"string"},"type":{"description":"DNS record type.","examples":["A","AAAA","MX","CNAME","TXT"],"type":"string"},"value":{"description":"DNS record value.","type":"string"},"hostname":{"description":"Resolved hostname.","type":"string"},"priority":{"description":"Record priority (relevant for MX records).","type":"number"},"ttl":{"description":"Time-to-live in seconds.","type":"number"},"createdAt":{"description":"When the record was first seen.","anyOf":[{"description":"When the record was first seen.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedAt":{"description":"When the record was last refreshed.","anyOf":[{"description":"When the record was last refreshed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the record is currently active.","type":"boolean"}}}}},"required":["records"]}}}}},"operationId":"getApiV1VikitronDns-records-checker","tags":["vikitron"],"summary":"Check DNS records for a domain","description":"Fetches and returns current DNS records for the given domain. Triggers a fresh DNS lookup before returning results."}},"/api/v1/vikitron/dns-explorer":{"get":{"parameters":[{"description":"Search query to find DNS records across all indexed domains.","examples":["mx google"],"schema":{"type":"string"},"in":"query","name":"query","required":true}],"responses":{"200":{"description":"Search results.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Matching DNS records.","type":"array","items":{"type":"object","required":["name","type","value","createdAt","updatedAt","active"],"properties":{"name":{"description":"DNS record name (hostname).","examples":["example.com"],"type":"string"},"type":{"description":"DNS record type.","examples":["A","AAAA","MX","CNAME","TXT"],"type":"string"},"value":{"description":"DNS record value.","type":"string"},"hostname":{"description":"Resolved hostname.","type":"string"},"priority":{"description":"Record priority (relevant for MX records).","type":"number"},"ttl":{"description":"Time-to-live in seconds.","type":"number"},"createdAt":{"description":"When the record was first seen.","anyOf":[{"description":"When the record was first seen.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedAt":{"description":"When the record was last refreshed.","anyOf":[{"description":"When the record was last refreshed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the record is currently active.","type":"boolean"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Matching DNS records.","type":"array","items":{"type":"object","required":["name","type","value","createdAt","updatedAt","active"],"properties":{"name":{"description":"DNS record name (hostname).","examples":["example.com"],"type":"string"},"type":{"description":"DNS record type.","examples":["A","AAAA","MX","CNAME","TXT"],"type":"string"},"value":{"description":"DNS record value.","type":"string"},"hostname":{"description":"Resolved hostname.","type":"string"},"priority":{"description":"Record priority (relevant for MX records).","type":"number"},"ttl":{"description":"Time-to-live in seconds.","type":"number"},"createdAt":{"description":"When the record was first seen.","anyOf":[{"description":"When the record was first seen.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedAt":{"description":"When the record was last refreshed.","anyOf":[{"description":"When the record was last refreshed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the record is currently active.","type":"boolean"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Matching DNS records.","type":"array","items":{"type":"object","required":["name","type","value","createdAt","updatedAt","active"],"properties":{"name":{"description":"DNS record name (hostname).","examples":["example.com"],"type":"string"},"type":{"description":"DNS record type.","examples":["A","AAAA","MX","CNAME","TXT"],"type":"string"},"value":{"description":"DNS record value.","type":"string"},"hostname":{"description":"Resolved hostname.","type":"string"},"priority":{"description":"Record priority (relevant for MX records).","type":"number"},"ttl":{"description":"Time-to-live in seconds.","type":"number"},"createdAt":{"description":"When the record was first seen.","anyOf":[{"description":"When the record was first seen.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedAt":{"description":"When the record was last refreshed.","anyOf":[{"description":"When the record was last refreshed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the record is currently active.","type":"boolean"}}}}},"required":["items"]}}}}},"operationId":"getApiV1VikitronDns-explorer","tags":["vikitron"],"summary":"Search DNS records","description":"Full-text search across all indexed DNS records. Useful for finding domains with specific record values."}},"/api/v1/vikitron/robots-txt-checker":{"get":{"parameters":[{"description":"Domain name to check.","examples":["example.com"],"schema":{"type":"string"},"in":"query","name":"domain","required":true}],"responses":{"200":{"description":"Robots.txt version history.","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"description":"Version history of robots.txt snapshots (newest first).","type":"array","items":{"type":"object","required":["id","content","httpCode","firstSeen","updatedDate"],"properties":{"id":{"description":"Hashed version identifier.","type":"string"},"content":{"description":"Raw robots.txt content.","type":"string"},"httpCode":{"description":"HTTP status code when fetching robots.txt.","examples":[200,404],"type":"number"},"firstSeen":{"description":"When this version was first observed.","anyOf":[{"description":"When this version was first observed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"When this version was last confirmed.","anyOf":[{"description":"When this version was last confirmed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["records"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"records":{"description":"Version history of robots.txt snapshots (newest first).","type":"array","items":{"type":"object","required":["id","content","httpCode","firstSeen","updatedDate"],"properties":{"id":{"description":"Hashed version identifier.","type":"string"},"content":{"description":"Raw robots.txt content.","type":"string"},"httpCode":{"description":"HTTP status code when fetching robots.txt.","examples":[200,404],"type":"number"},"firstSeen":{"description":"When this version was first observed.","anyOf":[{"description":"When this version was first observed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"When this version was last confirmed.","anyOf":[{"description":"When this version was last confirmed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["records"]}},"text/plain":{"schema":{"type":"object","properties":{"records":{"description":"Version history of robots.txt snapshots (newest first).","type":"array","items":{"type":"object","required":["id","content","httpCode","firstSeen","updatedDate"],"properties":{"id":{"description":"Hashed version identifier.","type":"string"},"content":{"description":"Raw robots.txt content.","type":"string"},"httpCode":{"description":"HTTP status code when fetching robots.txt.","examples":[200,404],"type":"number"},"firstSeen":{"description":"When this version was first observed.","anyOf":[{"description":"When this version was first observed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"When this version was last confirmed.","anyOf":[{"description":"When this version was last confirmed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["records"]}}}}},"operationId":"getApiV1VikitronRobots-txt-checker","tags":["vikitron"],"summary":"Check robots.txt history","description":"Fetches the current robots.txt for a domain and returns its version history. Each record represents a snapshot of the robots.txt content at a given time."}},"/api/v1/vikitron/ssl-certificate-checker":{"get":{"parameters":[{"description":"Domain name to check.","examples":["example.com"],"schema":{"type":"string"},"in":"query","name":"domain","required":true}],"responses":{"200":{"description":"SSL certificate check result.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the certificate was successfully retrieved.","type":"boolean"},"certificate":{"description":"SSL certificate details.","type":"object","required":["subjectCommonName","validFrom","validTo","issuerCountry","issuerOrganization","issuerOrganizationalUnit","issuerCommonName","serialNumber","fingerprint"],"properties":{"subjectCommonName":{"description":"Certificate subject CN.","examples":["*.example.com"],"type":"string"},"validFrom":{"description":"Certificate validity start date.","anyOf":[{"description":"Certificate validity start date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"Certificate validity end date.","anyOf":[{"description":"Certificate validity end date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"issuerCountry":{"description":"Issuer country code.","examples":["US"],"type":"string"},"issuerOrganization":{"description":"Issuer organization name.","examples":["Let's Encrypt"],"type":"string"},"issuerOrganizationalUnit":{"nullable":true,"anyOf":[{"description":"Issuer organizational unit.","type":"string"},{"type":"null"}]},"issuerCommonName":{"description":"Issuer common name.","examples":["R3"],"type":"string"},"serialNumber":{"description":"Certificate serial number.","type":"string"},"fingerprint":{"description":"Certificate SHA-1 fingerprint.","type":"string"}}}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the certificate was successfully retrieved.","type":"boolean"},"certificate":{"description":"SSL certificate details.","type":"object","required":["subjectCommonName","validFrom","validTo","issuerCountry","issuerOrganization","issuerOrganizationalUnit","issuerCommonName","serialNumber","fingerprint"],"properties":{"subjectCommonName":{"description":"Certificate subject CN.","examples":["*.example.com"],"type":"string"},"validFrom":{"description":"Certificate validity start date.","anyOf":[{"description":"Certificate validity start date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"Certificate validity end date.","anyOf":[{"description":"Certificate validity end date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"issuerCountry":{"description":"Issuer country code.","examples":["US"],"type":"string"},"issuerOrganization":{"description":"Issuer organization name.","examples":["Let's Encrypt"],"type":"string"},"issuerOrganizationalUnit":{"nullable":true,"anyOf":[{"description":"Issuer organizational unit.","type":"string"},{"type":"null"}]},"issuerCommonName":{"description":"Issuer common name.","examples":["R3"],"type":"string"},"serialNumber":{"description":"Certificate serial number.","type":"string"},"fingerprint":{"description":"Certificate SHA-1 fingerprint.","type":"string"}}}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the certificate was successfully retrieved.","type":"boolean"},"certificate":{"description":"SSL certificate details.","type":"object","required":["subjectCommonName","validFrom","validTo","issuerCountry","issuerOrganization","issuerOrganizationalUnit","issuerCommonName","serialNumber","fingerprint"],"properties":{"subjectCommonName":{"description":"Certificate subject CN.","examples":["*.example.com"],"type":"string"},"validFrom":{"description":"Certificate validity start date.","anyOf":[{"description":"Certificate validity start date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"Certificate validity end date.","anyOf":[{"description":"Certificate validity end date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"issuerCountry":{"description":"Issuer country code.","examples":["US"],"type":"string"},"issuerOrganization":{"description":"Issuer organization name.","examples":["Let's Encrypt"],"type":"string"},"issuerOrganizationalUnit":{"nullable":true,"anyOf":[{"description":"Issuer organizational unit.","type":"string"},{"type":"null"}]},"issuerCommonName":{"description":"Issuer common name.","examples":["R3"],"type":"string"},"serialNumber":{"description":"Certificate serial number.","type":"string"},"fingerprint":{"description":"Certificate SHA-1 fingerprint.","type":"string"}}}},"required":["success"]}}}}},"operationId":"getApiV1VikitronSsl-certificate-checker","tags":["vikitron"],"summary":"Check SSL certificate","description":"Retrieves and returns SSL/TLS certificate information for the given domain."}},"/api/v1/vikitron/subdomain-finder":{"get":{"parameters":[{"description":"Root hostname to scan for subdomains.","examples":["example.com"],"schema":{"type":"string","minLength":4,"pattern":"^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)+$"},"in":"query","name":"host","required":true}],"responses":{"200":{"description":"Subdomain scan results.","content":{"application/json":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of discovered subdomains.","type":"number"},"indexablePagesCount":{"description":"Number of subdomains that are indexable by search engines.","type":"number"},"items":{"description":"List of discovered subdomains.","type":"array","items":{"type":"object","required":["id","domain","insertedDate","httpCode"],"properties":{"id":{"description":"Subdomain identifier (same as domain).","type":"string"},"domain":{"description":"Full subdomain name.","examples":["www.example.com"],"type":"string"},"insertedDate":{"description":"When the subdomain was first discovered.","anyOf":[{"description":"When the subdomain was first discovered.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastCheckDate":{"description":"When the subdomain was last checked.","anyOf":[{"description":"When the subdomain was last checked.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"httpCode":{"description":"Last observed HTTP status code.","examples":[200,301,404],"type":"number"},"httpsSupport":{"description":"Whether the subdomain supports HTTPS.","type":"boolean"},"title":{"description":"Page title or crawl error message.","type":"string"},"server":{"description":"HTTP server software.","examples":["nginx","Apache"],"type":"string"},"responseTime":{"description":"Response time in milliseconds.","type":"number"},"uptimeOk":{"description":"Whether the subdomain is currently up.","type":"boolean"}}}}},"required":["itemCount","indexablePagesCount","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of discovered subdomains.","type":"number"},"indexablePagesCount":{"description":"Number of subdomains that are indexable by search engines.","type":"number"},"items":{"description":"List of discovered subdomains.","type":"array","items":{"type":"object","required":["id","domain","insertedDate","httpCode"],"properties":{"id":{"description":"Subdomain identifier (same as domain).","type":"string"},"domain":{"description":"Full subdomain name.","examples":["www.example.com"],"type":"string"},"insertedDate":{"description":"When the subdomain was first discovered.","anyOf":[{"description":"When the subdomain was first discovered.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastCheckDate":{"description":"When the subdomain was last checked.","anyOf":[{"description":"When the subdomain was last checked.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"httpCode":{"description":"Last observed HTTP status code.","examples":[200,301,404],"type":"number"},"httpsSupport":{"description":"Whether the subdomain supports HTTPS.","type":"boolean"},"title":{"description":"Page title or crawl error message.","type":"string"},"server":{"description":"HTTP server software.","examples":["nginx","Apache"],"type":"string"},"responseTime":{"description":"Response time in milliseconds.","type":"number"},"uptimeOk":{"description":"Whether the subdomain is currently up.","type":"boolean"}}}}},"required":["itemCount","indexablePagesCount","items"]}},"text/plain":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of discovered subdomains.","type":"number"},"indexablePagesCount":{"description":"Number of subdomains that are indexable by search engines.","type":"number"},"items":{"description":"List of discovered subdomains.","type":"array","items":{"type":"object","required":["id","domain","insertedDate","httpCode"],"properties":{"id":{"description":"Subdomain identifier (same as domain).","type":"string"},"domain":{"description":"Full subdomain name.","examples":["www.example.com"],"type":"string"},"insertedDate":{"description":"When the subdomain was first discovered.","anyOf":[{"description":"When the subdomain was first discovered.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastCheckDate":{"description":"When the subdomain was last checked.","anyOf":[{"description":"When the subdomain was last checked.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"httpCode":{"description":"Last observed HTTP status code.","examples":[200,301,404],"type":"number"},"httpsSupport":{"description":"Whether the subdomain supports HTTPS.","type":"boolean"},"title":{"description":"Page title or crawl error message.","type":"string"},"server":{"description":"HTTP server software.","examples":["nginx","Apache"],"type":"string"},"responseTime":{"description":"Response time in milliseconds.","type":"number"},"uptimeOk":{"description":"Whether the subdomain is currently up.","type":"boolean"}}}}},"required":["itemCount","indexablePagesCount","items"]}}}}},"operationId":"getApiV1VikitronSubdomain-finder","tags":["vikitron"],"summary":"Find subdomains","description":"Discovers and returns all known subdomains for a given host. If indexing is still in progress, a background crawl is triggered automatically. Results are sorted by HTTP status code."}},"/api/v1/vikitron/ip-lookup":{"get":{"parameters":[{"description":"IPv4 or IPv6 address to look up.","examples":["8.8.8.8"],"schema":{"type":"string"},"in":"query","name":"ip","required":true}],"responses":{"200":{"description":"IP address detail.","content":{"application/json":{"schema":{"type":"object","properties":{"ip":{"description":"Queried IP address.","type":"string"},"hostname":{"description":"Reverse DNS hostname.","type":"string"},"timezone":{"description":"IANA timezone identifier.","examples":["Europe/Prague"],"type":"string"},"timezoneLabel":{"description":"Human-readable timezone name.","type":"string"},"timezoneGmt":{"description":"GMT offset string.","examples":["GMT+1"],"type":"string"},"asNumber":{"description":"Autonomous System number.","examples":["AS15169"],"type":"string"},"asName":{"description":"AS name.","type":"string"},"asOrganisation":{"description":"AS organization.","type":"string"},"city":{"description":"City name.","type":"string"},"country":{"description":"Country code.","examples":["CZ","US"],"type":"string"},"countryRegion":{"description":"Region or state within the country.","type":"string"},"zip":{"description":"Postal/ZIP code.","type":"string"},"latitude":{"description":"Latitude coordinate.","type":"number"},"longitude":{"description":"Longitude coordinate.","type":"number"},"isp":{"description":"Internet Service Provider name.","type":"string"},"organisation":{"description":"IP block owner organization.","type":"string"},"mobile":{"description":"Whether the IP belongs to a mobile network.","type":"boolean"},"proxy":{"description":"Whether the IP is a known proxy/VPN.","type":"boolean"},"hosting":{"description":"Whether the IP belongs to a hosting/data center provider.","type":"boolean"},"tor":{"description":"Whether the IP is a known Tor exit node.","type":"boolean"}},"required":["ip","timezone","timezoneLabel","timezoneGmt","mobile","proxy","hosting","tor"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"ip":{"description":"Queried IP address.","type":"string"},"hostname":{"description":"Reverse DNS hostname.","type":"string"},"timezone":{"description":"IANA timezone identifier.","examples":["Europe/Prague"],"type":"string"},"timezoneLabel":{"description":"Human-readable timezone name.","type":"string"},"timezoneGmt":{"description":"GMT offset string.","examples":["GMT+1"],"type":"string"},"asNumber":{"description":"Autonomous System number.","examples":["AS15169"],"type":"string"},"asName":{"description":"AS name.","type":"string"},"asOrganisation":{"description":"AS organization.","type":"string"},"city":{"description":"City name.","type":"string"},"country":{"description":"Country code.","examples":["CZ","US"],"type":"string"},"countryRegion":{"description":"Region or state within the country.","type":"string"},"zip":{"description":"Postal/ZIP code.","type":"string"},"latitude":{"description":"Latitude coordinate.","type":"number"},"longitude":{"description":"Longitude coordinate.","type":"number"},"isp":{"description":"Internet Service Provider name.","type":"string"},"organisation":{"description":"IP block owner organization.","type":"string"},"mobile":{"description":"Whether the IP belongs to a mobile network.","type":"boolean"},"proxy":{"description":"Whether the IP is a known proxy/VPN.","type":"boolean"},"hosting":{"description":"Whether the IP belongs to a hosting/data center provider.","type":"boolean"},"tor":{"description":"Whether the IP is a known Tor exit node.","type":"boolean"}},"required":["ip","timezone","timezoneLabel","timezoneGmt","mobile","proxy","hosting","tor"]}},"text/plain":{"schema":{"type":"object","properties":{"ip":{"description":"Queried IP address.","type":"string"},"hostname":{"description":"Reverse DNS hostname.","type":"string"},"timezone":{"description":"IANA timezone identifier.","examples":["Europe/Prague"],"type":"string"},"timezoneLabel":{"description":"Human-readable timezone name.","type":"string"},"timezoneGmt":{"description":"GMT offset string.","examples":["GMT+1"],"type":"string"},"asNumber":{"description":"Autonomous System number.","examples":["AS15169"],"type":"string"},"asName":{"description":"AS name.","type":"string"},"asOrganisation":{"description":"AS organization.","type":"string"},"city":{"description":"City name.","type":"string"},"country":{"description":"Country code.","examples":["CZ","US"],"type":"string"},"countryRegion":{"description":"Region or state within the country.","type":"string"},"zip":{"description":"Postal/ZIP code.","type":"string"},"latitude":{"description":"Latitude coordinate.","type":"number"},"longitude":{"description":"Longitude coordinate.","type":"number"},"isp":{"description":"Internet Service Provider name.","type":"string"},"organisation":{"description":"IP block owner organization.","type":"string"},"mobile":{"description":"Whether the IP belongs to a mobile network.","type":"boolean"},"proxy":{"description":"Whether the IP is a known proxy/VPN.","type":"boolean"},"hosting":{"description":"Whether the IP belongs to a hosting/data center provider.","type":"boolean"},"tor":{"description":"Whether the IP is a known Tor exit node.","type":"boolean"}},"required":["ip","timezone","timezoneLabel","timezoneGmt","mobile","proxy","hosting","tor"]}}}}},"operationId":"getApiV1VikitronIp-lookup","tags":["vikitron"],"summary":"IP address lookup","description":"Returns geolocation, ASN, ISP, and network classification information for the given IP address."}},"/api/v1/vikitron/tor-ip-list":{"get":{"responses":{"200":{"description":"Tor exit node list.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"List of Tor exit nodes.","type":"array","items":{"type":"object","required":["ip","hostname","country","city","as_number","as_name","as_organisation"],"properties":{"ip":{"description":"Tor exit node IP address.","type":"string"},"hostname":{"description":"Reverse DNS hostname.","type":"string"},"country":{"description":"Country code.","examples":["DE","US","NL"],"type":"string"},"city":{"description":"City name.","type":"string"},"as_number":{"description":"Autonomous System number.","type":"string"},"as_name":{"description":"AS name.","type":"string"},"as_organisation":{"description":"AS organization.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"List of Tor exit nodes.","type":"array","items":{"type":"object","required":["ip","hostname","country","city","as_number","as_name","as_organisation"],"properties":{"ip":{"description":"Tor exit node IP address.","type":"string"},"hostname":{"description":"Reverse DNS hostname.","type":"string"},"country":{"description":"Country code.","examples":["DE","US","NL"],"type":"string"},"city":{"description":"City name.","type":"string"},"as_number":{"description":"Autonomous System number.","type":"string"},"as_name":{"description":"AS name.","type":"string"},"as_organisation":{"description":"AS organization.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"List of Tor exit nodes.","type":"array","items":{"type":"object","required":["ip","hostname","country","city","as_number","as_name","as_organisation"],"properties":{"ip":{"description":"Tor exit node IP address.","type":"string"},"hostname":{"description":"Reverse DNS hostname.","type":"string"},"country":{"description":"Country code.","examples":["DE","US","NL"],"type":"string"},"city":{"description":"City name.","type":"string"},"as_number":{"description":"Autonomous System number.","type":"string"},"as_name":{"description":"AS name.","type":"string"},"as_organisation":{"description":"AS organization.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getApiV1VikitronTor-ip-list","tags":["vikitron"],"summary":"List known Tor exit nodes","description":"Returns a list of all known Tor exit node IP addresses with their geolocation and ASN information."}},"/api/v1/vikitron/crawl-start":{"post":{"parameters":[],"responses":{"200":{"description":"Crawl start result.","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"description":"Normalised hostname being crawled (may differ from input after homepage redirects).","type":"string"},"domainId":{"description":"Opaque domain identifier (use for the status endpoint).","type":"string"},"inputHost":{"description":"Hostname the caller submitted, after normalisation.","type":"string"},"redirected":{"description":"True when the homepage probe followed a same-apex redirect chain.","type":"boolean"},"redirectChain":{"description":"Same-apex redirect chain followed at start (empty when no redirect).","type":"array","items":{"type":"object","required":["from","to","httpCode"],"properties":{"from":{"description":"Hostname before this hop.","type":"string"},"to":{"description":"Hostname after this hop.","type":"string"},"httpCode":{"description":"HTTP status code that produced this hop.","type":"number"}}}},"state":{"description":"Current crawl state.","anyOf":[{"const":"queued","type":"string"},{"const":"running","type":"string"},{"const":"completed","type":"string"}]},"started":{"description":"Whether this call actually started a new crawl.","type":"boolean"},"message":{"description":"Human-readable summary of the action taken.","type":"string"},"counts":{"type":"object","required":["pending","running","ok","error","redirect","skipped","total"],"properties":{"pending":{"description":"URLs waiting to be fetched.","type":"number"},"running":{"description":"URLs currently being fetched.","type":"number"},"ok":{"description":"Successfully fetched URLs (2xx).","type":"number"},"error":{"description":"URLs that failed to fetch.","type":"number"},"redirect":{"description":"URLs that returned a 3xx redirect.","type":"number"},"skipped":{"description":"URLs explicitly skipped (e.g. disallowed by robots.txt).","type":"number"},"total":{"description":"Total URLs discovered so far.","type":"number"}}},"crawlBudget":{"description":"Maximum number of URLs the crawler will fetch for this domain.","type":"number"}},"required":["domain","domainId","inputHost","redirected","redirectChain","state","started","message","counts","crawlBudget"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"domain":{"description":"Normalised hostname being crawled (may differ from input after homepage redirects).","type":"string"},"domainId":{"description":"Opaque domain identifier (use for the status endpoint).","type":"string"},"inputHost":{"description":"Hostname the caller submitted, after normalisation.","type":"string"},"redirected":{"description":"True when the homepage probe followed a same-apex redirect chain.","type":"boolean"},"redirectChain":{"description":"Same-apex redirect chain followed at start (empty when no redirect).","type":"array","items":{"type":"object","required":["from","to","httpCode"],"properties":{"from":{"description":"Hostname before this hop.","type":"string"},"to":{"description":"Hostname after this hop.","type":"string"},"httpCode":{"description":"HTTP status code that produced this hop.","type":"number"}}}},"state":{"description":"Current crawl state.","anyOf":[{"const":"queued","type":"string"},{"const":"running","type":"string"},{"const":"completed","type":"string"}]},"started":{"description":"Whether this call actually started a new crawl.","type":"boolean"},"message":{"description":"Human-readable summary of the action taken.","type":"string"},"counts":{"type":"object","required":["pending","running","ok","error","redirect","skipped","total"],"properties":{"pending":{"description":"URLs waiting to be fetched.","type":"number"},"running":{"description":"URLs currently being fetched.","type":"number"},"ok":{"description":"Successfully fetched URLs (2xx).","type":"number"},"error":{"description":"URLs that failed to fetch.","type":"number"},"redirect":{"description":"URLs that returned a 3xx redirect.","type":"number"},"skipped":{"description":"URLs explicitly skipped (e.g. disallowed by robots.txt).","type":"number"},"total":{"description":"Total URLs discovered so far.","type":"number"}}},"crawlBudget":{"description":"Maximum number of URLs the crawler will fetch for this domain.","type":"number"}},"required":["domain","domainId","inputHost","redirected","redirectChain","state","started","message","counts","crawlBudget"]}},"text/plain":{"schema":{"type":"object","properties":{"domain":{"description":"Normalised hostname being crawled (may differ from input after homepage redirects).","type":"string"},"domainId":{"description":"Opaque domain identifier (use for the status endpoint).","type":"string"},"inputHost":{"description":"Hostname the caller submitted, after normalisation.","type":"string"},"redirected":{"description":"True when the homepage probe followed a same-apex redirect chain.","type":"boolean"},"redirectChain":{"description":"Same-apex redirect chain followed at start (empty when no redirect).","type":"array","items":{"type":"object","required":["from","to","httpCode"],"properties":{"from":{"description":"Hostname before this hop.","type":"string"},"to":{"description":"Hostname after this hop.","type":"string"},"httpCode":{"description":"HTTP status code that produced this hop.","type":"number"}}}},"state":{"description":"Current crawl state.","anyOf":[{"const":"queued","type":"string"},{"const":"running","type":"string"},{"const":"completed","type":"string"}]},"started":{"description":"Whether this call actually started a new crawl.","type":"boolean"},"message":{"description":"Human-readable summary of the action taken.","type":"string"},"counts":{"type":"object","required":["pending","running","ok","error","redirect","skipped","total"],"properties":{"pending":{"description":"URLs waiting to be fetched.","type":"number"},"running":{"description":"URLs currently being fetched.","type":"number"},"ok":{"description":"Successfully fetched URLs (2xx).","type":"number"},"error":{"description":"URLs that failed to fetch.","type":"number"},"redirect":{"description":"URLs that returned a 3xx redirect.","type":"number"},"skipped":{"description":"URLs explicitly skipped (e.g. disallowed by robots.txt).","type":"number"},"total":{"description":"Total URLs discovered so far.","type":"number"}}},"crawlBudget":{"description":"Maximum number of URLs the crawler will fetch for this domain.","type":"number"}},"required":["domain","domainId","inputHost","redirected","redirectChain","state","started","message","counts","crawlBudget"]}}}}},"operationId":"postApiV1VikitronCrawl-start","tags":["vikitron"],"summary":"Start on-demand crawl","description":"Idempotently registers a domain as a crawl target and kicks off an immediate crawl. Will not start a second crawl while one is in progress and will not re-run a finished crawl.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"description":"Domain name (or subdomain) to crawl.","examples":["example.com"],"minLength":4,"pattern":"^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)+$","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"description":"Domain name (or subdomain) to crawl.","examples":["example.com"],"minLength":4,"pattern":"^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)+$","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"description":"Domain name (or subdomain) to crawl.","examples":["example.com"],"minLength":4,"pattern":"^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)+$","type":"string"}}}}}}}},"/api/v1/vikitron/crawl-status":{"get":{"parameters":[{"description":"Domain name to check.","examples":["example.com"],"schema":{"type":"string"},"in":"query","name":"domain","required":true}],"operationId":"getApiV1VikitronCrawl-status","tags":["vikitron"],"summary":"Get crawl status","description":"Returns the current state of an on-demand crawl and a per-URL report aggregated across every subdomain under the same registrable apex (pending, running, fetched, failed, redirected, skipped). Up to 1000 URLs are returned, ordered with running first, pending next, and the most recently checked completed URLs last.","responses":{"200":{}}}},"/api/v1/webpage/favicon":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"description":"Favicon result.","content":{"application/json":{"schema":{"type":"object","properties":{"icon":{"description":"Favicon URL or data URI. Empty string if not available.","type":"string"}},"required":["icon"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"icon":{"description":"Favicon URL or data URI. Empty string if not available.","type":"string"}},"required":["icon"]}},"text/plain":{"schema":{"type":"object","properties":{"icon":{"description":"Favicon URL or data URI. Empty string if not available.","type":"string"}},"required":["icon"]}}}}},"operationId":"getApiV1WebpageFavicon","tags":["webpage"],"summary":"Get website favicon","description":"Returns the favicon URL for the organisation website. Currently returns an empty placeholder (not yet implemented)."}},"/api/v1/webpage/screenshot":{"get":{"parameters":[{"description":"Your BizKitHub API key (passed as GET parameter).\n\n**Key format:** A 32-character string matching: `^(PROD|DEV_|ROOT)[A-Za-z0-9]{28}$`  \nPrefixes: `PROD` (production key), `DEV_` (individual developer), `ROOT` (system key with no limits). [Learn more](https://docs.bizkithub.com/api-key)","examples":["PRODPGrFxpGEtrOZfuWhnoJohUYBXuOE"],"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"responses":{"200":{"description":"Screenshot result.","content":{"application/json":{"schema":{"type":"object","properties":{"screenshot":{"description":"Screenshot URL or data URI. Empty string if not available.","type":"string"}},"required":["screenshot"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"screenshot":{"description":"Screenshot URL or data URI. Empty string if not available.","type":"string"}},"required":["screenshot"]}},"text/plain":{"schema":{"type":"object","properties":{"screenshot":{"description":"Screenshot URL or data URI. Empty string if not available.","type":"string"}},"required":["screenshot"]}}}}},"operationId":"getApiV1WebpageScreenshot","tags":["webpage"],"summary":"Get website screenshot","description":"Returns a screenshot of the organisation website. Currently returns an empty placeholder (not yet implemented)."}},"/api/service/frontend/order-status":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"operationId":"getApiServiceFrontendOrder-status","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/frontend/order-storno":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"operationId":"getApiServiceFrontendOrder-storno","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/frontend/order-pay":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"operationId":"getApiServiceFrontendOrder-pay","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/frontend/newsletter-confirm":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"token","required":true}],"operationId":"getApiServiceFrontendNewsletter-confirm","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/frontend/unsubscribe-newsletter":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"description":"E-mail address of the customer to unsubscribe.","schema":{"type":"string"},"in":"query","name":"email","required":true},{"description":"Organisation slug to scope the unsubscribe.","schema":{"type":"string"},"in":"query","name":"organisation","required":true}],"operationId":"getApiServiceFrontendUnsubscribe-newsletter","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/frontend/confirm-registration":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"token","required":true}],"operationId":"getApiServiceFrontendConfirm-registration","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/frontend/reset-password-verify-token":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"token","required":true}],"operationId":"getApiServiceFrontendReset-password-verify-token","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/emailer/queue-list":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true}],"operationId":"getApiServiceEmailerQueue-list","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/emailer/send-mail":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"externalId","required":true}],"operationId":"getApiServiceEmailerSend-mail","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/ai":{"post":{"parameters":[],"operationId":"postApiServiceAi","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["apiKey","model","question"],"properties":{"apiKey":{"type":"string"},"model":{"type":"string"},"question":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["apiKey","model","question"],"properties":{"apiKey":{"type":"string"},"model":{"type":"string"},"question":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["apiKey","model","question"],"properties":{"apiKey":{"type":"string"},"model":{"type":"string"},"question":{"type":"string"}}}}}},"responses":{"200":{}}}},"/api/service/status-page":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"apiKey","required":true},{"schema":{"type":"string"},"in":"query","name":"host","required":true}],"operationId":"getApiServiceStatus-page","tags":["service"],"description":"Internal API endpoints for micro-service architecture.","responses":{"200":{}}}},"/api/service/scheduler/claim":{"post":{"parameters":[],"operationId":"postApiServiceSchedulerClaim","tags":["service"],"description":"Claim up to N pending scheduler requests for a runner. Atomically marks them with the runnerId so concurrent runners cannot pick the same job. Returns the URL list to be crawled.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["apiKey","runnerId"],"properties":{"apiKey":{"type":"string"},"runnerId":{"minLength":4,"maxLength":8,"type":"string"},"limit":{"minimum":1,"maximum":200,"type":"number"}},"additionalProperties":false}},"multipart/form-data":{"schema":{"type":"object","required":["apiKey","runnerId"],"properties":{"apiKey":{"type":"string"},"runnerId":{"minLength":4,"maxLength":8,"type":"string"},"limit":{"minimum":1,"maximum":200,"type":"number"}},"additionalProperties":false}},"text/plain":{"schema":{"type":"object","required":["apiKey","runnerId"],"properties":{"apiKey":{"type":"string"},"runnerId":{"minLength":4,"maxLength":8,"type":"string"},"limit":{"minimum":1,"maximum":200,"type":"number"}},"additionalProperties":false}}}},"responses":{"200":{}}}},"/api/service/scheduler/peek":{"post":{"parameters":[],"operationId":"postApiServiceSchedulerPeek","tags":["service"],"description":"Read-only peek into the scheduler queue. Runs the same SELECT used by /claim but without the UPDATE, so the runner can validate end-to-end queue access (auth + DB + query) from its health check without consuming jobs.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["apiKey"],"properties":{"apiKey":{"type":"string"},"sampleSize":{"minimum":0,"maximum":25,"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["apiKey"],"properties":{"apiKey":{"type":"string"},"sampleSize":{"minimum":0,"maximum":25,"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["apiKey"],"properties":{"apiKey":{"type":"string"},"sampleSize":{"minimum":0,"maximum":25,"type":"number"}}}}}},"responses":{"200":{}}}},"/api/service/scheduler/complete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiServiceSchedulerComplete","tags":["service"],"description":"Report the outcome of a single scheduler request. On success the row is marked completed; on failure the retry counter is incremented and the row is finalized once retries are exhausted.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["apiKey","id","success"],"properties":{"apiKey":{"type":"string"},"id":{"description":"Scheduler request id (bigint serialized as string).","type":"string"},"success":{"type":"boolean"},"httpCode":{"anyOf":[{"type":"number"},{"type":"null"}]},"responseBody":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["apiKey","id","success"],"properties":{"apiKey":{"type":"string"},"id":{"description":"Scheduler request id (bigint serialized as string).","type":"string"},"success":{"type":"boolean"},"httpCode":{"anyOf":[{"type":"number"},{"type":"null"}]},"responseBody":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["apiKey","id","success"],"properties":{"apiKey":{"type":"string"},"id":{"description":"Scheduler request id (bigint serialized as string).","type":"string"},"success":{"type":"boolean"},"httpCode":{"anyOf":[{"type":"number"},{"type":"null"}]},"responseBody":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/api/service/scheduler/heartbeat":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiServiceSchedulerHeartbeat","tags":["service"],"description":"Liveness signal from the external scheduler runner. Stored as a temp record so /api/v1/ping/health can flag the runner offline if no heartbeat is received within the staleness window.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["apiKey","runnerId","requestCount","successCount"],"properties":{"apiKey":{"type":"string"},"runnerId":{"minLength":4,"maxLength":8,"type":"string"},"requestCount":{"minimum":0,"type":"number"},"successCount":{"minimum":0,"type":"number"}},"additionalProperties":false}},"multipart/form-data":{"schema":{"type":"object","required":["apiKey","runnerId","requestCount","successCount"],"properties":{"apiKey":{"type":"string"},"runnerId":{"minLength":4,"maxLength":8,"type":"string"},"requestCount":{"minimum":0,"type":"number"},"successCount":{"minimum":0,"type":"number"}},"additionalProperties":false}},"text/plain":{"schema":{"type":"object","required":["apiKey","runnerId","requestCount","successCount"],"properties":{"apiKey":{"type":"string"},"runnerId":{"minLength":4,"maxLength":8,"type":"string"},"requestCount":{"minimum":0,"type":"number"},"successCount":{"minimum":0,"type":"number"}},"additionalProperties":false}}}}}},"/api/service/scheduler/log":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postApiServiceSchedulerLog","tags":["service"],"description":"Centralized log channel for the external scheduler runner. Always writes against the BizKitHub internal organisation so failures are surfaced even when the runner has no DB access.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["apiKey","message"],"properties":{"apiKey":{"type":"string"},"message":{"type":"string"},"level":{"enum":["info","success","error","warning","critical"],"type":"string"},"subject":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["apiKey","message"],"properties":{"apiKey":{"type":"string"},"message":{"type":"string"},"level":{"enum":["info","success","error","warning","critical"],"type":"string"},"subject":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["apiKey","message"],"properties":{"apiKey":{"type":"string"},"message":{"type":"string"},"level":{"enum":["info","success","error","warning","critical"],"type":"string"},"subject":{"type":"string"}}}}}}}},"/bff/account/":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"isLoggedIn":{"description":"Whether the user is currently logged in.","type":"boolean"}},"required":["isLoggedIn"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"isLoggedIn":{"description":"Whether the user is currently logged in.","type":"boolean"}},"required":["isLoggedIn"]}},"text/plain":{"schema":{"type":"object","properties":{"isLoggedIn":{"description":"Whether the user is currently logged in.","type":"boolean"}},"required":["isLoggedIn"]}}}}},"operationId":"getBffAccount","tags":["Account"],"summary":"Check authentication status","description":"Returns whether the current request is authenticated."}},"/bff/account/detail":{"get":{"parameters":[{"description":"Override identity ID (defaults to cookie value).","schema":{"type":"string"},"in":"query","name":"brjInternalQueryIdentityId","required":false}],"operationId":"getBffAccountDetail","tags":["Account"],"summary":"Get account detail","description":"Returns full account detail for the authenticated user, including profile and geo information.","responses":{"200":{}}}},"/bff/account/detail-contact":{"get":{"operationId":"getBffAccountDetail-contact","tags":["Account"],"summary":"Get account contact information","description":"Returns contact details (email, phone, address) for the authenticated user.","responses":{"200":{}}}},"/bff/account/audit-login-attempts":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"currentIp":{"description":"IP address of the current request.","type":"string"},"currentLocation":{"description":"Resolved location string for the current request.","type":"string"},"itemCount":{"description":"Total number of login attempts.","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","committed","ip","insertedDate","relativeDate","location"],"properties":{"id":{"description":"Login attempt ID.","type":"number"},"committed":{"description":"Whether the login attempt was successful.","type":"boolean"},"ip":{"description":"IP address of the login attempt.","type":"string"},"insertedDate":{"description":"Absolute date of the login attempt.","type":"string"},"relativeDate":{"description":"Relative time since the login attempt.","type":"string"},"location":{"description":"Resolved geo location of the login attempt.","type":"string"}}}}},"required":["currentIp","currentLocation","itemCount","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"currentIp":{"description":"IP address of the current request.","type":"string"},"currentLocation":{"description":"Resolved location string for the current request.","type":"string"},"itemCount":{"description":"Total number of login attempts.","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","committed","ip","insertedDate","relativeDate","location"],"properties":{"id":{"description":"Login attempt ID.","type":"number"},"committed":{"description":"Whether the login attempt was successful.","type":"boolean"},"ip":{"description":"IP address of the login attempt.","type":"string"},"insertedDate":{"description":"Absolute date of the login attempt.","type":"string"},"relativeDate":{"description":"Relative time since the login attempt.","type":"string"},"location":{"description":"Resolved geo location of the login attempt.","type":"string"}}}}},"required":["currentIp","currentLocation","itemCount","items"]}},"text/plain":{"schema":{"type":"object","properties":{"currentIp":{"description":"IP address of the current request.","type":"string"},"currentLocation":{"description":"Resolved location string for the current request.","type":"string"},"itemCount":{"description":"Total number of login attempts.","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","committed","ip","insertedDate","relativeDate","location"],"properties":{"id":{"description":"Login attempt ID.","type":"number"},"committed":{"description":"Whether the login attempt was successful.","type":"boolean"},"ip":{"description":"IP address of the login attempt.","type":"string"},"insertedDate":{"description":"Absolute date of the login attempt.","type":"string"},"relativeDate":{"description":"Relative time since the login attempt.","type":"string"},"location":{"description":"Resolved geo location of the login attempt.","type":"string"}}}}},"required":["currentIp","currentLocation","itemCount","items"]}}}}},"operationId":"getBffAccountAudit-login-attempts","tags":["Account"],"summary":"List login attempts","description":"Returns audit log of login attempts for the authenticated user with geo information."}},"/bff/account/search-history":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Optional substring filter on the stored query text.","schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of distinct historical queries (after the filter).","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","query","results","frequency","updatedDate"],"properties":{"id":{"description":"Internal log row id (stable identifier for the row).","type":"number"},"query":{"description":"The exact normalized query text the member searched for.","type":"string"},"results":{"description":"Result count recorded the last time anyone in the org ran this query.","type":"number"},"frequency":{"description":"How many times this member has run this query.","type":"number"},"updatedDate":{"description":"Timestamp of the most recent time the member ran this query.","type":"string"}}}}},"required":["itemCount","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of distinct historical queries (after the filter).","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","query","results","frequency","updatedDate"],"properties":{"id":{"description":"Internal log row id (stable identifier for the row).","type":"number"},"query":{"description":"The exact normalized query text the member searched for.","type":"string"},"results":{"description":"Result count recorded the last time anyone in the org ran this query.","type":"number"},"frequency":{"description":"How many times this member has run this query.","type":"number"},"updatedDate":{"description":"Timestamp of the most recent time the member ran this query.","type":"string"}}}}},"required":["itemCount","items"]}},"text/plain":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of distinct historical queries (after the filter).","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","query","results","frequency","updatedDate"],"properties":{"id":{"description":"Internal log row id (stable identifier for the row).","type":"number"},"query":{"description":"The exact normalized query text the member searched for.","type":"string"},"results":{"description":"Result count recorded the last time anyone in the org ran this query.","type":"number"},"frequency":{"description":"How many times this member has run this query.","type":"number"},"updatedDate":{"description":"Timestamp of the most recent time the member ran this query.","type":"string"}}}}},"required":["itemCount","items"]}}}}},"operationId":"getBffAccountSearch-history","tags":["Account"],"summary":"List my search history","description":"Returns the personal search history of the authenticated member — one row per unique query (deduplicated by the unique index on cas__organisation_search_log), ordered by the most recent occurrence first. Includes how many times the member ran the query (frequency) and the latest result count. Category filter is intentionally ignored on the write side, so the history reflects what the user searched for, not where from."}},"/bff/account/login-otp-auth":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the OTP code was valid.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the OTP code was valid.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the OTP code was valid.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAccountLogin-otp-auth","tags":["Account"],"summary":"Verify OTP code","description":"Validates the 6-digit TOTP code (RFC 6238, HMAC-SHA1, 30s period) against the user's stored base32 secret with ±1-step clock skew tolerance, and authorizes the login identity if correct.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["otpCode"],"properties":{"otpCode":{"description":"One-time password code from the authenticator app.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["otpCode"],"properties":{"otpCode":{"description":"One-time password code from the authenticator app.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["otpCode"],"properties":{"otpCode":{"description":"One-time password code from the authenticator app.","type":"string"}}}}}}}},"/bff/account/reset-password":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the password was reset.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the password was reset.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the password was reset.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAccountReset-password","tags":["Account"],"summary":"Reset password","description":"Sets a new password using a reset token received via email.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","passwordInput","passwordAgain"],"properties":{"token":{"description":"Password reset token from the email link.","type":"string"},"passwordInput":{"description":"New password.","type":"string"},"passwordAgain":{"description":"New password confirmation (must match passwordInput).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["token","passwordInput","passwordAgain"],"properties":{"token":{"description":"Password reset token from the email link.","type":"string"},"passwordInput":{"description":"New password.","type":"string"},"passwordAgain":{"description":"New password confirmation (must match passwordInput).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["token","passwordInput","passwordAgain"],"properties":{"token":{"description":"Password reset token from the email link.","type":"string"},"passwordInput":{"description":"New password.","type":"string"},"passwordAgain":{"description":"New password confirmation (must match passwordInput).","type":"string"}}}}}}}},"/bff/account/restore-personal-account":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true if no error is thrown.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true if no error is thrown.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true if no error is thrown.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAccountRestore-personal-account","tags":["Account"],"summary":"Restore personal account","description":"Sends a password reset email to the specified address if a matching account exists.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["emailInput"],"properties":{"emailInput":{"description":"Email address of the account to restore.","examples":["user@example.com"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["emailInput"],"properties":{"emailInput":{"description":"Email address of the account to restore.","examples":["user@example.com"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["emailInput"],"properties":{"emailInput":{"description":"Email address of the account to restore.","examples":["user@example.com"],"type":"string"}}}}}}}},"/bff/account/set-activity-status":{"get":{"parameters":[{"description":"Activity status key (e.g. \"online\", \"away\", \"busy\").","examples":["online"],"schema":{"type":"string"},"in":"query","name":"status","required":true}],"operationId":"getBffAccountSet-activity-status","tags":["Account"],"summary":"Set activity status","description":"Updates the activity status of the authenticated user.","responses":{"200":{}}}},"/bff/account/set-name":{"post":{"parameters":[],"operationId":"postBffAccountSet-name","tags":["Account"],"summary":"Set user name","description":"Updates the first, last, and optionally middle name of the authenticated user.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["firstName","lastName"],"properties":{"firstName":{"description":"First name (will be capitalized).","type":"string"},"lastName":{"description":"Last name (will be capitalized).","type":"string"},"middleName":{"description":"Middle name (will be capitalized). Omit to leave unchanged.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["firstName","lastName"],"properties":{"firstName":{"description":"First name (will be capitalized).","type":"string"},"lastName":{"description":"Last name (will be capitalized).","type":"string"},"middleName":{"description":"Middle name (will be capitalized). Omit to leave unchanged.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["firstName","lastName"],"properties":{"firstName":{"description":"First name (will be capitalized).","type":"string"},"lastName":{"description":"Last name (will be capitalized).","type":"string"},"middleName":{"description":"Middle name (will be capitalized). Omit to leave unchanged.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/account/update-profile":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAccountUpdate-profile","tags":["Account"],"summary":"Update user profile","description":"Partial update of the authenticated user profile. Only provided fields are changed. Supersedes /set-name for new code — supports all personal fields including birthday and gender.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"minLength":2,"maxLength":100,"description":"First name (will be capitalized).","type":"string"},"lastName":{"minLength":2,"maxLength":100,"description":"Last name (will be capitalized).","type":"string"},"middleName":{"nullable":true,"anyOf":[{"maxLength":100,"description":"Middle name (will be capitalized). Null to clear.","type":"string"},{"type":"null"}]},"birthday":{"nullable":true,"anyOf":[{"pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Date of birth in ISO 8601 format (YYYY-MM-DD). Null to clear.","examples":["1990-05-15"],"type":"string"},{"type":"null"}]},"gender":{"nullable":true,"anyOf":[{"description":"Gender identifier: \"male\", \"female\", \"other\", or null to clear.","examples":["male"],"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"firstName":{"minLength":2,"maxLength":100,"description":"First name (will be capitalized).","type":"string"},"lastName":{"minLength":2,"maxLength":100,"description":"Last name (will be capitalized).","type":"string"},"middleName":{"nullable":true,"anyOf":[{"maxLength":100,"description":"Middle name (will be capitalized). Null to clear.","type":"string"},{"type":"null"}]},"birthday":{"nullable":true,"anyOf":[{"pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Date of birth in ISO 8601 format (YYYY-MM-DD). Null to clear.","examples":["1990-05-15"],"type":"string"},{"type":"null"}]},"gender":{"nullable":true,"anyOf":[{"description":"Gender identifier: \"male\", \"female\", \"other\", or null to clear.","examples":["male"],"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","properties":{"firstName":{"minLength":2,"maxLength":100,"description":"First name (will be capitalized).","type":"string"},"lastName":{"minLength":2,"maxLength":100,"description":"Last name (will be capitalized).","type":"string"},"middleName":{"nullable":true,"anyOf":[{"maxLength":100,"description":"Middle name (will be capitalized). Null to clear.","type":"string"},{"type":"null"}]},"birthday":{"nullable":true,"anyOf":[{"pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Date of birth in ISO 8601 format (YYYY-MM-DD). Null to clear.","examples":["1990-05-15"],"type":"string"},{"type":"null"}]},"gender":{"nullable":true,"anyOf":[{"description":"Gender identifier: \"male\", \"female\", \"other\", or null to clear.","examples":["male"],"type":"string"},{"type":"null"}]}}}}}}}},"/bff/account/setup-otp-generate-secret":{"post":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"secret":{"description":"Base32-encoded TOTP secret (RFC 4648, A–Z2–7, 32 chars).","type":"string"},"otpAuthUri":{"description":"Canonical otpauth://totp/... URI suitable for direct QR encoding (works with all TOTP apps).","type":"string"},"qrCodeUrl":{"description":"Pre-rendered QR code image URL hosted on cdn.bizkithub.com.","type":"string"}},"required":["secret","otpAuthUri","qrCodeUrl"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"secret":{"description":"Base32-encoded TOTP secret (RFC 4648, A–Z2–7, 32 chars).","type":"string"},"otpAuthUri":{"description":"Canonical otpauth://totp/... URI suitable for direct QR encoding (works with all TOTP apps).","type":"string"},"qrCodeUrl":{"description":"Pre-rendered QR code image URL hosted on cdn.bizkithub.com.","type":"string"}},"required":["secret","otpAuthUri","qrCodeUrl"]}},"text/plain":{"schema":{"type":"object","properties":{"secret":{"description":"Base32-encoded TOTP secret (RFC 4648, A–Z2–7, 32 chars).","type":"string"},"otpAuthUri":{"description":"Canonical otpauth://totp/... URI suitable for direct QR encoding (works with all TOTP apps).","type":"string"},"qrCodeUrl":{"description":"Pre-rendered QR code image URL hosted on cdn.bizkithub.com.","type":"string"}},"required":["secret","otpAuthUri","qrCodeUrl"]}}}}},"operationId":"postBffAccountSetup-otp-generate-secret","tags":["Account"],"summary":"Generate OTP secret","description":"Generates a fresh RFC 4226 base32 TOTP secret (160 bits) plus the canonical otpauth:// URI for QR-code rendering. The secret is NOT persisted yet — call /setup-otp-save with a verification code to enable 2FA."}},"/bff/account/setup-otp-save":{"post":{"parameters":[],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","reason"],"properties":{"success":{"const":false,"type":"boolean"},"reason":{"const":"invalid-code","type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","reason"],"properties":{"success":{"const":false,"type":"boolean"},"reason":{"const":"invalid-code","type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","reason"],"properties":{"success":{"const":false,"type":"boolean"},"reason":{"const":"invalid-code","type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","reason"],"properties":{"success":{"const":false,"type":"boolean"},"reason":{"const":"invalid-code","type":"string"}}}]}}}}},"operationId":"postBffAccountSetup-otp-save","tags":["Account"],"summary":"Activate 2FA on the account","description":"Verifies the 6-digit TOTP code against the supplied base32 secret. On success persists the secret on cas__user.otp_code and sets otp_enabled_date = NOW(); on failure returns `{ success: false, reason: \"invalid-code\" }` so the UI can prompt the user to retry.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["secret","otpCode"],"properties":{"secret":{"description":"Base32 TOTP secret returned by /setup-otp-generate-secret.","type":"string"},"otpCode":{"description":"6-digit code shown by the authenticator app right now — proves the user actually scanned the QR.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["secret","otpCode"],"properties":{"secret":{"description":"Base32 TOTP secret returned by /setup-otp-generate-secret.","type":"string"},"otpCode":{"description":"6-digit code shown by the authenticator app right now — proves the user actually scanned the QR.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["secret","otpCode"],"properties":{"secret":{"description":"Base32 TOTP secret returned by /setup-otp-generate-secret.","type":"string"},"otpCode":{"description":"6-digit code shown by the authenticator app right now — proves the user actually scanned the QR.","type":"string"}}}}}}}},"/bff/account/setup-otp-disable":{"post":{"parameters":[],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","reason"],"properties":{"success":{"const":false,"type":"boolean"},"reason":{"const":"invalid-code","type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","reason"],"properties":{"success":{"const":false,"type":"boolean"},"reason":{"const":"invalid-code","type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","reason"],"properties":{"success":{"const":false,"type":"boolean"},"reason":{"const":"invalid-code","type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","reason"],"properties":{"success":{"const":false,"type":"boolean"},"reason":{"const":"invalid-code","type":"string"}}}]}}}}},"operationId":"postBffAccountSetup-otp-disable","tags":["Account"],"summary":"Disable 2FA on the account","description":"Removes the stored TOTP secret after verifying the user can still produce a valid code. When the user has no 2FA configured, returns `{ success: true }` as a no-op.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["otpCode"],"properties":{"otpCode":{"description":"Current 6-digit TOTP code from the authenticator app — required to prove the request comes from the legitimate device and is not a session-hijack attempt to drop 2FA.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["otpCode"],"properties":{"otpCode":{"description":"Current 6-digit TOTP code from the authenticator app — required to prove the request comes from the legitimate device and is not a session-hijack attempt to drop 2FA.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["otpCode"],"properties":{"otpCode":{"description":"Current 6-digit TOTP code from the authenticator app — required to prove the request comes from the legitimate device and is not a session-hijack attempt to drop 2FA.","type":"string"}}}}}}}},"/bff/account/sync-status":{"get":{"operationId":"getBffAccountSync-status","tags":["Account"],"summary":"Get sync status","description":"Returns the current authentication and session sync status based on request geo data.","responses":{"200":{}}}},"/bff/account/create-login-attempt":{"post":{"parameters":[],"responses":{"200":{"anyOf":[{"type":"object","required":["success","identifier"],"properties":{"success":{"const":true,"type":"boolean"},"identifier":{"examples":["03oq7hsu9Iv70QogX0vBIcjDElj27WWe"],"type":"string"}}},{"type":"object","required":["success","error"],"properties":{"success":{"const":false,"type":"boolean"},"error":{"examples":["We were unable to find an account with that username. Please enter a different name or create a new BRJ ID."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success","identifier"],"properties":{"success":{"const":true,"type":"boolean"},"identifier":{"examples":["03oq7hsu9Iv70QogX0vBIcjDElj27WWe"],"type":"string"}}},{"type":"object","required":["success","error"],"properties":{"success":{"const":false,"type":"boolean"},"error":{"examples":["We were unable to find an account with that username. Please enter a different name or create a new BRJ ID."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success","identifier"],"properties":{"success":{"const":true,"type":"boolean"},"identifier":{"examples":["03oq7hsu9Iv70QogX0vBIcjDElj27WWe"],"type":"string"}}},{"type":"object","required":["success","error"],"properties":{"success":{"const":false,"type":"boolean"},"error":{"examples":["We were unable to find an account with that username. Please enter a different name or create a new BRJ ID."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success","identifier"],"properties":{"success":{"const":true,"type":"boolean"},"identifier":{"examples":["03oq7hsu9Iv70QogX0vBIcjDElj27WWe"],"type":"string"}}},{"type":"object","required":["success","error"],"properties":{"success":{"const":false,"type":"boolean"},"error":{"examples":["We were unable to find an account with that username. Please enter a different name or create a new BRJ ID."],"type":"string"}}}]}}}}},"operationId":"postBffAccountCreate-login-attempt","tags":["Account"],"summary":"Create login attempt","description":"Creates a login attempt record and returns an identifier used for the subsequent /login call.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username"],"properties":{"username":{"description":"Username (email) to create a login attempt for.","examples":["janbarasek@gmail.com"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["username"],"properties":{"username":{"description":"Username (email) to create a login attempt for.","examples":["janbarasek@gmail.com"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["username"],"properties":{"username":{"description":"Username (email) to create a login attempt for.","examples":["janbarasek@gmail.com"],"type":"string"}}}}}}}},"/bff/account/login":{"post":{"parameters":[],"responses":{"200":{"anyOf":[{"type":"object","required":["success","identity","needOtp","locale"],"properties":{"success":{"const":true,"type":"boolean"},"identity":{"examples":["03oq7hsu9Iv70QogX0vBIcjDElj27WWe"],"type":"string"},"needOtp":{"examples":false,"type":"boolean"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}},{"type":"object","required":["success","error"],"properties":{"success":{"const":false,"type":"boolean"},"error":{"examples":["User can not be logged in."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success","identity","needOtp","locale"],"properties":{"success":{"const":true,"type":"boolean"},"identity":{"examples":["03oq7hsu9Iv70QogX0vBIcjDElj27WWe"],"type":"string"},"needOtp":{"examples":false,"type":"boolean"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}},{"type":"object","required":["success","error"],"properties":{"success":{"const":false,"type":"boolean"},"error":{"examples":["User can not be logged in."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success","identity","needOtp","locale"],"properties":{"success":{"const":true,"type":"boolean"},"identity":{"examples":["03oq7hsu9Iv70QogX0vBIcjDElj27WWe"],"type":"string"},"needOtp":{"examples":false,"type":"boolean"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}},{"type":"object","required":["success","error"],"properties":{"success":{"const":false,"type":"boolean"},"error":{"examples":["User can not be logged in."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success","identity","needOtp","locale"],"properties":{"success":{"const":true,"type":"boolean"},"identity":{"examples":["03oq7hsu9Iv70QogX0vBIcjDElj27WWe"],"type":"string"},"needOtp":{"examples":false,"type":"boolean"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}},{"type":"object","required":["success","error"],"properties":{"success":{"const":false,"type":"boolean"},"error":{"examples":["User can not be logged in."],"type":"string"}}}]}}}}},"operationId":"postBffAccountLogin","tags":["Account"],"summary":"Log in","description":"Authenticates the user with credentials and a valid login attempt identifier.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username","password","attempt"],"properties":{"username":{"minLength":1,"description":"Username (email) of the account.","type":"string"},"password":{"minLength":1,"description":"Account password.","type":"string"},"attempt":{"minLength":1,"description":"Login attempt identifier from /create-login-attempt.","type":"string"},"host":{"description":"Optional host origin for cross-domain login.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["username","password","attempt"],"properties":{"username":{"minLength":1,"description":"Username (email) of the account.","type":"string"},"password":{"minLength":1,"description":"Account password.","type":"string"},"attempt":{"minLength":1,"description":"Login attempt identifier from /create-login-attempt.","type":"string"},"host":{"description":"Optional host origin for cross-domain login.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["username","password","attempt"],"properties":{"username":{"minLength":1,"description":"Username (email) of the account.","type":"string"},"password":{"minLength":1,"description":"Account password.","type":"string"},"attempt":{"minLength":1,"description":"Login attempt identifier from /create-login-attempt.","type":"string"},"host":{"description":"Optional host origin for cross-domain login.","type":"string"}}}}}}}},"/bff/account/logout":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAccountLogout","tags":["Account"],"summary":"Log out","description":"Logs out a specific session or all other sessions for the authenticated user.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"identityId":{"description":"Identity to log out (defaults to current session).","type":"string"},"logoutAllOther":{"description":"Log out all other sessions instead.","examples":[false],"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"identityId":{"description":"Identity to log out (defaults to current session).","type":"string"},"logoutAllOther":{"description":"Log out all other sessions instead.","examples":[false],"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","properties":{"identityId":{"description":"Identity to log out (defaults to current session).","type":"string"},"logoutAllOther":{"description":"Log out all other sessions instead.","examples":[false],"type":"boolean"}}}}}}}},"/bff/account/create-account":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was created.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was created.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was created.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAccountCreate-account","tags":["Account"],"summary":"Create account","description":"Registers a new user account and sends a confirmation email.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["locale","organisationName","emailInput","firstName","lastName","passwordInput","passwordAgain"],"properties":{"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"organisationName":{"description":"Name of the organisation for the new account.","type":"string"},"emailInput":{"description":"Email address for the new account.","examples":["user@example.com"],"type":"string"},"firstName":{"minLength":2,"description":"First name of the account holder.","type":"string"},"lastName":{"minLength":2,"description":"Last name of the account holder.","type":"string"},"passwordInput":{"minLength":8,"description":"Password (min 8 characters).","type":"string"},"passwordAgain":{"minLength":8,"description":"Password confirmation (must match passwordInput).","type":"string"},"checkboxTerms":{"description":"Whether terms and conditions were accepted.","type":"boolean"},"checkboxMarketing":{"description":"Whether marketing consent was given.","default":true,"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["locale","organisationName","emailInput","firstName","lastName","passwordInput","passwordAgain"],"properties":{"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"organisationName":{"description":"Name of the organisation for the new account.","type":"string"},"emailInput":{"description":"Email address for the new account.","examples":["user@example.com"],"type":"string"},"firstName":{"minLength":2,"description":"First name of the account holder.","type":"string"},"lastName":{"minLength":2,"description":"Last name of the account holder.","type":"string"},"passwordInput":{"minLength":8,"description":"Password (min 8 characters).","type":"string"},"passwordAgain":{"minLength":8,"description":"Password confirmation (must match passwordInput).","type":"string"},"checkboxTerms":{"description":"Whether terms and conditions were accepted.","type":"boolean"},"checkboxMarketing":{"description":"Whether marketing consent was given.","default":true,"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["locale","organisationName","emailInput","firstName","lastName","passwordInput","passwordAgain"],"properties":{"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"organisationName":{"description":"Name of the organisation for the new account.","type":"string"},"emailInput":{"description":"Email address for the new account.","examples":["user@example.com"],"type":"string"},"firstName":{"minLength":2,"description":"First name of the account holder.","type":"string"},"lastName":{"minLength":2,"description":"Last name of the account holder.","type":"string"},"passwordInput":{"minLength":8,"description":"Password (min 8 characters).","type":"string"},"passwordAgain":{"minLength":8,"description":"Password confirmation (must match passwordInput).","type":"string"},"checkboxTerms":{"description":"Whether terms and conditions were accepted.","type":"boolean"},"checkboxMarketing":{"description":"Whether marketing consent was given.","default":true,"type":"boolean"}}}}}}}},"/bff/account/create-account-by-token":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was activated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was activated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was activated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAccountCreate-account-by-token","tags":["Account"],"summary":"Confirm account by token","description":"Activates a previously created account using the confirmation token from email.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"description":"Confirmation token from the registration email.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["token"],"properties":{"token":{"description":"Confirmation token from the registration email.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["token"],"properties":{"token":{"description":"Confirmation token from the registration email.","type":"string"}}}}}}}},"/bff/activity/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Filter by event type (e.g. `order.create`).","examples":["order.create"],"schema":{"type":"string"},"in":"query","name":"type","required":false},{"description":"Polymorphic subject entity (DB table name). Used together with `subjectId` to load the \"Activity\" tab on a specific entity detail page.","examples":["shop__order"],"schema":{"type":"string"},"in":"query","name":"subjectEntity","required":false},{"description":"Polymorphic subject row id.","examples":["1234"],"schema":{"type":"string"},"in":"query","name":"subjectId","required":false},{"description":"Composite actor filter from the admin \"Kto\" dropdown. Format: `member:<external_id>` or `contact:<external_id>` (16-char `shop__contact.external_id`).","examples":["member:6NZboqKESgMFufqe","contact:Dlko1bEG85c6304a"],"schema":{"type":"string"},"in":"query","name":"actor","required":false},{"description":"Filter by actor kind.","examples":["member"],"schema":{"anyOf":[{"const":"member","type":"string"},{"const":"contact","type":"string"},{"const":"system","type":"string"},{"const":"cron","type":"string"},{"const":"api","type":"string"}]},"in":"query","name":"actorKind","required":false},{"description":"Filter by a specific staff member as actor (`cas__organisation_member.id`).","examples":["42"],"schema":{"type":"string"},"in":"query","name":"actorMemberId","required":false},{"description":"External 16-char id of the contact who acted.","examples":["Dlko1bEG85c6304a"],"schema":{"type":"string"},"in":"query","name":"actorContactExternalId","required":false},{"description":"External 16-char id of the contact the action was directed at.","examples":["Dlko1bEG85c6304a"],"schema":{"type":"string"},"in":"query","name":"targetContactExternalId","required":false},{"description":"External 16-char id matching the contact in *either* role — actor OR target. Used by the \"Aktivity\" tab on the contact detail page where the operator wants to see everything about a contact regardless of which side they played.","examples":["Dlko1bEG85c6304a"],"schema":{"type":"string"},"in":"query","name":"contactExternalId","required":false},{"description":"Minimum level (0 info, 1 notice, 2 warning).","examples":["1"],"schema":{"type":"string"},"in":"query","name":"minLevel","required":false},{"description":"ISO timestamp — events after this point.","examples":["2026-01-01T00:00:00Z"],"schema":{"type":"string"},"in":"query","name":"dateFrom","required":false},{"description":"ISO timestamp — events before this point.","examples":["2026-12-31T23:59:59Z"],"schema":{"type":"string"},"in":"query","name":"dateTo","required":false},{"description":"Group all activities from one HTTP request / cron run.","examples":["iad1::cdy5w-1758481392361"],"schema":{"type":"string"},"in":"query","name":"correlationId","required":false}],"operationId":"getBffActivityList","tags":["Activity"],"summary":"List activity entries","description":"Returns a paginated list of activity entries for the current organisation. Supports filtering by event type, polymorphic subject, actor (member/contact/system/cron/api), target contact, level, time range, and correlation id.","responses":{"200":{}}}},"/bff/activity/detail":{"get":{"parameters":[{"description":"24-char activity external id (the URL slug from /activity/{id} in admin).","examples":["aZfP19992R1wD0Cp8hx7ao2w"],"schema":{"type":"string","minLength":24,"maxLength":24},"in":"query","name":"id","required":true}],"operationId":"getBffActivityDetail","tags":["Activity"],"summary":"Get activity entry detail","description":"Returns a single activity entry with the full meta payload, geo enrichment and network context. Scoped to the current organisation.","responses":{"200":{}}}},"/bff/activity/actors":{"get":{"operationId":"getBffActivityActors","tags":["Activity"],"summary":"List distinct actors who have written activity entries","description":"Returns staff members and external contacts who have authored at least one row in `core__activity` for the current organisation. Used to populate the leading \"Kto\" filter on the admin Aktivity grid — only real actors show up, no empty options.","responses":{"200":{}}}},"/bff/address/detail":{"get":{"parameters":[{"description":"External address identifier.","examples":["addr_abc123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"description":"Address detail.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Unique external address identifier.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","examples":["Nové Město"],"type":"string"},"stateRegion":{"description":"State or region.","examples":["Středočeský kraj"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}},"required":["id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Unique external address identifier.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","examples":["Nové Město"],"type":"string"},"stateRegion":{"description":"State or region.","examples":["Středočeský kraj"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}},"required":["id"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Unique external address identifier.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","examples":["Nové Město"],"type":"string"},"stateRegion":{"description":"State or region.","examples":["Středočeský kraj"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}},"required":["id"]}}}}},"operationId":"getBffAddressDetail","tags":["Address"],"summary":"Get address detail","description":"Returns a single address record by its external ID."}},"/bff/address/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAddressCreate","tags":["Address"],"summary":"Create a new address","description":"Creates a new address record and links it to a contact identified by contactId.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"External address ID. Required for update, optional for create.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"contactId":{"description":"Contact external reference number to link address to.","examples":["cu_xyz789"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"External address ID. Required for update, optional for create.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"contactId":{"description":"Contact external reference number to link address to.","examples":["cu_xyz789"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"External address ID. Required for update, optional for create.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"contactId":{"description":"Contact external reference number to link address to.","examples":["cu_xyz789"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}}}}}}}},"/bff/address/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAddressUpdate","tags":["Address"],"summary":"Update an existing address","description":"Updates an existing address record. The address ID must be provided in the body.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"External address ID. Required for update, optional for create.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"contactId":{"description":"Contact external reference number to link address to.","examples":["cu_xyz789"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"External address ID. Required for update, optional for create.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"contactId":{"description":"Contact external reference number to link address to.","examples":["cu_xyz789"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"External address ID. Required for update, optional for create.","examples":["addr_abc123"],"type":"string"},"type":{"description":"Address type: accounting, billing, deliveryGoods or deliveryInvoice.","examples":["billing"],"type":"string"},"contactId":{"description":"Contact external reference number to link address to.","examples":["cu_xyz789"],"type":"string"},"firstName":{"description":"First name.","examples":["Jan"],"type":"string"},"lastName":{"description":"Last name.","examples":["Novák"],"type":"string"},"companyName":{"description":"Company name.","examples":["Acme s.r.o."],"type":"string"},"streetAddress":{"description":"Street and house number.","examples":["Vodičkova 36"],"type":"string"},"postalCode":{"description":"Postal / ZIP code.","examples":["11000"],"type":"string"},"city":{"description":"City name.","examples":["Praha"],"type":"string"},"cityPart":{"description":"City part or district.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","examples":["05103118"],"type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (DIČ).","examples":["CZ9609040727"],"type":"string"},"notice":{"description":"Internal note about the address.","type":"string"}}}}}}}},"/bff/admin/organisation-list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["name","slug","description","emoji","memberCount","lastActivityAt"],"properties":{"name":{"description":"Organisation display name.","type":"string"},"slug":{"description":"URL-friendly organisation identifier.","type":"string"},"description":{"description":"Organisation description.","anyOf":[{"type":"string"},{"type":"null"}]},"emoji":{"description":"Organisation emoji icon.","anyOf":[{"type":"string"},{"type":"null"}]},"memberCount":{"description":"Number of active (non-blocked) members.","type":"number"},"lastActivityAt":{"description":"Most recent member activity timestamp (ISO-8601). Falls back to the organisation inserted date when there has been no member activity yet. Drives the list ordering.","type":"string"}}}},"itemCount":{"description":"Total number of organisations matching the filter.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["name","slug","description","emoji","memberCount","lastActivityAt"],"properties":{"name":{"description":"Organisation display name.","type":"string"},"slug":{"description":"URL-friendly organisation identifier.","type":"string"},"description":{"description":"Organisation description.","anyOf":[{"type":"string"},{"type":"null"}]},"emoji":{"description":"Organisation emoji icon.","anyOf":[{"type":"string"},{"type":"null"}]},"memberCount":{"description":"Number of active (non-blocked) members.","type":"number"},"lastActivityAt":{"description":"Most recent member activity timestamp (ISO-8601). Falls back to the organisation inserted date when there has been no member activity yet. Drives the list ordering.","type":"string"}}}},"itemCount":{"description":"Total number of organisations matching the filter.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["name","slug","description","emoji","memberCount","lastActivityAt"],"properties":{"name":{"description":"Organisation display name.","type":"string"},"slug":{"description":"URL-friendly organisation identifier.","type":"string"},"description":{"description":"Organisation description.","anyOf":[{"type":"string"},{"type":"null"}]},"emoji":{"description":"Organisation emoji icon.","anyOf":[{"type":"string"},{"type":"null"}]},"memberCount":{"description":"Number of active (non-blocked) members.","type":"number"},"lastActivityAt":{"description":"Most recent member activity timestamp (ISO-8601). Falls back to the organisation inserted date when there has been no member activity yet. Drives the list ordering.","type":"string"}}}},"itemCount":{"description":"Total number of organisations matching the filter.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffAdminOrganisation-list","tags":["Admin"],"summary":"List organisations","description":"Returns a paginated list of all organisations with active member counts. Supports fulltext search by name or slug. Sorted by liveness — the latest member activity (MAX last_activity_date) descending, falling back to organisation inserted date, so active organisations float to the top and dormant ones sink. Requires internal admin membership."}},"/bff/admin/organisation-detail":{"get":{"parameters":[{"description":"Organisation slug to look up.","examples":["acme-corp"],"schema":{"type":"string"},"in":"query","name":"slug","required":true}],"operationId":"getBffAdminOrganisation-detail","tags":["Admin"],"summary":"Get organisation detail","description":"Returns full organisation record by slug. Requires internal admin membership.","responses":{"200":{}}}},"/bff/admin/member-list":{"get":{"parameters":[{"description":"Slug of the organisation to list members for.","examples":["acme-corp"],"schema":{"type":"string"},"in":"query","name":"organisationSlug","required":true}],"operationId":"getBffAdminMember-list","tags":["Admin"],"summary":"List organisation members","description":"Returns a paginated list of members for a given organisation. Supports fulltext search by name, username, or personal number. Requires internal admin membership.","responses":{"200":{}}}},"/bff/admin/member-detail":{"get":{"parameters":[{"description":"Slug of the organisation the member belongs to.","examples":["acme-corp"],"schema":{"type":"string"},"in":"query","name":"organisationSlug","required":true},{"description":"Member external ID (customer external_id).","examples":["cust_abc123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffAdminMember-detail","tags":["Admin"],"summary":"Get member detail","description":"Returns full member profile including contact info, parent member, timezone, and activity data. Requires internal admin membership.","responses":{"200":{}}}},"/bff/admin/add-member":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the member was added successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the member was added successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the member was added successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAdminAdd-member","tags":["Admin"],"summary":"Add member to organisation","description":"Creates a new membership for an existing user in the specified organisation. If the user is already a member, returns the existing membership. Sends a welcome email notification. Requires internal admin membership.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug","username"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["acme-corp"],"type":"string"},"username":{"description":"Username (email) of the user to add as a member.","examples":["john@example.com"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug","username"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["acme-corp"],"type":"string"},"username":{"description":"Username (email) of the user to add as a member.","examples":["john@example.com"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug","username"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["acme-corp"],"type":"string"},"username":{"description":"Username (email) of the user to add as a member.","examples":["john@example.com"],"type":"string"}}}}}}}},"/bff/admin/set-member-root":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation succeeded.","type":"boolean"},"hasRoot":{"description":"Resulting root state on the member.","type":"boolean"}},"required":["success","hasRoot"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation succeeded.","type":"boolean"},"hasRoot":{"description":"Resulting root state on the member.","type":"boolean"}},"required":["success","hasRoot"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation succeeded.","type":"boolean"},"hasRoot":{"description":"Resulting root state on the member.","type":"boolean"}},"required":["success","hasRoot"]}}}}},"operationId":"postBffAdminSet-member-root","tags":["Admin"],"summary":"Grant or revoke root permission on a member","description":"Additively toggles the `root` role on an organisation member. Other permissions and roles are left untouched. Triggers the standard root-grant audit log when transitioning from non-root to root. Requires internal admin membership.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug","memberId","hasRoot"],"properties":{"organisationSlug":{"description":"Slug of the organisation.","examples":["acme-corp"],"type":"string"},"memberId":{"description":"Wire member id (shop__contact.external_id). Pending invitations are not accepted.","examples":["cust_abc123"],"type":"string"},"hasRoot":{"description":"true → grant root role, false → revoke root role and any direct root permission.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug","memberId","hasRoot"],"properties":{"organisationSlug":{"description":"Slug of the organisation.","examples":["acme-corp"],"type":"string"},"memberId":{"description":"Wire member id (shop__contact.external_id). Pending invitations are not accepted.","examples":["cust_abc123"],"type":"string"},"hasRoot":{"description":"true → grant root role, false → revoke root role and any direct root permission.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug","memberId","hasRoot"],"properties":{"organisationSlug":{"description":"Slug of the organisation.","examples":["acme-corp"],"type":"string"},"memberId":{"description":"Wire member id (shop__contact.external_id). Pending invitations are not accepted.","examples":["cust_abc123"],"type":"string"},"hasRoot":{"description":"true → grant root role, false → revoke root role and any direct root permission.","type":"boolean"}}}}}}}},"/bff/admin/add-self-as-root":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation succeeded.","type":"boolean"},"memberExternalId":{"description":"External id of the member that now holds root.","type":"string"}},"required":["success","memberExternalId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation succeeded.","type":"boolean"},"memberExternalId":{"description":"External id of the member that now holds root.","type":"string"}},"required":["success","memberExternalId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation succeeded.","type":"boolean"},"memberExternalId":{"description":"External id of the member that now holds root.","type":"string"}},"required":["success","memberExternalId"]}}}}},"operationId":"postBffAdminAdd-self-as-root","tags":["Admin"],"summary":"Add the calling internal admin as a root member","description":"Self-onboards the calling operator into the target organisation with full root permissions. Idempotent for membership creation. Skips the welcome email since this is an operator action. Requires internal admin membership.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["acme-corp"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["acme-corp"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["acme-corp"],"type":"string"}}}}}}}},"/bff/admin/block-member":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the member was blocked successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the member was blocked successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the member was blocked successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffAdminBlock-member","tags":["Admin"],"summary":"Block organisation member","description":"Blocks a member by email in the specified organisation. Invalidates all their API keys and sends a notification email. Cannot block the last active member. Requires internal admin membership.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug","email"],"properties":{"organisationSlug":{"description":"Slug of the organisation.","examples":["acme-corp"],"type":"string"},"email":{"description":"Email address of the member to block.","examples":["john@example.com"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug","email"],"properties":{"organisationSlug":{"description":"Slug of the organisation.","examples":["acme-corp"],"type":"string"},"email":{"description":"Email address of the member to block.","examples":["john@example.com"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug","email"],"properties":{"organisationSlug":{"description":"Slug of the organisation.","examples":["acme-corp"],"type":"string"},"email":{"description":"Email address of the member to block.","examples":["john@example.com"],"type":"string"}}}}}}}},"/bff/admin/user-organisations":{"get":{"parameters":[{"description":"Username (email) of the user to look up.","examples":["john@example.com"],"schema":{"type":"string"},"in":"query","name":"username","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"description":"The looked-up username.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["organisationName","organisationSlug","blocked","insertedDate"],"properties":{"organisationName":{"description":"Organisation display name.","type":"string"},"organisationSlug":{"description":"Organisation slug.","type":"string"},"blocked":{"description":"Whether the membership is blocked.","type":"boolean"},"insertedDate":{"description":"Date when the user joined the organisation.","anyOf":[{"description":"Date when the user joined the organisation.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["username","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"username":{"description":"The looked-up username.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["organisationName","organisationSlug","blocked","insertedDate"],"properties":{"organisationName":{"description":"Organisation display name.","type":"string"},"organisationSlug":{"description":"Organisation slug.","type":"string"},"blocked":{"description":"Whether the membership is blocked.","type":"boolean"},"insertedDate":{"description":"Date when the user joined the organisation.","anyOf":[{"description":"Date when the user joined the organisation.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["username","items"]}},"text/plain":{"schema":{"type":"object","properties":{"username":{"description":"The looked-up username.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["organisationName","organisationSlug","blocked","insertedDate"],"properties":{"organisationName":{"description":"Organisation display name.","type":"string"},"organisationSlug":{"description":"Organisation slug.","type":"string"},"blocked":{"description":"Whether the membership is blocked.","type":"boolean"},"insertedDate":{"description":"Date when the user joined the organisation.","anyOf":[{"description":"Date when the user joined the organisation.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["username","items"]}}}}},"operationId":"getBffAdminUser-organisations","tags":["Admin"],"summary":"List user organisations","description":"Returns all organisations a user belongs to, including blocked memberships. Useful for customer support to see a user's full organisation context. Requires internal admin membership."}},"/bff/admin/system-log":{"get":{"parameters":[{"description":"Slug of the organisation to fetch logs for.","examples":["acme-corp"],"schema":{"type":"string"},"in":"query","name":"organisationSlug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","level","message","insertedDate"],"properties":{"id":{"description":"Log entry ID.","type":"number"},"level":{"description":"Log level (e.g. info, warning, error).","type":"string"},"message":{"description":"Log message.","type":"string"},"insertedDate":{"description":"Timestamp of the log entry.","type":"string"}}}},"itemCount":{"description":"Total number of log entries for this organisation.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","level","message","insertedDate"],"properties":{"id":{"description":"Log entry ID.","type":"number"},"level":{"description":"Log level (e.g. info, warning, error).","type":"string"},"message":{"description":"Log message.","type":"string"},"insertedDate":{"description":"Timestamp of the log entry.","type":"string"}}}},"itemCount":{"description":"Total number of log entries for this organisation.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","level","message","insertedDate"],"properties":{"id":{"description":"Log entry ID.","type":"number"},"level":{"description":"Log level (e.g. info, warning, error).","type":"string"},"message":{"description":"Log message.","type":"string"},"insertedDate":{"description":"Timestamp of the log entry.","type":"string"}}}},"itemCount":{"description":"Total number of log entries for this organisation.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffAdminSystem-log","tags":["Admin"],"summary":"View system log","description":"Returns a paginated system log for the specified organisation, ordered by newest first. Useful for debugging and auditing organisation activity. Requires internal admin membership."}},"/bff/admin/switch-to-organisation":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the switch was successful.","type":"boolean"},"identityId":{"description":"New identity ID after switching.","type":"string"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the switch was successful.","type":"boolean"},"identityId":{"description":"New identity ID after switching.","type":"string"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the switch was successful.","type":"boolean"},"identityId":{"description":"New identity ID after switching.","type":"string"}},"required":["success"]}}}}},"operationId":"postBffAdminSwitch-to-organisation","tags":["Admin"],"summary":"Switch to organisation","description":"Switches the admin's session context to the specified organisation. Creates a new login identity and sets an auth cookie. Useful for customer support to impersonate an organisation context. Requires internal admin membership.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the organisation to switch into.","examples":["acme-corp"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the organisation to switch into.","examples":["acme-corp"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the organisation to switch into.","examples":["acme-corp"],"type":"string"}}}}}}}},"/bff/bank-account/":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["externalId","iban","domesticLabel","displayName","bankCode","bankName","bic","source","isActive","isPrimary","isPubliclyListed","mfcrPublishedDate","mfcrLastCheckedDate","fraudHits","fraudSeverity","insertedDate","hasConnector","connectorType","connectorLastStatus","connectorLastRunDate","apiToken","lastFetchedDate","lastSyncSuccess","lastSyncErrorMessage","accountNumber","currency","openingBalance","closingBalance","dateStart","dateEnd","transactionCount","transactionsThisMonth","totalIncome","totalExpense","income30d","expense30d","matchedTransactions","unmatchedTransactions","lastTransactionDate"],"properties":{"externalId":{"description":"Stable external identifier of the bank account.","type":"string"},"iban":{"description":"Account IBAN (normalised, uppercase).","anyOf":[{"type":"string"},{"type":"null"}]},"domesticLabel":{"description":"Czech domestic representation (e.g. \"670100-2110572041/6210\"). Null for non-CZ/SK IBANs.","anyOf":[{"type":"string"},{"type":"null"}]},"displayName":{"description":"Optional user-facing label.","anyOf":[{"type":"string"},{"type":"null"}]},"bankCode":{"description":"4-digit Czech bank code.","anyOf":[{"type":"string"},{"type":"null"}]},"bankName":{"description":"Bank display name.","anyOf":[{"type":"string"},{"type":"null"}]},"bic":{"description":"Bank BIC/SWIFT.","anyOf":[{"type":"string"},{"type":"null"}]},"source":{"description":"Where the account record originated.","examples":["manual","mfcr","fio_api","gpc"],"type":"string"},"isActive":{"description":"Whether the account is active (false = soft-deleted).","type":"boolean"},"isPrimary":{"description":"Marked as the organisation primary account.","type":"boolean"},"isPubliclyListed":{"description":"True when this account is currently published in the MFCR VAT-payer registry for the organisation.","type":"boolean"},"mfcrPublishedDate":{"description":"Date the account was published in the MFCR registry (ISO date).","anyOf":[{"type":"string"},{"type":"null"}]},"mfcrLastCheckedDate":{"description":"Last time the MFCR registry was checked (ISO timestamp).","anyOf":[{"type":"string"},{"type":"null"}]},"fraudHits":{"description":"Number of active fraud-list entries linked to this normalised account.","type":"number"},"fraudSeverity":{"description":"Highest fraud severity (\"info\", \"warning\", \"critical\") or null when not on any list.","anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"description":"When the account was first added (ISO).","type":"string"},"hasConnector":{"description":"True if an active sync connector (e.g. FIO API token) is attached.","type":"boolean"},"connectorType":{"description":"Connector type, e.g. \"fio_v2\".","anyOf":[{"type":"string"},{"type":"null"}]},"connectorLastStatus":{"description":"Last connector run status (\"success\" or \"error\").","anyOf":[{"type":"string"},{"type":"null"}]},"connectorLastRunDate":{"description":"Last connector run timestamp (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"apiToken":{"description":"Masked API token (for display only).","anyOf":[{"type":"string"},{"type":"null"}]},"lastFetchedDate":{"description":"Timestamp of the last connector fetch attempt (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"lastSyncSuccess":{"description":"True when the last connector run completed without error.","type":"boolean"},"lastSyncErrorMessage":{"description":"Human-readable error message from the last failed sync.","anyOf":[{"type":"string"},{"type":"null"}]},"accountNumber":{"description":"Bank account number as reported by the connector (digits before the slash).","anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"description":"Account currency code (e.g. \"CZK\", \"EUR\").","anyOf":[{"type":"string"},{"type":"null"}]},"openingBalance":{"description":"Opening balance from the most recent synced period.","anyOf":[{"type":"number"},{"type":"null"}]},"closingBalance":{"description":"Closing balance from the most recent synced period.","anyOf":[{"type":"number"},{"type":"null"}]},"dateStart":{"description":"Start of the most recent synced period (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"dateEnd":{"description":"End of the most recent synced period (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"transactionCount":{"description":"Total number of stored transactions for this account.","type":"number"},"transactionsThisMonth":{"description":"Transactions falling within the current calendar month.","type":"number"},"totalIncome":{"description":"All-time sum of incoming payments.","type":"number"},"totalExpense":{"description":"All-time sum of outgoing payments (absolute value).","type":"number"},"income30d":{"description":"Incoming payments in the last 30 days.","type":"number"},"expense30d":{"description":"Outgoing payments in the last 30 days (absolute value).","type":"number"},"matchedTransactions":{"description":"Transactions automatically matched to an order.","type":"number"},"unmatchedTransactions":{"description":"Transactions not yet matched to any order.","type":"number"},"lastTransactionDate":{"description":"Date of the most recent transaction (ISO) or null.","anyOf":[{"type":"string"},{"type":"null"}]}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["externalId","iban","domesticLabel","displayName","bankCode","bankName","bic","source","isActive","isPrimary","isPubliclyListed","mfcrPublishedDate","mfcrLastCheckedDate","fraudHits","fraudSeverity","insertedDate","hasConnector","connectorType","connectorLastStatus","connectorLastRunDate","apiToken","lastFetchedDate","lastSyncSuccess","lastSyncErrorMessage","accountNumber","currency","openingBalance","closingBalance","dateStart","dateEnd","transactionCount","transactionsThisMonth","totalIncome","totalExpense","income30d","expense30d","matchedTransactions","unmatchedTransactions","lastTransactionDate"],"properties":{"externalId":{"description":"Stable external identifier of the bank account.","type":"string"},"iban":{"description":"Account IBAN (normalised, uppercase).","anyOf":[{"type":"string"},{"type":"null"}]},"domesticLabel":{"description":"Czech domestic representation (e.g. \"670100-2110572041/6210\"). Null for non-CZ/SK IBANs.","anyOf":[{"type":"string"},{"type":"null"}]},"displayName":{"description":"Optional user-facing label.","anyOf":[{"type":"string"},{"type":"null"}]},"bankCode":{"description":"4-digit Czech bank code.","anyOf":[{"type":"string"},{"type":"null"}]},"bankName":{"description":"Bank display name.","anyOf":[{"type":"string"},{"type":"null"}]},"bic":{"description":"Bank BIC/SWIFT.","anyOf":[{"type":"string"},{"type":"null"}]},"source":{"description":"Where the account record originated.","examples":["manual","mfcr","fio_api","gpc"],"type":"string"},"isActive":{"description":"Whether the account is active (false = soft-deleted).","type":"boolean"},"isPrimary":{"description":"Marked as the organisation primary account.","type":"boolean"},"isPubliclyListed":{"description":"True when this account is currently published in the MFCR VAT-payer registry for the organisation.","type":"boolean"},"mfcrPublishedDate":{"description":"Date the account was published in the MFCR registry (ISO date).","anyOf":[{"type":"string"},{"type":"null"}]},"mfcrLastCheckedDate":{"description":"Last time the MFCR registry was checked (ISO timestamp).","anyOf":[{"type":"string"},{"type":"null"}]},"fraudHits":{"description":"Number of active fraud-list entries linked to this normalised account.","type":"number"},"fraudSeverity":{"description":"Highest fraud severity (\"info\", \"warning\", \"critical\") or null when not on any list.","anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"description":"When the account was first added (ISO).","type":"string"},"hasConnector":{"description":"True if an active sync connector (e.g. FIO API token) is attached.","type":"boolean"},"connectorType":{"description":"Connector type, e.g. \"fio_v2\".","anyOf":[{"type":"string"},{"type":"null"}]},"connectorLastStatus":{"description":"Last connector run status (\"success\" or \"error\").","anyOf":[{"type":"string"},{"type":"null"}]},"connectorLastRunDate":{"description":"Last connector run timestamp (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"apiToken":{"description":"Masked API token (for display only).","anyOf":[{"type":"string"},{"type":"null"}]},"lastFetchedDate":{"description":"Timestamp of the last connector fetch attempt (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"lastSyncSuccess":{"description":"True when the last connector run completed without error.","type":"boolean"},"lastSyncErrorMessage":{"description":"Human-readable error message from the last failed sync.","anyOf":[{"type":"string"},{"type":"null"}]},"accountNumber":{"description":"Bank account number as reported by the connector (digits before the slash).","anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"description":"Account currency code (e.g. \"CZK\", \"EUR\").","anyOf":[{"type":"string"},{"type":"null"}]},"openingBalance":{"description":"Opening balance from the most recent synced period.","anyOf":[{"type":"number"},{"type":"null"}]},"closingBalance":{"description":"Closing balance from the most recent synced period.","anyOf":[{"type":"number"},{"type":"null"}]},"dateStart":{"description":"Start of the most recent synced period (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"dateEnd":{"description":"End of the most recent synced period (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"transactionCount":{"description":"Total number of stored transactions for this account.","type":"number"},"transactionsThisMonth":{"description":"Transactions falling within the current calendar month.","type":"number"},"totalIncome":{"description":"All-time sum of incoming payments.","type":"number"},"totalExpense":{"description":"All-time sum of outgoing payments (absolute value).","type":"number"},"income30d":{"description":"Incoming payments in the last 30 days.","type":"number"},"expense30d":{"description":"Outgoing payments in the last 30 days (absolute value).","type":"number"},"matchedTransactions":{"description":"Transactions automatically matched to an order.","type":"number"},"unmatchedTransactions":{"description":"Transactions not yet matched to any order.","type":"number"},"lastTransactionDate":{"description":"Date of the most recent transaction (ISO) or null.","anyOf":[{"type":"string"},{"type":"null"}]}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["externalId","iban","domesticLabel","displayName","bankCode","bankName","bic","source","isActive","isPrimary","isPubliclyListed","mfcrPublishedDate","mfcrLastCheckedDate","fraudHits","fraudSeverity","insertedDate","hasConnector","connectorType","connectorLastStatus","connectorLastRunDate","apiToken","lastFetchedDate","lastSyncSuccess","lastSyncErrorMessage","accountNumber","currency","openingBalance","closingBalance","dateStart","dateEnd","transactionCount","transactionsThisMonth","totalIncome","totalExpense","income30d","expense30d","matchedTransactions","unmatchedTransactions","lastTransactionDate"],"properties":{"externalId":{"description":"Stable external identifier of the bank account.","type":"string"},"iban":{"description":"Account IBAN (normalised, uppercase).","anyOf":[{"type":"string"},{"type":"null"}]},"domesticLabel":{"description":"Czech domestic representation (e.g. \"670100-2110572041/6210\"). Null for non-CZ/SK IBANs.","anyOf":[{"type":"string"},{"type":"null"}]},"displayName":{"description":"Optional user-facing label.","anyOf":[{"type":"string"},{"type":"null"}]},"bankCode":{"description":"4-digit Czech bank code.","anyOf":[{"type":"string"},{"type":"null"}]},"bankName":{"description":"Bank display name.","anyOf":[{"type":"string"},{"type":"null"}]},"bic":{"description":"Bank BIC/SWIFT.","anyOf":[{"type":"string"},{"type":"null"}]},"source":{"description":"Where the account record originated.","examples":["manual","mfcr","fio_api","gpc"],"type":"string"},"isActive":{"description":"Whether the account is active (false = soft-deleted).","type":"boolean"},"isPrimary":{"description":"Marked as the organisation primary account.","type":"boolean"},"isPubliclyListed":{"description":"True when this account is currently published in the MFCR VAT-payer registry for the organisation.","type":"boolean"},"mfcrPublishedDate":{"description":"Date the account was published in the MFCR registry (ISO date).","anyOf":[{"type":"string"},{"type":"null"}]},"mfcrLastCheckedDate":{"description":"Last time the MFCR registry was checked (ISO timestamp).","anyOf":[{"type":"string"},{"type":"null"}]},"fraudHits":{"description":"Number of active fraud-list entries linked to this normalised account.","type":"number"},"fraudSeverity":{"description":"Highest fraud severity (\"info\", \"warning\", \"critical\") or null when not on any list.","anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"description":"When the account was first added (ISO).","type":"string"},"hasConnector":{"description":"True if an active sync connector (e.g. FIO API token) is attached.","type":"boolean"},"connectorType":{"description":"Connector type, e.g. \"fio_v2\".","anyOf":[{"type":"string"},{"type":"null"}]},"connectorLastStatus":{"description":"Last connector run status (\"success\" or \"error\").","anyOf":[{"type":"string"},{"type":"null"}]},"connectorLastRunDate":{"description":"Last connector run timestamp (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"apiToken":{"description":"Masked API token (for display only).","anyOf":[{"type":"string"},{"type":"null"}]},"lastFetchedDate":{"description":"Timestamp of the last connector fetch attempt (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"lastSyncSuccess":{"description":"True when the last connector run completed without error.","type":"boolean"},"lastSyncErrorMessage":{"description":"Human-readable error message from the last failed sync.","anyOf":[{"type":"string"},{"type":"null"}]},"accountNumber":{"description":"Bank account number as reported by the connector (digits before the slash).","anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"description":"Account currency code (e.g. \"CZK\", \"EUR\").","anyOf":[{"type":"string"},{"type":"null"}]},"openingBalance":{"description":"Opening balance from the most recent synced period.","anyOf":[{"type":"number"},{"type":"null"}]},"closingBalance":{"description":"Closing balance from the most recent synced period.","anyOf":[{"type":"number"},{"type":"null"}]},"dateStart":{"description":"Start of the most recent synced period (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"dateEnd":{"description":"End of the most recent synced period (ISO).","anyOf":[{"type":"string"},{"type":"null"}]},"transactionCount":{"description":"Total number of stored transactions for this account.","type":"number"},"transactionsThisMonth":{"description":"Transactions falling within the current calendar month.","type":"number"},"totalIncome":{"description":"All-time sum of incoming payments.","type":"number"},"totalExpense":{"description":"All-time sum of outgoing payments (absolute value).","type":"number"},"income30d":{"description":"Incoming payments in the last 30 days.","type":"number"},"expense30d":{"description":"Outgoing payments in the last 30 days (absolute value).","type":"number"},"matchedTransactions":{"description":"Transactions automatically matched to an order.","type":"number"},"unmatchedTransactions":{"description":"Transactions not yet matched to any order.","type":"number"},"lastTransactionDate":{"description":"Date of the most recent transaction (ISO) or null.","anyOf":[{"type":"string"},{"type":"null"}]}}}}},"required":["items"]}}}}},"operationId":"getBffBank-account","tags":["Bank account"],"summary":"List organisation bank accounts","description":"Single source of truth for organisation bank accounts. Returns every account ever attached (active + soft-deleted), regardless of source (manual / MFCR / Fio API / GPC). Each row carries identity metadata, optional connector status, optional Fio-style live metadata (balance, sync period), and transaction analytics (counts, last 30d income/expense, match rate, last transaction date). Consumers (Settings page, Bank Transactions page) filter and sort client-side."},"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string"},"iban":{"type":"string"},"bankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"fraudHits":{"type":"array","items":{"type":"object","required":["id","source","severity","reason"],"properties":{"id":{"type":"number"},"source":{"type":"string"},"severity":{"type":"string"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}},"required":["externalId","iban","bankCode","fraudHits"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"externalId":{"type":"string"},"iban":{"type":"string"},"bankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"fraudHits":{"type":"array","items":{"type":"object","required":["id","source","severity","reason"],"properties":{"id":{"type":"number"},"source":{"type":"string"},"severity":{"type":"string"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}},"required":["externalId","iban","bankCode","fraudHits"]}},"text/plain":{"schema":{"type":"object","properties":{"externalId":{"type":"string"},"iban":{"type":"string"},"bankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"fraudHits":{"type":"array","items":{"type":"object","required":["id","source","severity","reason"],"properties":{"id":{"type":"number"},"source":{"type":"string"},"severity":{"type":"string"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}},"required":["externalId","iban","bankCode","fraudHits"]}}}}},"operationId":"postBffBank-account","tags":["Bank account"],"summary":"Add or re-activate an organisation bank account","description":"Adds a manually entered bank account. If the same IBAN is already attached to this organisation it is re-activated. Always returns fraud-list hits associated with the normalised IBAN so the UI can warn the user.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bankAccount"],"properties":{"bankAccount":{"description":"IBAN (any country) or Czech domestic format (\"670100-2110572041/6210\"). Will be normalised.","examples":["670100-2110572041/6210","CZ6520100000002901234567"],"type":"string"},"displayName":{"description":"Optional user-facing label.","type":"string"},"isPrimary":{"description":"Mark as the organisation primary account.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["bankAccount"],"properties":{"bankAccount":{"description":"IBAN (any country) or Czech domestic format (\"670100-2110572041/6210\"). Will be normalised.","examples":["670100-2110572041/6210","CZ6520100000002901234567"],"type":"string"},"displayName":{"description":"Optional user-facing label.","type":"string"},"isPrimary":{"description":"Mark as the organisation primary account.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["bankAccount"],"properties":{"bankAccount":{"description":"IBAN (any country) or Czech domestic format (\"670100-2110572041/6210\"). Will be normalised.","examples":["670100-2110572041/6210","CZ6520100000002901234567"],"type":"string"},"displayName":{"description":"Optional user-facing label.","type":"string"},"isPrimary":{"description":"Mark as the organisation primary account.","type":"boolean"}}}}}}}},"/bff/bank-account/{externalId}/update":{"post":{"parameters":[{"description":"Bank account external ID returned by the list endpoint.","schema":{"type":"string"},"in":"path","name":"externalId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBank-accountByExternalIdUpdate","tags":["Bank account"],"summary":"Update editable bank account fields","description":"Partial-update of organisation-scoped, user-editable fields on a bank account. Currently exposes `displayName`. Designed to grow safely: unspecified fields are left untouched, `null` / `\"\"` clears the value.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"description":"Custom user-facing label for the account. Empty string or null clears it (the UI will then fall back to domesticLabel / IBAN / external ID).","anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"displayName":{"description":"Custom user-facing label for the account. Empty string or null clears it (the UI will then fall back to domesticLabel / IBAN / external ID).","anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","properties":{"displayName":{"description":"Custom user-facing label for the account. Empty string or null clears it (the UI will then fall back to domesticLabel / IBAN / external ID).","anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/bank-account/{externalId}":{"delete":{"parameters":[{"description":"Bank account external ID returned by the list endpoint.","schema":{"type":"string"},"in":"path","name":"externalId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"deleteBffBank-accountByExternalId","tags":["Bank account"],"summary":"Soft-delete a bank account","description":"Marks the account inactive and disables any attached sync connectors. The row is preserved."}},"/bff/bank-account/sync-mfcr":{"post":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"vatNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"imported":{"type":"number"},"matched":{"type":"number"},"errors":{"type":"array","items":{"type":"string"}}},"required":["vatNumber","imported","matched","errors"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"vatNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"imported":{"type":"number"},"matched":{"type":"number"},"errors":{"type":"array","items":{"type":"string"}}},"required":["vatNumber","imported","matched","errors"]}},"text/plain":{"schema":{"type":"object","properties":{"vatNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"imported":{"type":"number"},"matched":{"type":"number"},"errors":{"type":"array","items":{"type":"string"}}},"required":["vatNumber","imported","matched","errors"]}}}}},"operationId":"postBffBank-accountSync-mfcr","tags":["Bank account"],"summary":"Sync MFCR-published bank accounts","description":"Calls the Czech tax authority (MFCR) registr plátců DPH SOAP API for the organisation's DIČ and imports any officially published bank accounts. Updates the publicly-listed flag on existing accounts. No-op when the organisation has no DIČ or is not a VAT payer."}},"/bff/ai/question":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"answer":{"description":"The AI-generated response text","type":"string"}},"required":["answer"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"answer":{"description":"The AI-generated response text","type":"string"}},"required":["answer"]}},"text/plain":{"schema":{"type":"object","properties":{"answer":{"description":"The AI-generated response text","type":"string"}},"required":["answer"]}}}}},"operationId":"postBffAiQuestion","tags":["bff"],"summary":"Ask AI a question and get a complete response","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["question"],"properties":{"question":{"description":"The question or prompt to send to the AI model","examples":["What is the capital of France?"],"type":"string"},"model":{"description":"AI model identifier (e.g. \"gpt-5-mini\", \"claude-sonnet-4-20250514\"). Defaults to gpt-5-mini","examples":["gpt-5-mini"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["question"],"properties":{"question":{"description":"The question or prompt to send to the AI model","examples":["What is the capital of France?"],"type":"string"},"model":{"description":"AI model identifier (e.g. \"gpt-5-mini\", \"claude-sonnet-4-20250514\"). Defaults to gpt-5-mini","examples":["gpt-5-mini"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["question"],"properties":{"question":{"description":"The question or prompt to send to the AI model","examples":["What is the capital of France?"],"type":"string"},"model":{"description":"AI model identifier (e.g. \"gpt-5-mini\", \"claude-sonnet-4-20250514\"). Defaults to gpt-5-mini","examples":["gpt-5-mini"],"type":"string"}}}}}}}},"/bff/ai/question-stream":{"post":{"parameters":[],"operationId":"postBffAiQuestion-stream","tags":["bff"],"summary":"Ask AI a question with SSE streaming response","description":"Returns a Server-Sent Events stream. Events: \"token\" ({ text }) for partial chunks, \"done\" ({ answer }) for the complete response, \"error\" ({ message }) on failure.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["question"],"properties":{"question":{"description":"The question or prompt to send to the AI model","examples":["What is the capital of France?"],"type":"string"},"model":{"description":"AI model identifier (e.g. \"gpt-5-mini\", \"claude-sonnet-4-20250514\"). Defaults to gpt-5-mini","examples":["gpt-5-mini"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["question"],"properties":{"question":{"description":"The question or prompt to send to the AI model","examples":["What is the capital of France?"],"type":"string"},"model":{"description":"AI model identifier (e.g. \"gpt-5-mini\", \"claude-sonnet-4-20250514\"). Defaults to gpt-5-mini","examples":["gpt-5-mini"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["question"],"properties":{"question":{"description":"The question or prompt to send to the AI model","examples":["What is the capital of France?"],"type":"string"},"model":{"description":"AI model identifier (e.g. \"gpt-5-mini\", \"claude-sonnet-4-20250514\"). Defaults to gpt-5-mini","examples":["gpt-5-mini"],"type":"string"}}}}}},"responses":{"200":{}}}},"/bff/ai/test":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"answer":{"description":"The AI-generated response text","type":"string"}},"required":["answer"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"answer":{"description":"The AI-generated response text","type":"string"}},"required":["answer"]}},"text/plain":{"schema":{"type":"object","properties":{"answer":{"description":"The AI-generated response text","type":"string"}},"required":["answer"]}}}}},"operationId":"getBffAiTest","tags":["bff"],"summary":"Test AI connectivity with a sample question"}},"/bff/analytics/category-list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","title","color","bgColor","analytics"],"properties":{"id":{"description":"Category identifier.","type":"string"},"title":{"description":"Category title.","type":"string"},"description":{"type":"string"},"color":{"description":"Tailwind text color class.","type":"string"},"bgColor":{"description":"Tailwind background color class.","type":"string"},"analytics":{"type":"array","items":{"type":"object","required":["slug","name"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"popular":{"type":"boolean"}}}}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","title","color","bgColor","analytics"],"properties":{"id":{"description":"Category identifier.","type":"string"},"title":{"description":"Category title.","type":"string"},"description":{"type":"string"},"color":{"description":"Tailwind text color class.","type":"string"},"bgColor":{"description":"Tailwind background color class.","type":"string"},"analytics":{"type":"array","items":{"type":"object","required":["slug","name"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"popular":{"type":"boolean"}}}}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","title","color","bgColor","analytics"],"properties":{"id":{"description":"Category identifier.","type":"string"},"title":{"description":"Category title.","type":"string"},"description":{"type":"string"},"color":{"description":"Tailwind text color class.","type":"string"},"bgColor":{"description":"Tailwind background color class.","type":"string"},"analytics":{"type":"array","items":{"type":"object","required":["slug","name"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"popular":{"type":"boolean"}}}}}}}},"required":["items"]}}}}},"operationId":"getBffAnalyticsCategory-list","tags":["Analytics"],"summary":"List analytics categories","description":"Returns analytics categories with reports the caller has permission to read. Empty categories are pruned."}},"/bff/analytics/detail":{"get":{"parameters":[{"description":"Report slug.","examples":["sales-daily-revenue"],"schema":{"type":"string"},"in":"query","name":"slug","required":true},{"examples":["cs","en"],"schema":{"type":"string"},"in":"query","name":"locale","required":false},{"schema":{"minimum":1,"default":1,"anyOf":[{"format":"numeric","default":0,"type":"string"},{"minimum":1,"default":1,"type":"number"}]},"in":"query","name":"page","required":false},{"schema":{"minimum":1,"maximum":500,"default":50,"anyOf":[{"format":"numeric","default":0,"type":"string"},{"minimum":1,"maximum":500,"default":50,"type":"number"}]},"in":"query","name":"pageSize","required":false},{"schema":{"type":"string"},"in":"query","name":"sortBy","required":false},{"schema":{"anyOf":[{"const":"asc","type":"string"},{"const":"desc","type":"string"}]},"in":"query","name":"sortDir","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"headerLabels":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"rows":{"type":"array","items":{}},"columns":{"type":"array","items":{}},"kpis":{"type":"array","items":{}},"chart":{},"pagination":{"type":"object","required":["page","pageSize","total"],"properties":{"page":{"type":"number"},"pageSize":{"type":"number"},"total":{"type":"number"}}},"meta":{"type":"object","required":["generatedAt"],"properties":{"generatedAt":{"type":"string"},"cached":{"type":"boolean"},"truncated":{"type":"boolean"}}}},"required":["slug","headerLabels","rows","pagination","meta"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"headerLabels":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"rows":{"type":"array","items":{}},"columns":{"type":"array","items":{}},"kpis":{"type":"array","items":{}},"chart":{},"pagination":{"type":"object","required":["page","pageSize","total"],"properties":{"page":{"type":"number"},"pageSize":{"type":"number"},"total":{"type":"number"}}},"meta":{"type":"object","required":["generatedAt"],"properties":{"generatedAt":{"type":"string"},"cached":{"type":"boolean"},"truncated":{"type":"boolean"}}}},"required":["slug","headerLabels","rows","pagination","meta"]}},"text/plain":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"headerLabels":{"type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"rows":{"type":"array","items":{}},"columns":{"type":"array","items":{}},"kpis":{"type":"array","items":{}},"chart":{},"pagination":{"type":"object","required":["page","pageSize","total"],"properties":{"page":{"type":"number"},"pageSize":{"type":"number"},"total":{"type":"number"}}},"meta":{"type":"object","required":["generatedAt"],"properties":{"generatedAt":{"type":"string"},"cached":{"type":"boolean"},"truncated":{"type":"boolean"}}}},"required":["slug","headerLabels","rows","pagination","meta"]}}}}},"operationId":"getBffAnalyticsDetail","tags":["Analytics"],"summary":"Get analytics report detail","description":"Runs a specific analytics report. Supports per-report query params, pagination, sorting and free-text search. Permission is checked per report."}},"/bff/api-key/list":{"get":{"responses":{"200":{"description":"List of API keys with metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of API keys.","type":"array","items":{"description":"Single API key item.","type":"object","required":["id","apiKey","environment","usedCountToday","isActive","isDeleted","expirationDate","insertedDate"],"properties":{"id":{"description":"External identifier (UUID) of the API key.","type":"string"},"apiKey":{"description":"Masked API key value (shows first 10 chars, rest masked).","type":"string"},"environment":{"description":"Environment type: \"PROD\" for production, \"DEV\" for development/sandbox, \"ROOT\" for system-level access.","anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"usedCountToday":{"description":"Number of API calls made with this key today.","type":"number"},"member":{"description":"Member information if key is member-specific.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the member this key is assigned to.","type":"string"}}},"isActive":{"description":"Whether the key is currently active and can be used.","type":"boolean"},"isDeleted":{"description":"Whether the key has been deleted (invalidated).","type":"boolean"},"description":{"description":"Human-readable description of the key purpose.","type":"string"},"expirationDate":{"description":"Date when the key will expire and become unusable.","anyOf":[{"description":"Date when the key will expire and become unusable.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the key was created.","anyOf":[{"description":"Date when the key was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of API keys.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of API keys.","type":"array","items":{"description":"Single API key item.","type":"object","required":["id","apiKey","environment","usedCountToday","isActive","isDeleted","expirationDate","insertedDate"],"properties":{"id":{"description":"External identifier (UUID) of the API key.","type":"string"},"apiKey":{"description":"Masked API key value (shows first 10 chars, rest masked).","type":"string"},"environment":{"description":"Environment type: \"PROD\" for production, \"DEV\" for development/sandbox, \"ROOT\" for system-level access.","anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"usedCountToday":{"description":"Number of API calls made with this key today.","type":"number"},"member":{"description":"Member information if key is member-specific.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the member this key is assigned to.","type":"string"}}},"isActive":{"description":"Whether the key is currently active and can be used.","type":"boolean"},"isDeleted":{"description":"Whether the key has been deleted (invalidated).","type":"boolean"},"description":{"description":"Human-readable description of the key purpose.","type":"string"},"expirationDate":{"description":"Date when the key will expire and become unusable.","anyOf":[{"description":"Date when the key will expire and become unusable.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the key was created.","anyOf":[{"description":"Date when the key was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of API keys.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of API keys.","type":"array","items":{"description":"Single API key item.","type":"object","required":["id","apiKey","environment","usedCountToday","isActive","isDeleted","expirationDate","insertedDate"],"properties":{"id":{"description":"External identifier (UUID) of the API key.","type":"string"},"apiKey":{"description":"Masked API key value (shows first 10 chars, rest masked).","type":"string"},"environment":{"description":"Environment type: \"PROD\" for production, \"DEV\" for development/sandbox, \"ROOT\" for system-level access.","anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"usedCountToday":{"description":"Number of API calls made with this key today.","type":"number"},"member":{"description":"Member information if key is member-specific.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the member this key is assigned to.","type":"string"}}},"isActive":{"description":"Whether the key is currently active and can be used.","type":"boolean"},"isDeleted":{"description":"Whether the key has been deleted (invalidated).","type":"boolean"},"description":{"description":"Human-readable description of the key purpose.","type":"string"},"expirationDate":{"description":"Date when the key will expire and become unusable.","anyOf":[{"description":"Date when the key will expire and become unusable.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the key was created.","anyOf":[{"description":"Date when the key was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of API keys.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffApi-keyList","tags":["API Key"],"summary":"List API keys","description":"Returns a list of all API keys for the organisation. Each key includes basic information, masked key value, environment, description, and expiration date. Active and deleted keys are both included - use the isDeleted flag to filter."}},"/bff/api-key/detail":{"get":{"parameters":[{"description":"External identifier (UUID) of the API key.","examples":["550e8400-e29b-41d4-a716-446655440000"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"description":"Complete API key detail with metadata, ownership information, and usage statistics. Includes all information about the key including when it was created, when it expires, who owns it, and detailed usage history.","content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"description":"External identifier (UUID) of the API key.","type":"string"},"apiKey":{"description":"Masked API key value (shows first 10 chars, rest masked).","type":"string"},"environment":{"description":"Environment type: PROD for production, DEV for development, ROOT for system-level access.","anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"description":{"description":"Human-readable description of the key purpose. Null if not set.","anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"description":"Whether the key is currently active and can be used for API requests.","type":"boolean"},"isDeleted":{"description":"Whether the key has been deleted/invalidated. Deleted keys cannot be used.","type":"boolean"},"insertedDate":{"description":"Date and time when the API key was created.","anyOf":[{"description":"Date and time when the API key was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"description":"Date and time when the key will expire and become unusable.","anyOf":[{"description":"Date and time when the key will expire and become unusable.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"member":{"description":"Member information if key is member-specific. Undefined for organisation-wide keys.","type":"object","required":["id","name"],"properties":{"id":{"description":"Internal member ID.","type":"number"},"name":{"description":"Full name of the member this key is assigned to.","type":"string"}}},"usedCountToday":{"description":"Number of API calls made with this key today.","type":"number"},"usedCountTotal":{"description":"Total number of days this key has been used (including today).","type":"number"},"usedSumTotal":{"description":"Total number of API calls made with this key (all time).","type":"number"},"usageList":{"description":"Daily usage history for the last 90 days, ordered by date (newest first). Can be used to generate usage charts.","type":"array","items":{"description":"Daily usage record.","type":"object","required":["date","count"],"properties":{"date":{"description":"Date of usage.","anyOf":[{"description":"Date of usage.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"count":{"description":"Number of API calls made on this date.","type":"number"}}}},"scopes":{"description":"List of scope codes assigned to this key. Empty array means full access (no restrictions).","type":"array","items":{"type":"string"}}},"required":["externalId","apiKey","environment","description","isActive","isDeleted","insertedDate","expirationDate","usedCountToday","usedCountTotal","usedSumTotal","usageList","scopes"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"externalId":{"description":"External identifier (UUID) of the API key.","type":"string"},"apiKey":{"description":"Masked API key value (shows first 10 chars, rest masked).","type":"string"},"environment":{"description":"Environment type: PROD for production, DEV for development, ROOT for system-level access.","anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"description":{"description":"Human-readable description of the key purpose. Null if not set.","anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"description":"Whether the key is currently active and can be used for API requests.","type":"boolean"},"isDeleted":{"description":"Whether the key has been deleted/invalidated. Deleted keys cannot be used.","type":"boolean"},"insertedDate":{"description":"Date and time when the API key was created.","anyOf":[{"description":"Date and time when the API key was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"description":"Date and time when the key will expire and become unusable.","anyOf":[{"description":"Date and time when the key will expire and become unusable.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"member":{"description":"Member information if key is member-specific. Undefined for organisation-wide keys.","type":"object","required":["id","name"],"properties":{"id":{"description":"Internal member ID.","type":"number"},"name":{"description":"Full name of the member this key is assigned to.","type":"string"}}},"usedCountToday":{"description":"Number of API calls made with this key today.","type":"number"},"usedCountTotal":{"description":"Total number of days this key has been used (including today).","type":"number"},"usedSumTotal":{"description":"Total number of API calls made with this key (all time).","type":"number"},"usageList":{"description":"Daily usage history for the last 90 days, ordered by date (newest first). Can be used to generate usage charts.","type":"array","items":{"description":"Daily usage record.","type":"object","required":["date","count"],"properties":{"date":{"description":"Date of usage.","anyOf":[{"description":"Date of usage.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"count":{"description":"Number of API calls made on this date.","type":"number"}}}},"scopes":{"description":"List of scope codes assigned to this key. Empty array means full access (no restrictions).","type":"array","items":{"type":"string"}}},"required":["externalId","apiKey","environment","description","isActive","isDeleted","insertedDate","expirationDate","usedCountToday","usedCountTotal","usedSumTotal","usageList","scopes"]}},"text/plain":{"schema":{"type":"object","properties":{"externalId":{"description":"External identifier (UUID) of the API key.","type":"string"},"apiKey":{"description":"Masked API key value (shows first 10 chars, rest masked).","type":"string"},"environment":{"description":"Environment type: PROD for production, DEV for development, ROOT for system-level access.","anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"description":{"description":"Human-readable description of the key purpose. Null if not set.","anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"description":"Whether the key is currently active and can be used for API requests.","type":"boolean"},"isDeleted":{"description":"Whether the key has been deleted/invalidated. Deleted keys cannot be used.","type":"boolean"},"insertedDate":{"description":"Date and time when the API key was created.","anyOf":[{"description":"Date and time when the API key was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"expirationDate":{"description":"Date and time when the key will expire and become unusable.","anyOf":[{"description":"Date and time when the key will expire and become unusable.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"member":{"description":"Member information if key is member-specific. Undefined for organisation-wide keys.","type":"object","required":["id","name"],"properties":{"id":{"description":"Internal member ID.","type":"number"},"name":{"description":"Full name of the member this key is assigned to.","type":"string"}}},"usedCountToday":{"description":"Number of API calls made with this key today.","type":"number"},"usedCountTotal":{"description":"Total number of days this key has been used (including today).","type":"number"},"usedSumTotal":{"description":"Total number of API calls made with this key (all time).","type":"number"},"usageList":{"description":"Daily usage history for the last 90 days, ordered by date (newest first). Can be used to generate usage charts.","type":"array","items":{"description":"Daily usage record.","type":"object","required":["date","count"],"properties":{"date":{"description":"Date of usage.","anyOf":[{"description":"Date of usage.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"count":{"description":"Number of API calls made on this date.","type":"number"}}}},"scopes":{"description":"List of scope codes assigned to this key. Empty array means full access (no restrictions).","type":"array","items":{"type":"string"}}},"required":["externalId","apiKey","environment","description","isActive","isDeleted","insertedDate","expirationDate","usedCountToday","usedCountTotal","usedSumTotal","usageList","scopes"]}}}}},"operationId":"getBffApi-keyDetail","tags":["API Key"],"summary":"Get API key detail with usage statistics","description":"Returns detailed information about a specific API key including usage statistics. Shows the masked key value, total usage count, total API calls made, and daily usage history for the last 90 days. Useful for monitoring API key usage and identifying patterns."}},"/bff/api-key/generate-key":{"post":{"parameters":[],"responses":{"200":{"description":"Newly generated API key.","content":{"application/json":{"schema":{"type":"object","properties":{"apiKey":{"description":"The generated API key (32 character string). IMPORTANT: Store this securely - it will not be shown again.","type":"string"}},"required":["apiKey"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"apiKey":{"description":"The generated API key (32 character string). IMPORTANT: Store this securely - it will not be shown again.","type":"string"}},"required":["apiKey"]}},"text/plain":{"schema":{"type":"object","properties":{"apiKey":{"description":"The generated API key (32 character string). IMPORTANT: Store this securely - it will not be shown again.","type":"string"}},"required":["apiKey"]}}}}},"operationId":"postBffApi-keyGenerate-key","tags":["API Key"],"summary":"Generate new API key","description":"Creates a new API key for programmatic access to the API. The key is a random 32-character string that must be included in API requests. Keys can be organisation-wide or member-specific, and are associated with an environment (production, sandbox, or test). Store the returned key securely - it cannot be retrieved later, only viewed in masked form.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["environment"],"properties":{"environment":{"description":"Environment for the key: \"PROD\" for production, \"DEV\" for development/sandbox, \"ROOT\" for system-level access.","examples":["PROD"],"anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"relatedToMember":{"description":"Whether to associate this key with the current member. If true, key is member-specific.","type":"boolean"},"description":{"description":"Human-readable description of the key purpose (e.g., \"Mobile app integration\", \"Partner API access\").","examples":["Mobile app integration"],"type":"string"},"expirationDate":{"description":"Expiration date in ISO format (YYYY-MM-DD). If not provided, key expires in 90 days from creation.","examples":["2026-07-18"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["environment"],"properties":{"environment":{"description":"Environment for the key: \"PROD\" for production, \"DEV\" for development/sandbox, \"ROOT\" for system-level access.","examples":["PROD"],"anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"relatedToMember":{"description":"Whether to associate this key with the current member. If true, key is member-specific.","type":"boolean"},"description":{"description":"Human-readable description of the key purpose (e.g., \"Mobile app integration\", \"Partner API access\").","examples":["Mobile app integration"],"type":"string"},"expirationDate":{"description":"Expiration date in ISO format (YYYY-MM-DD). If not provided, key expires in 90 days from creation.","examples":["2026-07-18"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["environment"],"properties":{"environment":{"description":"Environment for the key: \"PROD\" for production, \"DEV\" for development/sandbox, \"ROOT\" for system-level access.","examples":["PROD"],"anyOf":[{"const":"PROD","type":"string"},{"const":"DEV","type":"string"},{"const":"ROOT","type":"string"}]},"relatedToMember":{"description":"Whether to associate this key with the current member. If true, key is member-specific.","type":"boolean"},"description":{"description":"Human-readable description of the key purpose (e.g., \"Mobile app integration\", \"Partner API access\").","examples":["Mobile app integration"],"type":"string"},"expirationDate":{"description":"Expiration date in ISO format (YYYY-MM-DD). If not provided, key expires in 90 days from creation.","examples":["2026-07-18"],"type":"string"}}}}}}}},"/bff/api-key/invalidate-key":{"post":{"parameters":[],"responses":{"200":{"description":"Key invalidated successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffApi-keyInvalidate-key","tags":["API Key"],"summary":"Invalidate API key","description":"Marks an API key as deleted, making it immediately unusable for API requests. This action is permanent and cannot be undone. The key will still appear in the list but with isDeleted: true. Use this when a key has been compromised or is no longer needed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External identifier (UUID) of the API key to invalidate.","examples":["550e8400-e29b-41d4-a716-446655440000"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External identifier (UUID) of the API key to invalidate.","examples":["550e8400-e29b-41d4-a716-446655440000"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External identifier (UUID) of the API key to invalidate.","examples":["550e8400-e29b-41d4-a716-446655440000"],"type":"string"}}}}}}}},"/bff/api-key/scope/list":{"get":{"responses":{"200":{"description":"List of available API key scopes.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of available scopes.","type":"array","items":{"type":"object","required":["code","label","description"],"properties":{"code":{"description":"Scope code used for assignment.","type":"string"},"label":{"description":"Human-readable label for the scope.","type":"string"},"description":{"description":"Description of what the scope grants access to.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of available scopes.","type":"array","items":{"type":"object","required":["code","label","description"],"properties":{"code":{"description":"Scope code used for assignment.","type":"string"},"label":{"description":"Human-readable label for the scope.","type":"string"},"description":{"description":"Description of what the scope grants access to.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of available scopes.","type":"array","items":{"type":"object","required":["code","label","description"],"properties":{"code":{"description":"Scope code used for assignment.","type":"string"},"label":{"description":"Human-readable label for the scope.","type":"string"},"description":{"description":"Description of what the scope grants access to.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffApi-keyScopeList","tags":["API Key"],"summary":"List available API key scopes","description":"Returns a list of all available scope codes that can be assigned to an API key. Use these codes when setting scopes via the /scope/set endpoint."}},"/bff/api-key/scope/detail":{"get":{"parameters":[{"description":"External identifier (UUID) of the API key.","examples":["550e8400-e29b-41d4-a716-446655440000"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"description":"Scopes assigned to the API key.","content":{"application/json":{"schema":{"type":"object","properties":{"scopes":{"description":"Array of scope codes assigned to this key. Empty means full access.","type":"array","items":{"type":"string"}}},"required":["scopes"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"scopes":{"description":"Array of scope codes assigned to this key. Empty means full access.","type":"array","items":{"type":"string"}}},"required":["scopes"]}},"text/plain":{"schema":{"type":"object","properties":{"scopes":{"description":"Array of scope codes assigned to this key. Empty means full access.","type":"array","items":{"type":"string"}}},"required":["scopes"]}}}}},"operationId":"getBffApi-keyScopeDetail","tags":["API Key"],"summary":"Get scopes assigned to an API key","description":"Returns a list of scope codes currently assigned to the specified API key. An empty array means the key has full access (no scope restrictions)."}},"/bff/api-key/scope/set":{"post":{"parameters":[],"responses":{"200":{"description":"Scopes updated successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffApi-keyScopeSet","tags":["API Key"],"summary":"Set API key scopes","description":"Replaces all scopes assigned to an API key. Pass an empty array to remove all scope restrictions (key gets full access). Only valid scope codes from /scope/list are accepted.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","scopes"],"properties":{"id":{"description":"External identifier (UUID) of the API key.","examples":["550e8400-e29b-41d4-a716-446655440000"],"type":"string"},"scopes":{"description":"Array of scope codes to assign. Empty array removes all restrictions (full access).","type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","scopes"],"properties":{"id":{"description":"External identifier (UUID) of the API key.","examples":["550e8400-e29b-41d4-a716-446655440000"],"type":"string"},"scopes":{"description":"Array of scope codes to assign. Empty array removes all restrictions (full access).","type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["id","scopes"],"properties":{"id":{"description":"External identifier (UUID) of the API key.","examples":["550e8400-e29b-41d4-a716-446655440000"],"type":"string"},"scopes":{"description":"Array of scope codes to assign. Empty array removes all restrictions (full access).","type":"array","items":{"type":"string"}}}}}}}}},"/bff/blob/upload":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"blobToken":{"description":"Token to reference the uploaded blob.","examples":["blb_abc123xyz"],"type":"string"}},"required":["blobToken"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"blobToken":{"description":"Token to reference the uploaded blob.","examples":["blb_abc123xyz"],"type":"string"}},"required":["blobToken"]}},"text/plain":{"schema":{"type":"object","properties":{"blobToken":{"description":"Token to reference the uploaded blob.","examples":["blb_abc123xyz"],"type":"string"}},"required":["blobToken"]}}}}},"operationId":"postBffBlobUpload","tags":["Blob"],"summary":"Upload a file","description":"Uploads a file via multipart/form-data. The request body must contain a \"file\" field with the binary data, an optional \"blobPath\" for storage path prefix, and an optional \"tag\" for categorization. Returns a blob token for referencing the uploaded file.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["file"],"properties":{"file":{"default":"File","description":"Binary file payload.","type":"string","format":"binary"},"blobPath":{"description":"Optional storage path prefix.","examples":["post/N195wg3F34tFierY"],"type":"string"},"tag":{"description":"Optional categorization tag.","examples":["post"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"default":"File","description":"Binary file payload.","type":"string","format":"binary"},"blobPath":{"description":"Optional storage path prefix.","examples":["post/N195wg3F34tFierY"],"type":"string"},"tag":{"description":"Optional categorization tag.","examples":["post"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["file"],"properties":{"file":{"default":"File","description":"Binary file payload.","type":"string","format":"binary"},"blobPath":{"description":"Optional storage path prefix.","examples":["post/N195wg3F34tFierY"],"type":"string"},"tag":{"description":"Optional categorization tag.","examples":["post"],"type":"string"}}}}}}}},"/bff/blob/upload-user-avatar":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBlobUpload-user-avatar","tags":["Blob"],"summary":"Upload user avatar","description":"Uploads an image file as the current user's avatar via multipart/form-data. Only image content types are accepted. The request body must contain \"file\" and \"blobPath\" fields.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["file","blobPath"],"properties":{"file":{"default":"File","description":"Image binary to use as the avatar.","type":"string","format":"binary"},"blobPath":{"description":"Storage path prefix.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["file","blobPath"],"properties":{"file":{"default":"File","description":"Image binary to use as the avatar.","type":"string","format":"binary"},"blobPath":{"description":"Storage path prefix.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["file","blobPath"],"properties":{"file":{"default":"File","description":"Image binary to use as the avatar.","type":"string","format":"binary"},"blobPath":{"description":"Storage path prefix.","type":"string"}}}}}}}},"/bff/blob/viewer":{"get":{"parameters":[{"description":"Blob token identifying the file to view.","examples":["blb_abc123xyz"],"schema":{"type":"string"},"in":"query","name":"token","required":true}],"operationId":"getBffBlobViewer","tags":["Blob"],"summary":"View/download a blob","description":"Proxies the blob content as a binary response with appropriate Content-Type header. Returns the raw file bytes — response schema is not typed as the content type varies (images, PDFs, etc.).","responses":{"200":{}}}},"/bff/branch/list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","slug","name","active","openingHoursRegular","branchType","insertedDate","updatedDate"],"properties":{"id":{"description":"Branch slug (used as identifier in other endpoints).","type":"string"},"slug":{"description":"URL-safe unique branch slug.","type":"string"},"name":{"description":"Branch display name.","type":"string"},"description":{"description":"Short branch description.","type":"string"},"internalCode":{"description":"Organisation-internal branch code.","type":"string"},"active":{"description":"Whether the branch is active and visible.","type":"boolean"},"url":{"description":"Branch public URL.","type":"string"},"latitude":{"description":"Branch GPS latitude.","type":"number"},"longitude":{"description":"Branch GPS longitude.","type":"number"},"mainPhotoUrl":{"description":"URL of the main photo.","type":"string"},"addressSummary":{"description":"Short rendered address (street, ZIP, city).","type":"string"},"openingHoursRegular":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition","active"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday … 6 = Sunday.","type":"number"},"definition":{"description":"Time-range definition, e.g. \"08:00-17:00\".","type":"string"},"active":{"type":"boolean"}}}},"openingHoursExceptionToday":{"type":"object","required":["isOpen"],"properties":{"isOpen":{"type":"boolean"},"reason":{"type":"string"}}},"branchType":{"description":"Branch kind. Defaults to \"own\" for historical rows.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranchSlug":{"description":"Slug of the operational parent branch, if any.","type":"string"},"operatingCompanyName":{"description":"Display name of the legal entity operating this branch. Doubles as the franchise brand label.","type":"string"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update date.","anyOf":[{"description":"Last update date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of branches matching the query.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","slug","name","active","openingHoursRegular","branchType","insertedDate","updatedDate"],"properties":{"id":{"description":"Branch slug (used as identifier in other endpoints).","type":"string"},"slug":{"description":"URL-safe unique branch slug.","type":"string"},"name":{"description":"Branch display name.","type":"string"},"description":{"description":"Short branch description.","type":"string"},"internalCode":{"description":"Organisation-internal branch code.","type":"string"},"active":{"description":"Whether the branch is active and visible.","type":"boolean"},"url":{"description":"Branch public URL.","type":"string"},"latitude":{"description":"Branch GPS latitude.","type":"number"},"longitude":{"description":"Branch GPS longitude.","type":"number"},"mainPhotoUrl":{"description":"URL of the main photo.","type":"string"},"addressSummary":{"description":"Short rendered address (street, ZIP, city).","type":"string"},"openingHoursRegular":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition","active"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday … 6 = Sunday.","type":"number"},"definition":{"description":"Time-range definition, e.g. \"08:00-17:00\".","type":"string"},"active":{"type":"boolean"}}}},"openingHoursExceptionToday":{"type":"object","required":["isOpen"],"properties":{"isOpen":{"type":"boolean"},"reason":{"type":"string"}}},"branchType":{"description":"Branch kind. Defaults to \"own\" for historical rows.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranchSlug":{"description":"Slug of the operational parent branch, if any.","type":"string"},"operatingCompanyName":{"description":"Display name of the legal entity operating this branch. Doubles as the franchise brand label.","type":"string"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update date.","anyOf":[{"description":"Last update date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of branches matching the query.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","slug","name","active","openingHoursRegular","branchType","insertedDate","updatedDate"],"properties":{"id":{"description":"Branch slug (used as identifier in other endpoints).","type":"string"},"slug":{"description":"URL-safe unique branch slug.","type":"string"},"name":{"description":"Branch display name.","type":"string"},"description":{"description":"Short branch description.","type":"string"},"internalCode":{"description":"Organisation-internal branch code.","type":"string"},"active":{"description":"Whether the branch is active and visible.","type":"boolean"},"url":{"description":"Branch public URL.","type":"string"},"latitude":{"description":"Branch GPS latitude.","type":"number"},"longitude":{"description":"Branch GPS longitude.","type":"number"},"mainPhotoUrl":{"description":"URL of the main photo.","type":"string"},"addressSummary":{"description":"Short rendered address (street, ZIP, city).","type":"string"},"openingHoursRegular":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition","active"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday … 6 = Sunday.","type":"number"},"definition":{"description":"Time-range definition, e.g. \"08:00-17:00\".","type":"string"},"active":{"type":"boolean"}}}},"openingHoursExceptionToday":{"type":"object","required":["isOpen"],"properties":{"isOpen":{"type":"boolean"},"reason":{"type":"string"}}},"branchType":{"description":"Branch kind. Defaults to \"own\" for historical rows.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranchSlug":{"description":"Slug of the operational parent branch, if any.","type":"string"},"operatingCompanyName":{"description":"Display name of the legal entity operating this branch. Doubles as the franchise brand label.","type":"string"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update date.","anyOf":[{"description":"Last update date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of branches matching the query.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffBranchList","tags":["Branch"],"description":"Returns a paginated list of branches for the authenticated organisation. Branches are ordered by active status first, then by name ascending. Supports fulltext filter on name, slug, internal code and city.","summary":"List branches"}},"/bff/branch/detail":{"get":{"parameters":[{"description":"Branch slug.","examples":["prague-central"],"schema":{"type":"string"},"in":"query","name":"slug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"internalCode":{"type":"string"},"active":{"type":"boolean"},"url":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"branchContact":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"CuRefNo of the linked contact.","type":"string"},"name":{"type":"string"},"email":{"type":"string"},"companyName":{"type":"string"}}},"branchType":{"description":"Branch kind declared by the operator. \"own\" = the organisation runs the branch directly; \"franchise\" = a third-party franchisee runs it under the organisation's brand; \"partner\" = a cooperating but independent business (e.g. white-label outlet).","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranch":{"type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the operational parent (regional flagship / HQ).","type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]}}},"operatingCompany":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"CuRefNo of the legal entity operating this branch.","type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"description":"Czech IČO (or local equivalent).","type":"string"},"taxIdentificationNumber":{"description":"Czech DIČ (or local equivalent).","type":"string"}}},"people":{"type":"array","items":{"type":"object","required":["id","contactId","role","position"],"properties":{"id":{"description":"Internal id of the link row (used to update/remove).","type":"string"},"contactId":{"description":"CuRefNo of the linked contact.","type":"string"},"role":{"description":"Role enum — see BRANCH_PERSON_ROLES.","type":"string"},"customLabel":{"description":"Free-text label that overrides the role display.","type":"string"},"position":{"description":"Sort position.","type":"number"},"name":{"type":"string"},"email":{"type":"string"},"companyName":{"type":"string"}}}},"establishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"termsAndConditions":{"description":"Terms & Conditions (VOP), Markdown source.","type":"string"},"complaintsProcedure":{"description":"Complaints procedure (Reklamační řád), Markdown source.","type":"string"},"privacyPolicy":{"description":"Privacy policy (GDPR), Markdown source.","type":"string"},"internalDescription":{"description":"Internal branch description (handbook style).","type":"string"},"staffInstructions":{"description":"Internal instructions for branch staff.","type":"string"},"aiInstructions":{"description":"System-prompt guidance for the AI agent acting on this branch.","type":"string"},"mainPhotoUrl":{"type":"string"},"address":{"type":"object","required":["id"],"properties":{"id":{"description":"External address identifier.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"type":"string"}}},"openingHours":{"type":"object","required":["regular","exceptions"],"properties":{"regular":{"type":"array","items":{"type":"object","required":["id","dayOfWeek","definition","active"],"properties":{"id":{"type":"string"},"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday, 6 = Sunday.","type":"number"},"definition":{"description":"Time range definition (e.g. \"08:00-17:00\").","type":"string"},"description":{"type":"string"},"validFrom":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"type":"boolean"}}}},"exceptions":{"type":"array","items":{"type":"object","required":["id","date","isOpen"],"properties":{"id":{"type":"string"},"date":{"description":"Exception date (ISO YYYY-MM-DD).","type":"string"},"isOpen":{"type":"boolean"},"reason":{"type":"string"}}}}}},"emails":{"type":"array","items":{"type":"object","required":["id","email"],"properties":{"id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"verifiedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"phones":{"type":"array","items":{"type":"object","required":["id","phone"],"properties":{"id":{"type":"string"},"phone":{"type":"string"},"role":{"type":"string"},"verifiedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"calendars":{"type":"array","items":{"type":"object","required":["id","name","code"],"properties":{"id":{"description":"Calendar ID.","type":"string"},"name":{"type":"string"},"code":{"type":"string"},"colorHex":{"description":"6-char hex color without # prefix.","type":"string"}}}},"products":{"type":"array","items":{"type":"object","required":["id","code","slug","active"],"properties":{"id":{"description":"Product ID.","type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"active":{"type":"boolean"},"mainImageId":{"type":"number"}}}},"locks":{"type":"array","items":{"type":"object","required":["lockId","active"],"properties":{"lockId":{"description":"External TTLock identifier (matches the lock detail URL).","type":"number"},"alias":{"description":"Operator-defined display name.","type":"string"},"electricQuantity":{"description":"Battery level in percent (0–100), if reported.","type":"number"},"hasGateway":{"description":"Whether the lock is reachable via a Wi-Fi gateway.","type":"boolean"},"active":{"description":"Whether the lock is actively monitored.","type":"boolean"}}}},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","slug","name","active","branchType","people","openingHours","emails","phones","calendars","products","locks","insertedDate","updatedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"internalCode":{"type":"string"},"active":{"type":"boolean"},"url":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"branchContact":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"CuRefNo of the linked contact.","type":"string"},"name":{"type":"string"},"email":{"type":"string"},"companyName":{"type":"string"}}},"branchType":{"description":"Branch kind declared by the operator. \"own\" = the organisation runs the branch directly; \"franchise\" = a third-party franchisee runs it under the organisation's brand; \"partner\" = a cooperating but independent business (e.g. white-label outlet).","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranch":{"type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the operational parent (regional flagship / HQ).","type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]}}},"operatingCompany":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"CuRefNo of the legal entity operating this branch.","type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"description":"Czech IČO (or local equivalent).","type":"string"},"taxIdentificationNumber":{"description":"Czech DIČ (or local equivalent).","type":"string"}}},"people":{"type":"array","items":{"type":"object","required":["id","contactId","role","position"],"properties":{"id":{"description":"Internal id of the link row (used to update/remove).","type":"string"},"contactId":{"description":"CuRefNo of the linked contact.","type":"string"},"role":{"description":"Role enum — see BRANCH_PERSON_ROLES.","type":"string"},"customLabel":{"description":"Free-text label that overrides the role display.","type":"string"},"position":{"description":"Sort position.","type":"number"},"name":{"type":"string"},"email":{"type":"string"},"companyName":{"type":"string"}}}},"establishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"termsAndConditions":{"description":"Terms & Conditions (VOP), Markdown source.","type":"string"},"complaintsProcedure":{"description":"Complaints procedure (Reklamační řád), Markdown source.","type":"string"},"privacyPolicy":{"description":"Privacy policy (GDPR), Markdown source.","type":"string"},"internalDescription":{"description":"Internal branch description (handbook style).","type":"string"},"staffInstructions":{"description":"Internal instructions for branch staff.","type":"string"},"aiInstructions":{"description":"System-prompt guidance for the AI agent acting on this branch.","type":"string"},"mainPhotoUrl":{"type":"string"},"address":{"type":"object","required":["id"],"properties":{"id":{"description":"External address identifier.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"type":"string"}}},"openingHours":{"type":"object","required":["regular","exceptions"],"properties":{"regular":{"type":"array","items":{"type":"object","required":["id","dayOfWeek","definition","active"],"properties":{"id":{"type":"string"},"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday, 6 = Sunday.","type":"number"},"definition":{"description":"Time range definition (e.g. \"08:00-17:00\").","type":"string"},"description":{"type":"string"},"validFrom":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"type":"boolean"}}}},"exceptions":{"type":"array","items":{"type":"object","required":["id","date","isOpen"],"properties":{"id":{"type":"string"},"date":{"description":"Exception date (ISO YYYY-MM-DD).","type":"string"},"isOpen":{"type":"boolean"},"reason":{"type":"string"}}}}}},"emails":{"type":"array","items":{"type":"object","required":["id","email"],"properties":{"id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"verifiedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"phones":{"type":"array","items":{"type":"object","required":["id","phone"],"properties":{"id":{"type":"string"},"phone":{"type":"string"},"role":{"type":"string"},"verifiedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"calendars":{"type":"array","items":{"type":"object","required":["id","name","code"],"properties":{"id":{"description":"Calendar ID.","type":"string"},"name":{"type":"string"},"code":{"type":"string"},"colorHex":{"description":"6-char hex color without # prefix.","type":"string"}}}},"products":{"type":"array","items":{"type":"object","required":["id","code","slug","active"],"properties":{"id":{"description":"Product ID.","type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"active":{"type":"boolean"},"mainImageId":{"type":"number"}}}},"locks":{"type":"array","items":{"type":"object","required":["lockId","active"],"properties":{"lockId":{"description":"External TTLock identifier (matches the lock detail URL).","type":"number"},"alias":{"description":"Operator-defined display name.","type":"string"},"electricQuantity":{"description":"Battery level in percent (0–100), if reported.","type":"number"},"hasGateway":{"description":"Whether the lock is reachable via a Wi-Fi gateway.","type":"boolean"},"active":{"description":"Whether the lock is actively monitored.","type":"boolean"}}}},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","slug","name","active","branchType","people","openingHours","emails","phones","calendars","products","locks","insertedDate","updatedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"internalCode":{"type":"string"},"active":{"type":"boolean"},"url":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"branchContact":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"CuRefNo of the linked contact.","type":"string"},"name":{"type":"string"},"email":{"type":"string"},"companyName":{"type":"string"}}},"branchType":{"description":"Branch kind declared by the operator. \"own\" = the organisation runs the branch directly; \"franchise\" = a third-party franchisee runs it under the organisation's brand; \"partner\" = a cooperating but independent business (e.g. white-label outlet).","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranch":{"type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the operational parent (regional flagship / HQ).","type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]}}},"operatingCompany":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"CuRefNo of the legal entity operating this branch.","type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"description":"Czech IČO (or local equivalent).","type":"string"},"taxIdentificationNumber":{"description":"Czech DIČ (or local equivalent).","type":"string"}}},"people":{"type":"array","items":{"type":"object","required":["id","contactId","role","position"],"properties":{"id":{"description":"Internal id of the link row (used to update/remove).","type":"string"},"contactId":{"description":"CuRefNo of the linked contact.","type":"string"},"role":{"description":"Role enum — see BRANCH_PERSON_ROLES.","type":"string"},"customLabel":{"description":"Free-text label that overrides the role display.","type":"string"},"position":{"description":"Sort position.","type":"number"},"name":{"type":"string"},"email":{"type":"string"},"companyName":{"type":"string"}}}},"establishedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"termsAndConditions":{"description":"Terms & Conditions (VOP), Markdown source.","type":"string"},"complaintsProcedure":{"description":"Complaints procedure (Reklamační řád), Markdown source.","type":"string"},"privacyPolicy":{"description":"Privacy policy (GDPR), Markdown source.","type":"string"},"internalDescription":{"description":"Internal branch description (handbook style).","type":"string"},"staffInstructions":{"description":"Internal instructions for branch staff.","type":"string"},"aiInstructions":{"description":"System-prompt guidance for the AI agent acting on this branch.","type":"string"},"mainPhotoUrl":{"type":"string"},"address":{"type":"object","required":["id"],"properties":{"id":{"description":"External address identifier.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code.","type":"string"},"notice":{"type":"string"}}},"openingHours":{"type":"object","required":["regular","exceptions"],"properties":{"regular":{"type":"array","items":{"type":"object","required":["id","dayOfWeek","definition","active"],"properties":{"id":{"type":"string"},"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday, 6 = Sunday.","type":"number"},"definition":{"description":"Time range definition (e.g. \"08:00-17:00\").","type":"string"},"description":{"type":"string"},"validFrom":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"type":"boolean"}}}},"exceptions":{"type":"array","items":{"type":"object","required":["id","date","isOpen"],"properties":{"id":{"type":"string"},"date":{"description":"Exception date (ISO YYYY-MM-DD).","type":"string"},"isOpen":{"type":"boolean"},"reason":{"type":"string"}}}}}},"emails":{"type":"array","items":{"type":"object","required":["id","email"],"properties":{"id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"verifiedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"phones":{"type":"array","items":{"type":"object","required":["id","phone"],"properties":{"id":{"type":"string"},"phone":{"type":"string"},"role":{"type":"string"},"verifiedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"calendars":{"type":"array","items":{"type":"object","required":["id","name","code"],"properties":{"id":{"description":"Calendar ID.","type":"string"},"name":{"type":"string"},"code":{"type":"string"},"colorHex":{"description":"6-char hex color without # prefix.","type":"string"}}}},"products":{"type":"array","items":{"type":"object","required":["id","code","slug","active"],"properties":{"id":{"description":"Product ID.","type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"active":{"type":"boolean"},"mainImageId":{"type":"number"}}}},"locks":{"type":"array","items":{"type":"object","required":["lockId","active"],"properties":{"lockId":{"description":"External TTLock identifier (matches the lock detail URL).","type":"number"},"alias":{"description":"Operator-defined display name.","type":"string"},"electricQuantity":{"description":"Battery level in percent (0–100), if reported.","type":"number"},"hasGateway":{"description":"Whether the lock is reachable via a Wi-Fi gateway.","type":"boolean"},"active":{"description":"Whether the lock is actively monitored.","type":"boolean"}}}},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","slug","name","active","branchType","people","openingHours","emails","phones","calendars","products","locks","insertedDate","updatedDate"]}}}}},"operationId":"getBffBranchDetail","tags":["Branch"],"description":"Returns full branch detail including basic fields, address, manager contact, regular opening hours, opening hour exceptions, emails, phones and main photo URL.","summary":"Get branch detail"}},"/bff/branch/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"description":"Final slug of the created branch.","type":"string"}},"required":["success","slug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"description":"Final slug of the created branch.","type":"string"}},"required":["success","slug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"description":"Final slug of the created branch.","type":"string"}},"required":["success","slug"]}}}}},"operationId":"postBffBranchCreate","tags":["Branch"],"description":"Creates a new branch for the authenticated organisation. Generates a unique slug and validates internal code uniqueness. The branch_contact link and the list of associated people are set afterwards via the dedicated endpoints (`/set-branch-contact`, `/add-branch-person`).","summary":"Create branch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Branch display name.","examples":["Prague Central"],"type":"string"},"slug":{"description":"Preferred URL slug. Generated from name if empty.","type":"string"},"internalCode":{"description":"Organisation-internal code (unique per organisation).","type":"string"},"description":{"description":"Short branch description.","type":"string"},"url":{"description":"Public branch URL.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Branch display name.","examples":["Prague Central"],"type":"string"},"slug":{"description":"Preferred URL slug. Generated from name if empty.","type":"string"},"internalCode":{"description":"Organisation-internal code (unique per organisation).","type":"string"},"description":{"description":"Short branch description.","type":"string"},"url":{"description":"Public branch URL.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Branch display name.","examples":["Prague Central"],"type":"string"},"slug":{"description":"Preferred URL slug. Generated from name if empty.","type":"string"},"internalCode":{"description":"Organisation-internal code (unique per organisation).","type":"string"},"description":{"description":"Short branch description.","type":"string"},"url":{"description":"Public branch URL.","type":"string"}}}}}}}},"/bff/branch/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"type":"string"}},"required":["success","slug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"type":"string"}},"required":["success","slug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"type":"string"}},"required":["success","slug"]}}}}},"operationId":"postBffBranchUpdate","tags":["Branch"],"description":"Updates editable fields of a branch. Only provided fields are changed; undefined fields are preserved. Null values explicitly clear nullable fields.","summary":"Update branch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug (used to identify the branch).","examples":["prague-central"],"type":"string"},"name":{"minLength":1,"description":"New branch display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"New description. Null to clear.","type":"string"},{"type":"null"}]},"internalCode":{"nullable":true,"anyOf":[{"description":"Internal code (unique per org). Null to clear.","type":"string"},{"type":"null"}]},"url":{"nullable":true,"anyOf":[{"description":"Public URL. Null to clear.","type":"string"},{"type":"null"}]},"active":{"description":"Whether the branch is active.","type":"boolean"},"latitude":{"nullable":true,"anyOf":[{"description":"GPS latitude.","type":"number"},{"type":"null"}]},"longitude":{"nullable":true,"anyOf":[{"description":"GPS longitude.","type":"number"},{"type":"null"}]},"branchContactId":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact representing the branch itself (technical mail / accounting target). Null to unlink.","type":"string"},{"type":"null"}]},"establishedDate":{"nullable":true,"anyOf":[{"description":"Branch establishment date (ISO timestamp).","type":"string"},{"type":"null"}]},"termsAndConditions":{"nullable":true,"anyOf":[{"description":"Terms & Conditions (VOP), Markdown source. Null clears.","type":"string"},{"type":"null"}]},"complaintsProcedure":{"nullable":true,"anyOf":[{"description":"Complaints procedure (Reklamační řád), Markdown. Null clears.","type":"string"},{"type":"null"}]},"privacyPolicy":{"nullable":true,"anyOf":[{"description":"Privacy policy (GDPR), Markdown source. Null clears.","type":"string"},{"type":"null"}]},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal branch description (handbook). Null clears.","type":"string"},{"type":"null"}]},"staffInstructions":{"nullable":true,"anyOf":[{"description":"Internal instructions for branch staff. Null clears.","type":"string"},{"type":"null"}]},"aiInstructions":{"nullable":true,"anyOf":[{"description":"System-prompt guidance for the AI agent acting on this branch (chat / voice / e-mail). Null clears.","type":"string"},{"type":"null"}]},"branchType":{"description":"Branch kind. Cannot be null — defaults to \"own\" if never set.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranchSlug":{"nullable":true,"anyOf":[{"description":"Slug of the operational parent branch. Null detaches. Setting a slug that would create a cycle is rejected.","type":"string"},{"type":"null"}]},"operatingCompanyContactRef":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact representing the legal entity operating this branch. Null unlinks (admin then shows a missing-operator warning).","type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug (used to identify the branch).","examples":["prague-central"],"type":"string"},"name":{"minLength":1,"description":"New branch display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"New description. Null to clear.","type":"string"},{"type":"null"}]},"internalCode":{"nullable":true,"anyOf":[{"description":"Internal code (unique per org). Null to clear.","type":"string"},{"type":"null"}]},"url":{"nullable":true,"anyOf":[{"description":"Public URL. Null to clear.","type":"string"},{"type":"null"}]},"active":{"description":"Whether the branch is active.","type":"boolean"},"latitude":{"nullable":true,"anyOf":[{"description":"GPS latitude.","type":"number"},{"type":"null"}]},"longitude":{"nullable":true,"anyOf":[{"description":"GPS longitude.","type":"number"},{"type":"null"}]},"branchContactId":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact representing the branch itself (technical mail / accounting target). Null to unlink.","type":"string"},{"type":"null"}]},"establishedDate":{"nullable":true,"anyOf":[{"description":"Branch establishment date (ISO timestamp).","type":"string"},{"type":"null"}]},"termsAndConditions":{"nullable":true,"anyOf":[{"description":"Terms & Conditions (VOP), Markdown source. Null clears.","type":"string"},{"type":"null"}]},"complaintsProcedure":{"nullable":true,"anyOf":[{"description":"Complaints procedure (Reklamační řád), Markdown. Null clears.","type":"string"},{"type":"null"}]},"privacyPolicy":{"nullable":true,"anyOf":[{"description":"Privacy policy (GDPR), Markdown source. Null clears.","type":"string"},{"type":"null"}]},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal branch description (handbook). Null clears.","type":"string"},{"type":"null"}]},"staffInstructions":{"nullable":true,"anyOf":[{"description":"Internal instructions for branch staff. Null clears.","type":"string"},{"type":"null"}]},"aiInstructions":{"nullable":true,"anyOf":[{"description":"System-prompt guidance for the AI agent acting on this branch (chat / voice / e-mail). Null clears.","type":"string"},{"type":"null"}]},"branchType":{"description":"Branch kind. Cannot be null — defaults to \"own\" if never set.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranchSlug":{"nullable":true,"anyOf":[{"description":"Slug of the operational parent branch. Null detaches. Setting a slug that would create a cycle is rejected.","type":"string"},{"type":"null"}]},"operatingCompanyContactRef":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact representing the legal entity operating this branch. Null unlinks (admin then shows a missing-operator warning).","type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug (used to identify the branch).","examples":["prague-central"],"type":"string"},"name":{"minLength":1,"description":"New branch display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"New description. Null to clear.","type":"string"},{"type":"null"}]},"internalCode":{"nullable":true,"anyOf":[{"description":"Internal code (unique per org). Null to clear.","type":"string"},{"type":"null"}]},"url":{"nullable":true,"anyOf":[{"description":"Public URL. Null to clear.","type":"string"},{"type":"null"}]},"active":{"description":"Whether the branch is active.","type":"boolean"},"latitude":{"nullable":true,"anyOf":[{"description":"GPS latitude.","type":"number"},{"type":"null"}]},"longitude":{"nullable":true,"anyOf":[{"description":"GPS longitude.","type":"number"},{"type":"null"}]},"branchContactId":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact representing the branch itself (technical mail / accounting target). Null to unlink.","type":"string"},{"type":"null"}]},"establishedDate":{"nullable":true,"anyOf":[{"description":"Branch establishment date (ISO timestamp).","type":"string"},{"type":"null"}]},"termsAndConditions":{"nullable":true,"anyOf":[{"description":"Terms & Conditions (VOP), Markdown source. Null clears.","type":"string"},{"type":"null"}]},"complaintsProcedure":{"nullable":true,"anyOf":[{"description":"Complaints procedure (Reklamační řád), Markdown. Null clears.","type":"string"},{"type":"null"}]},"privacyPolicy":{"nullable":true,"anyOf":[{"description":"Privacy policy (GDPR), Markdown source. Null clears.","type":"string"},{"type":"null"}]},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal branch description (handbook). Null clears.","type":"string"},{"type":"null"}]},"staffInstructions":{"nullable":true,"anyOf":[{"description":"Internal instructions for branch staff. Null clears.","type":"string"},{"type":"null"}]},"aiInstructions":{"nullable":true,"anyOf":[{"description":"System-prompt guidance for the AI agent acting on this branch (chat / voice / e-mail). Null clears.","type":"string"},{"type":"null"}]},"branchType":{"description":"Branch kind. Cannot be null — defaults to \"own\" if never set.","anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"parentBranchSlug":{"nullable":true,"anyOf":[{"description":"Slug of the operational parent branch. Null detaches. Setting a slug that would create a cycle is rejected.","type":"string"},{"type":"null"}]},"operatingCompanyContactRef":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact representing the legal entity operating this branch. Null unlinks (admin then shows a missing-operator warning).","type":"string"},{"type":"null"}]}}}}}}}},"/bff/branch/change-slug":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"type":"string"}},"required":["success","slug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"type":"string"}},"required":["success","slug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"slug":{"type":"string"}},"required":["success","slug"]}}}}},"operationId":"postBffBranchChange-slug","tags":["Branch"],"description":"Renames the slug of a branch. The new slug is sanitized and deduplicated so that it remains unique within the organisation.","summary":"Change branch slug","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["currentSlug","newSlug"],"properties":{"currentSlug":{"description":"Current branch slug.","type":"string"},"newSlug":{"minLength":1,"description":"Desired new slug (will be slugified/deduplicated).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["currentSlug","newSlug"],"properties":{"currentSlug":{"description":"Current branch slug.","type":"string"},"newSlug":{"minLength":1,"description":"Desired new slug (will be slugified/deduplicated).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["currentSlug","newSlug"],"properties":{"currentSlug":{"description":"Current branch slug.","type":"string"},"newSlug":{"minLength":1,"description":"Desired new slug (will be slugified/deduplicated).","type":"string"}}}}}}}},"/bff/branch/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchDelete","tags":["Branch"],"description":"Sets the branch to inactive. The branch and all its related data (address, opening hours, images) are kept; only the active flag is flipped to false.","summary":"Deactivate branch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug to deactivate.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug to deactivate.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug to deactivate.","type":"string"}}}}}}}},"/bff/branch/save-address":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"addressId":{"type":"string"}},"required":["success","addressId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"addressId":{"type":"string"}},"required":["success","addressId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"addressId":{"type":"string"}},"required":["success","addressId"]}}}}},"operationId":"postBffBranchSave-address","tags":["Branch"],"description":"Creates or updates the address linked to a branch. If the branch already has an address, its fields are updated. Otherwise a new address record is created and linked. Returns the external address ID.","summary":"Save branch address","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code. Defaults to org default.","type":"string"},"notice":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code. Defaults to org default.","type":"string"},"notice":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"streetAddress":{"type":"string"},"city":{"type":"string"},"cityPart":{"type":"string"},"stateRegion":{"type":"string"},"postalCode":{"type":"string"},"country":{"description":"ISO 3166-1 alpha-2 country code. Defaults to org default.","type":"string"},"notice":{"type":"string"}}}}}}}},"/bff/branch/save-opening-hours":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchSave-opening-hours","tags":["Branch"],"description":"Replaces ALL existing regular opening hours for the branch in a single batch. Previous rows are soft-deleted (is_deleted = true) and fresh rows are inserted. Exceptions are not affected.","summary":"Save regular opening hours","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","hours"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"hours":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday ... 6 = Sunday.","type":"number"},"definition":{"minLength":1,"description":"Time range definition (e.g. \"08:00-17:00\", or OSM-compatible string).","type":"string"},"description":{"type":"string"},"validFrom":{"nullable":true,"anyOf":[{"description":"ISO datetime the hours are valid from.","type":"string"},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"ISO datetime the hours are valid to.","type":"string"},{"type":"null"}]},"active":{"description":"Whether the hour record is active. Defaults to true.","type":"boolean"}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","hours"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"hours":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday ... 6 = Sunday.","type":"number"},"definition":{"minLength":1,"description":"Time range definition (e.g. \"08:00-17:00\", or OSM-compatible string).","type":"string"},"description":{"type":"string"},"validFrom":{"nullable":true,"anyOf":[{"description":"ISO datetime the hours are valid from.","type":"string"},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"ISO datetime the hours are valid to.","type":"string"},{"type":"null"}]},"active":{"description":"Whether the hour record is active. Defaults to true.","type":"boolean"}}}}}}},"text/plain":{"schema":{"type":"object","required":["slug","hours"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"hours":{"type":"array","items":{"type":"object","required":["dayOfWeek","definition"],"properties":{"dayOfWeek":{"minimum":0,"maximum":6,"description":"0 = Monday ... 6 = Sunday.","type":"number"},"definition":{"minLength":1,"description":"Time range definition (e.g. \"08:00-17:00\", or OSM-compatible string).","type":"string"},"description":{"type":"string"},"validFrom":{"nullable":true,"anyOf":[{"description":"ISO datetime the hours are valid from.","type":"string"},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"ISO datetime the hours are valid to.","type":"string"},{"type":"null"}]},"active":{"description":"Whether the hour record is active. Defaults to true.","type":"boolean"}}}}}}}}}}},"/bff/branch/auto-parse-opening-hours":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"appliedRegularRows":{"type":"number"},"appliedExceptions":{"type":"number"}},"required":["success","appliedRegularRows","appliedExceptions"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"appliedRegularRows":{"type":"number"},"appliedExceptions":{"type":"number"}},"required":["success","appliedRegularRows","appliedExceptions"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"appliedRegularRows":{"type":"number"},"appliedExceptions":{"type":"number"}},"required":["success","appliedRegularRows","appliedExceptions"]}}}}},"operationId":"postBffBranchAuto-parse-opening-hours","tags":["Branch"],"description":"Sends the user prompt to the LLM, validates the structured output and applies it as a full replace of the regular hours plus an idempotent upsert of the exceptions. Returns the counts that were actually persisted (the model may drop or skip rows that fail server-side validation).","summary":"Auto-fill opening hours from a free-text description (AI)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","prompt"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"prompt":{"minLength":1,"maxLength":4000,"description":"Free-text description of the opening hours in any language and format. The AI will parse it into a structured weekly schedule plus optional date-specific exceptions.","examples":["Po–Pá 8:00–17:00, So 9–12, Ne zavřeno. Na vánoce (24.-26.12.) zavřeno."],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","prompt"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"prompt":{"minLength":1,"maxLength":4000,"description":"Free-text description of the opening hours in any language and format. The AI will parse it into a structured weekly schedule plus optional date-specific exceptions.","examples":["Po–Pá 8:00–17:00, So 9–12, Ne zavřeno. Na vánoce (24.-26.12.) zavřeno."],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug","prompt"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"prompt":{"minLength":1,"maxLength":4000,"description":"Free-text description of the opening hours in any language and format. The AI will parse it into a structured weekly schedule plus optional date-specific exceptions.","examples":["Po–Pá 8:00–17:00, So 9–12, Ne zavřeno. Na vánoce (24.-26.12.) zavřeno."],"type":"string"}}}}}}}},"/bff/branch/add-opening-hour-exception":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchAdd-opening-hour-exception","tags":["Branch"],"description":"Creates a new opening hour exception for a specific date. Idempotent per (branch, date) pair.","summary":"Add opening hour exception","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","exceptionDate","isOpen"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"exceptionDate":{"description":"Exception date in ISO YYYY-MM-DD.","examples":["2026-12-24"],"type":"string"},"isOpen":{"description":"Whether the branch is open or closed on the exception date.","type":"boolean"},"reason":{"description":"Reason for the exception (e.g. \"Christmas Eve\").","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","exceptionDate","isOpen"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"exceptionDate":{"description":"Exception date in ISO YYYY-MM-DD.","examples":["2026-12-24"],"type":"string"},"isOpen":{"description":"Whether the branch is open or closed on the exception date.","type":"boolean"},"reason":{"description":"Reason for the exception (e.g. \"Christmas Eve\").","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug","exceptionDate","isOpen"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"exceptionDate":{"description":"Exception date in ISO YYYY-MM-DD.","examples":["2026-12-24"],"type":"string"},"isOpen":{"description":"Whether the branch is open or closed on the exception date.","type":"boolean"},"reason":{"description":"Reason for the exception (e.g. \"Christmas Eve\").","type":"string"}}}}}}}},"/bff/branch/delete-opening-hour-exception":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchDelete-opening-hour-exception","tags":["Branch"],"description":"Organisation branches (pobočky) management. Each organisation can create any number of branches. A branch contains name, description, internal code, address, GPS coordinates, manager, opening hours (regular + exceptions), email/phone contacts and a photo gallery with a dedicated main photo.","summary":"Remove opening hour exception","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","exceptionId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"exceptionId":{"description":"Opening hour exception ID (from detail response).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","exceptionId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"exceptionId":{"description":"Opening hour exception ID (from detail response).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug","exceptionId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"exceptionId":{"description":"Opening hour exception ID (from detail response).","type":"string"}}}}}}}},"/bff/branch/add-email":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchAdd-email","tags":["Branch"],"description":"Organisation branches (pobočky) management. Each organisation can create any number of branches. A branch contains name, description, internal code, address, GPS coordinates, manager, opening hours (regular + exceptions), email/phone contacts and a photo gallery with a dedicated main photo.","summary":"Add branch email","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","email"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"email":{"format":"email","description":"Email address to attach.","type":"string"},"role":{"description":"Role label (e.g. \"Reception\").","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","email"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"email":{"format":"email","description":"Email address to attach.","type":"string"},"role":{"description":"Role label (e.g. \"Reception\").","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug","email"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"email":{"format":"email","description":"Email address to attach.","type":"string"},"role":{"description":"Role label (e.g. \"Reception\").","type":"string"}}}}}}}},"/bff/branch/delete-email":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchDelete-email","tags":["Branch"],"description":"Organisation branches (pobočky) management. Each organisation can create any number of branches. A branch contains name, description, internal code, address, GPS coordinates, manager, opening hours (regular + exceptions), email/phone contacts and a photo gallery with a dedicated main photo.","summary":"Remove branch email","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","emailId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"emailId":{"description":"Email ID from detail response.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","emailId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"emailId":{"description":"Email ID from detail response.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug","emailId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"emailId":{"description":"Email ID from detail response.","type":"string"}}}}}}}},"/bff/branch/add-phone":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchAdd-phone","tags":["Branch"],"description":"Organisation branches (pobočky) management. Each organisation can create any number of branches. A branch contains name, description, internal code, address, GPS coordinates, manager, opening hours (regular + exceptions), email/phone contacts and a photo gallery with a dedicated main photo.","summary":"Add branch phone","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","phone"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"phone":{"minLength":1,"description":"Phone number.","type":"string"},"role":{"description":"Role label (e.g. \"Main\", \"Fax\").","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","phone"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"phone":{"minLength":1,"description":"Phone number.","type":"string"},"role":{"description":"Role label (e.g. \"Main\", \"Fax\").","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug","phone"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"phone":{"minLength":1,"description":"Phone number.","type":"string"},"role":{"description":"Role label (e.g. \"Main\", \"Fax\").","type":"string"}}}}}}}},"/bff/branch/delete-phone":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchDelete-phone","tags":["Branch"],"description":"Organisation branches (pobočky) management. Each organisation can create any number of branches. A branch contains name, description, internal code, address, GPS coordinates, manager, opening hours (regular + exceptions), email/phone contacts and a photo gallery with a dedicated main photo.","summary":"Remove branch phone","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","phoneId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"phoneId":{"description":"Phone ID from detail response.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","phoneId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"phoneId":{"description":"Phone ID from detail response.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug","phoneId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"phoneId":{"description":"Phone ID from detail response.","type":"string"}}}}}}}},"/bff/branch/gallery-list":{"get":{"parameters":[{"description":"Branch slug.","schema":{"type":"string"},"in":"query","name":"slug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["blob","title","position","active","deleted","isLogo","isMainPhoto"],"properties":{"id":{"description":"Blob token (used as image identifier).","type":"string"},"blob":{"description":"Blob metadata (filename, URL, size)."},"title":{"description":"Image description / alt text.","type":"string"},"position":{"type":"number"},"active":{"type":"boolean"},"deleted":{"type":"boolean"},"isLogo":{"type":"boolean"},"isMainPhoto":{"type":"boolean"}}}},"mainImageId":{"description":"Blob token of the main image, if set.","type":"string"},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["blob","title","position","active","deleted","isLogo","isMainPhoto"],"properties":{"id":{"description":"Blob token (used as image identifier).","type":"string"},"blob":{"description":"Blob metadata (filename, URL, size)."},"title":{"description":"Image description / alt text.","type":"string"},"position":{"type":"number"},"active":{"type":"boolean"},"deleted":{"type":"boolean"},"isLogo":{"type":"boolean"},"isMainPhoto":{"type":"boolean"}}}},"mainImageId":{"description":"Blob token of the main image, if set.","type":"string"},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["blob","title","position","active","deleted","isLogo","isMainPhoto"],"properties":{"id":{"description":"Blob token (used as image identifier).","type":"string"},"blob":{"description":"Blob metadata (filename, URL, size)."},"title":{"description":"Image description / alt text.","type":"string"},"position":{"type":"number"},"active":{"type":"boolean"},"deleted":{"type":"boolean"},"isLogo":{"type":"boolean"},"isMainPhoto":{"type":"boolean"}}}},"mainImageId":{"description":"Blob token of the main image, if set.","type":"string"},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffBranchGallery-list","tags":["Branch"],"description":"Returns all non-deleted images of the branch gallery ordered by active first, then by position ascending. Includes blob metadata and the main image identifier.","summary":"List branch gallery images"}},"/bff/branch/gallery-link-blob":{"get":{"parameters":[{"description":"Branch slug.","schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Blob token from file upload.","schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffBranchGallery-link-blob","tags":["Branch"],"description":"Links an uploaded blob to the branch gallery. If the branch has no main photo yet, the new image becomes the main photo.","summary":"Add image to branch gallery"}},"/bff/branch/gallery-image-mark-main":{"get":{"parameters":[{"description":"Branch slug.","schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Blob token of the image to promote to main.","schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffBranchGallery-image-mark-main","tags":["Branch"],"description":"Organisation branches (pobočky) management. Each organisation can create any number of branches. A branch contains name, description, internal code, address, GPS coordinates, manager, opening hours (regular + exceptions), email/phone contacts and a photo gallery with a dedicated main photo.","summary":"Set main branch photo"}},"/bff/branch/gallery-image-delete":{"get":{"parameters":[{"description":"Branch slug.","schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Blob token of the image to delete.","schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffBranchGallery-image-delete","tags":["Branch"],"description":"Soft-deletes an image (is_deleted = true). If the deleted image was the main photo, the next active image becomes main.","summary":"Delete gallery image"}},"/bff/branch/gallery-image-toggle-active":{"get":{"parameters":[{"description":"Branch slug.","schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Blob token of the image to toggle.","schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffBranchGallery-image-toggle-active","tags":["Branch"],"description":"Organisation branches (pobočky) management. Each organisation can create any number of branches. A branch contains name, description, internal code, address, GPS coordinates, manager, opening hours (regular + exceptions), email/phone contacts and a photo gallery with a dedicated main photo.","summary":"Toggle gallery image active status"}},"/bff/branch/gallery-image-update-meta":{"get":{"parameters":[{"description":"Branch slug.","schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Blob token of the image.","schema":{"type":"string"},"in":"query","name":"blobToken","required":true},{"description":"New description / alt text. Empty to clear.","schema":{"type":"string"},"in":"query","name":"title","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffBranchGallery-image-update-meta","tags":["Branch"],"description":"Organisation branches (pobočky) management. Each organisation can create any number of branches. A branch contains name, description, internal code, address, GPS coordinates, manager, opening hours (regular + exceptions), email/phone contacts and a photo gallery with a dedicated main photo.","summary":"Update gallery image description"}},"/bff/branch/gallery-image-set-logo":{"get":{"parameters":[{"description":"Branch slug.","schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Blob token of the image.","schema":{"type":"string"},"in":"query","name":"blobToken","required":true},{"description":"Set to \"true\" to mark as logo, otherwise \"false\".","examples":["true"],"schema":{"type":"string"},"in":"query","name":"value","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffBranchGallery-image-set-logo","tags":["Branch"],"description":"Sets the is_logo flag for the image. When value is true, the flag is cleared from other images in the same branch first.","summary":"Mark image as logo"}},"/bff/branch/attachable-calendars":{"get":{"parameters":[{"description":"Branch slug.","schema":{"type":"string"},"in":"query","name":"slug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","code"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"code":{"type":"string"},"colorHex":{"type":"string"},"attachedToBranchId":{"type":"string"},"attachedToBranchName":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","code"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"code":{"type":"string"},"colorHex":{"type":"string"},"attachedToBranchId":{"type":"string"},"attachedToBranchName":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","code"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"code":{"type":"string"},"colorHex":{"type":"string"},"attachedToBranchId":{"type":"string"},"attachedToBranchName":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffBranchAttachable-calendars","tags":["Branch"],"description":"Returns calendars currently free (not attached to any branch) plus calendars already attached to this branch. Calendars attached to a different branch are excluded.","summary":"List attachable calendars for a branch"}},"/bff/branch/attach-calendar":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchAttach-calendar","tags":["Branch"],"description":"Sets core__calendar.branch_id = branchId. The calendar must belong to the same organisation. A calendar can only be attached to one branch at a time.","summary":"Attach calendar to branch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","calendarId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"calendarId":{"description":"Calendar ID to attach.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","calendarId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"calendarId":{"description":"Calendar ID to attach.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["slug","calendarId"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"calendarId":{"description":"Calendar ID to attach.","type":"string"}}}}}}}},"/bff/branch/detach-calendar":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchDetach-calendar","tags":["Branch"],"description":"Clears core__calendar.branch_id. The calendar becomes organisation-wide again.","summary":"Detach calendar from any branch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["calendarId"],"properties":{"calendarId":{"description":"Calendar ID to detach (clears branch_id).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["calendarId"],"properties":{"calendarId":{"description":"Calendar ID to detach (clears branch_id).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["calendarId"],"properties":{"calendarId":{"description":"Calendar ID to detach (clears branch_id).","type":"string"}}}}}}}},"/bff/branch/product-options":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","slug","active"],"properties":{"id":{"type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"active":{"type":"boolean"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","slug","active"],"properties":{"id":{"type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"active":{"type":"boolean"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","slug","active"],"properties":{"id":{"type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"active":{"type":"boolean"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffBranchProduct-options","tags":["Branch"],"description":"Lightweight list (id, code, slug, active) of all non-deleted products in the organisation. Used as the option list of the branch product multi-select.","summary":"List products available to attach to a branch"}},"/bff/branch/save-products":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"added":{"type":"number"},"removed":{"type":"number"},"total":{"type":"number"}},"required":["success","added","removed","total"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"added":{"type":"number"},"removed":{"type":"number"},"total":{"type":"number"}},"required":["success","added","removed","total"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"added":{"type":"number"},"removed":{"type":"number"},"total":{"type":"number"}},"required":["success","added","removed","total"]}}}}},"operationId":"postBffBranchSave-products","tags":["Branch"],"description":"Replaces the full set of products assigned to a branch (M:N via shop__branch_product). Uses a diff strategy — only the rows that actually need to be added or removed are touched. All product IDs are validated against the organisation; passing a foreign or deleted product is rejected.","summary":"Save branch product assortment","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","productIds"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"productIds":{"description":"Full desired list of product IDs for the branch. The assortment is replaced, not appended.","type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","productIds"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"productIds":{"description":"Full desired list of product IDs for the branch. The assortment is replaced, not appended.","type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["slug","productIds"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"productIds":{"description":"Full desired list of product IDs for the branch. The assortment is replaced, not appended.","type":"array","items":{"type":"string"}}}}}}}}},"/bff/branch/set-branch-contact":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchSet-branch-contact","tags":["Branch"],"description":"Links a single `shop__contact` to a branch as its technical-contact identity. Pass `null` or omit `contactId` to unlink. This is independent of `shop__branch_person` (which carries real people).","summary":"Set or clear the branch technical contact","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"contactId":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact to link, or null to unlink.","type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"contactId":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact to link, or null to unlink.","type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"contactId":{"nullable":true,"anyOf":[{"description":"CuRefNo of the contact to link, or null to unlink.","type":"string"},{"type":"null"}]}}}}}}}},"/bff/branch/add-branch-person":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}},"required":["success","id"]}}}}},"operationId":"postBffBranchAdd-branch-person","tags":["Branch"],"description":"Creates a new `shop__branch_person` row linking a contact to the branch in a given role. Idempotent on (branchId, contactId, role) — if the link already exists the customLabel and position are updated instead of failing with a constraint violation.","summary":"Add (or upsert) a person on a branch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","contactId","role"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"contactId":{"description":"CuRefNo of the contact to link to the branch.","type":"string"},"role":{"description":"Role enum. Allowed: branch_contact, owner, manager, custodian, cleaner, technician, accountant, security, support, other.","examples":["manager","owner","custodian"],"type":"string"},"customLabel":{"nullable":true,"anyOf":[{"maxLength":200,"description":"Free-text label (≤ 200 chars) shown next to / instead of the role. Optional.","type":"string"},{"type":"null"}]},"position":{"description":"Sort position; lower = earlier. Default 0.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","contactId","role"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"contactId":{"description":"CuRefNo of the contact to link to the branch.","type":"string"},"role":{"description":"Role enum. Allowed: branch_contact, owner, manager, custodian, cleaner, technician, accountant, security, support, other.","examples":["manager","owner","custodian"],"type":"string"},"customLabel":{"nullable":true,"anyOf":[{"maxLength":200,"description":"Free-text label (≤ 200 chars) shown next to / instead of the role. Optional.","type":"string"},{"type":"null"}]},"position":{"description":"Sort position; lower = earlier. Default 0.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["slug","contactId","role"],"properties":{"slug":{"description":"Branch slug.","type":"string"},"contactId":{"description":"CuRefNo of the contact to link to the branch.","type":"string"},"role":{"description":"Role enum. Allowed: branch_contact, owner, manager, custodian, cleaner, technician, accountant, security, support, other.","examples":["manager","owner","custodian"],"type":"string"},"customLabel":{"nullable":true,"anyOf":[{"maxLength":200,"description":"Free-text label (≤ 200 chars) shown next to / instead of the role. Optional.","type":"string"},{"type":"null"}]},"position":{"description":"Sort position; lower = earlier. Default 0.","type":"number"}}}}}}}},"/bff/branch/update-branch-person":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchUpdate-branch-person","tags":["Branch"],"description":"Updates the role / custom label / position on an existing branch_person row. Verifies the row belongs to the caller’s organisation.","summary":"Update a branch_person row","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["personId"],"properties":{"personId":{"description":"Internal id of the branch_person row (from the detail response).","type":"string"},"role":{"description":"New role; one of: branch_contact, owner, manager, custodian, cleaner, technician, accountant, security, support, other.","type":"string"},"customLabel":{"nullable":true,"anyOf":[{"maxLength":200,"description":"New free-text label; null to clear.","type":"string"},{"type":"null"}]},"position":{"description":"New sort position.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["personId"],"properties":{"personId":{"description":"Internal id of the branch_person row (from the detail response).","type":"string"},"role":{"description":"New role; one of: branch_contact, owner, manager, custodian, cleaner, technician, accountant, security, support, other.","type":"string"},"customLabel":{"nullable":true,"anyOf":[{"maxLength":200,"description":"New free-text label; null to clear.","type":"string"},{"type":"null"}]},"position":{"description":"New sort position.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["personId"],"properties":{"personId":{"description":"Internal id of the branch_person row (from the detail response).","type":"string"},"role":{"description":"New role; one of: branch_contact, owner, manager, custodian, cleaner, technician, accountant, security, support, other.","type":"string"},"customLabel":{"nullable":true,"anyOf":[{"maxLength":200,"description":"New free-text label; null to clear.","type":"string"},{"type":"null"}]},"position":{"description":"New sort position.","type":"number"}}}}}}}},"/bff/branch/remove-branch-person":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffBranchRemove-branch-person","tags":["Branch"],"description":"Deletes a single branch_person row owned by the caller’s organisation.","summary":"Remove a branch_person row","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["personId"],"properties":{"personId":{"description":"Internal id of the branch_person row (from the detail response).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["personId"],"properties":{"personId":{"description":"Internal id of the branch_person row (from the detail response).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["personId"],"properties":{"personId":{"description":"Internal id of the branch_person row (from the detail response).","type":"string"}}}}}}}},"/bff/branch/tree":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["slug","name","parentSlug","branchType","active","childCount"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"parentSlug":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"active":{"type":"boolean"},"childCount":{"type":"number"},"operatingCompany":{"type":"object","required":["contactId"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"}}}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["slug","name","parentSlug","branchType","active","childCount"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"parentSlug":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"active":{"type":"boolean"},"childCount":{"type":"number"},"operatingCompany":{"type":"object","required":["contactId"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"}}}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["slug","name","parentSlug","branchType","active","childCount"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"parentSlug":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"active":{"type":"boolean"},"childCount":{"type":"number"},"operatingCompany":{"type":"object","required":["contactId"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"}}}}}}},"required":["items"]}}}}},"operationId":"getBffBranchTree","tags":["Branch"],"description":"Flat list of all branches in the authenticated organisation with parent-slug, branch type, operating-company summary and direct-child count. The admin assembles the tree client-side so it can drive expand/collapse state without round-trips.","summary":"Branch operational tree"}},"/bff/branch/holding-tree":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"companies":{"type":"array","items":{"type":"object","required":["contactId","name","branchCount"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"},"branchCount":{"type":"number"}}}},"links":{"type":"array","items":{"type":"object","required":["id","parentContactId","childContactId","relationType"],"properties":{"id":{"type":"string"},"parentContactId":{"type":"string"},"childContactId":{"type":"string"},"relationType":{"anyOf":[{"const":"subsidiary","type":"string"},{"const":"franchisee","type":"string"},{"const":"sister","type":"string"},{"const":"joint_venture","type":"string"},{"const":"silent_partner","type":"string"}]},"ownershipPercent":{"type":"number"},"validFrom":{"type":"string"},"validTo":{"type":"string"},"notes":{"type":"string"}}}},"branchesByCompany":{"type":"object","patternProperties":{"^(.*)$":{"type":"array","items":{"type":"object","required":["slug","name","branchType","active"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"active":{"type":"boolean"}}}}}}},"required":["companies","links","branchesByCompany"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"companies":{"type":"array","items":{"type":"object","required":["contactId","name","branchCount"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"},"branchCount":{"type":"number"}}}},"links":{"type":"array","items":{"type":"object","required":["id","parentContactId","childContactId","relationType"],"properties":{"id":{"type":"string"},"parentContactId":{"type":"string"},"childContactId":{"type":"string"},"relationType":{"anyOf":[{"const":"subsidiary","type":"string"},{"const":"franchisee","type":"string"},{"const":"sister","type":"string"},{"const":"joint_venture","type":"string"},{"const":"silent_partner","type":"string"}]},"ownershipPercent":{"type":"number"},"validFrom":{"type":"string"},"validTo":{"type":"string"},"notes":{"type":"string"}}}},"branchesByCompany":{"type":"object","patternProperties":{"^(.*)$":{"type":"array","items":{"type":"object","required":["slug","name","branchType","active"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"active":{"type":"boolean"}}}}}}},"required":["companies","links","branchesByCompany"]}},"text/plain":{"schema":{"type":"object","properties":{"companies":{"type":"array","items":{"type":"object","required":["contactId","name","branchCount"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"},"branchCount":{"type":"number"}}}},"links":{"type":"array","items":{"type":"object","required":["id","parentContactId","childContactId","relationType"],"properties":{"id":{"type":"string"},"parentContactId":{"type":"string"},"childContactId":{"type":"string"},"relationType":{"anyOf":[{"const":"subsidiary","type":"string"},{"const":"franchisee","type":"string"},{"const":"sister","type":"string"},{"const":"joint_venture","type":"string"},{"const":"silent_partner","type":"string"}]},"ownershipPercent":{"type":"number"},"validFrom":{"type":"string"},"validTo":{"type":"string"},"notes":{"type":"string"}}}},"branchesByCompany":{"type":"object","patternProperties":{"^(.*)$":{"type":"array","items":{"type":"object","required":["slug","name","branchType","active"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"branchType":{"anyOf":[{"const":"own","type":"string"},{"const":"franchise","type":"string"},{"const":"partner","type":"string"}]},"active":{"type":"boolean"}}}}}}},"required":["companies","links","branchesByCompany"]}}}}},"operationId":"getBffBranchHolding-tree","tags":["Branch"],"description":"Per-organisation DAG of company-to-company relationships plus the branches each company operates. Returned as flat lists (`companies`, `links`, `branchesByCompany`) so the admin renderer can walk the DAG safely (deduping nodes when the same company appears under multiple parents).","summary":"Holding (legal-entity) tree"}},"/bff/branch/operating-company-options":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["contactId","name"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["contactId","name"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["contactId","name"],"properties":{"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffBranchOperating-company-options","tags":["Branch"],"description":"Returns every contact in the organisation that already has an IČO — i.e. legal entities eligible to be picked as a branch operator. Capped at 500 rows.","summary":"List candidate operating companies"}},"/bff/branch/resolve-operating-company-by-ico":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"},"created":{"description":"True if a fresh contact was created in this call.","type":"boolean"}},"required":["success","contactId","name","created"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"},"created":{"description":"True if a fresh contact was created in this call.","type":"boolean"}},"required":["success","contactId","name","created"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"contactId":{"type":"string"},"name":{"type":"string"},"companyRegistrationNumber":{"type":"string"},"taxIdentificationNumber":{"type":"string"},"created":{"description":"True if a fresh contact was created in this call.","type":"boolean"}},"required":["success","contactId","name","created"]}}}}},"operationId":"postBffBranchResolve-operating-company-by-ico","tags":["Branch"],"description":"Returns an existing contact with this IČO in the org, or creates a new contact and runs the ARES sync to fill in name / DIČ / VAT status. The returned `contactId` (CuRefNo) is the value to pass as `operatingCompanyContactRef` in `/update`.","summary":"Resolve operating company by IČO","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["companyRegistrationNumber"],"properties":{"companyRegistrationNumber":{"minLength":1,"description":"IČO of the legal entity. Will be parsed/normalized server-side.","examples":["27082440"],"type":"string"},"countryCode":{"description":"ISO 3166-1 alpha-2 country code. Defaults to CZ.","examples":["CZ"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["companyRegistrationNumber"],"properties":{"companyRegistrationNumber":{"minLength":1,"description":"IČO of the legal entity. Will be parsed/normalized server-side.","examples":["27082440"],"type":"string"},"countryCode":{"description":"ISO 3166-1 alpha-2 country code. Defaults to CZ.","examples":["CZ"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["companyRegistrationNumber"],"properties":{"companyRegistrationNumber":{"minLength":1,"description":"IČO of the legal entity. Will be parsed/normalized server-side.","examples":["27082440"],"type":"string"},"countryCode":{"description":"ISO 3166-1 alpha-2 country code. Defaults to CZ.","examples":["CZ"],"type":"string"}}}}}}}},"/bff/branch/holding/link":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}},"required":["success","id"]}}}}},"operationId":"postBffBranchHoldingLink","tags":["Branch"],"description":"Creates a typed relationship between two company contacts. Duplicates per (org, parent, child, relationType) are rejected by a unique index. Self-loops are forbidden at the DB level.","summary":"Create a holding link","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["parentContactRef","childContactRef","relationType"],"properties":{"parentContactRef":{"description":"CuRefNo of the parent (owning) company contact.","type":"string"},"childContactRef":{"description":"CuRefNo of the child (owned) company contact.","type":"string"},"relationType":{"description":"Kind of relationship.","anyOf":[{"const":"subsidiary","type":"string"},{"const":"franchisee","type":"string"},{"const":"sister","type":"string"},{"const":"joint_venture","type":"string"},{"const":"silent_partner","type":"string"}]},"ownershipPercent":{"nullable":true,"anyOf":[{"minimum":0,"maximum":100,"description":"Ownership percent (0–100).","type":"number"},{"type":"null"}]},"validFrom":{"nullable":true,"anyOf":[{"description":"ISO YYYY-MM-DD.","type":"string"},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"ISO YYYY-MM-DD.","type":"string"},{"type":"null"}]},"notes":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["parentContactRef","childContactRef","relationType"],"properties":{"parentContactRef":{"description":"CuRefNo of the parent (owning) company contact.","type":"string"},"childContactRef":{"description":"CuRefNo of the child (owned) company contact.","type":"string"},"relationType":{"description":"Kind of relationship.","anyOf":[{"const":"subsidiary","type":"string"},{"const":"franchisee","type":"string"},{"const":"sister","type":"string"},{"const":"joint_venture","type":"string"},{"const":"silent_partner","type":"string"}]},"ownershipPercent":{"nullable":true,"anyOf":[{"minimum":0,"maximum":100,"description":"Ownership percent (0–100).","type":"number"},{"type":"null"}]},"validFrom":{"nullable":true,"anyOf":[{"description":"ISO YYYY-MM-DD.","type":"string"},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"ISO YYYY-MM-DD.","type":"string"},{"type":"null"}]},"notes":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["parentContactRef","childContactRef","relationType"],"properties":{"parentContactRef":{"description":"CuRefNo of the parent (owning) company contact.","type":"string"},"childContactRef":{"description":"CuRefNo of the child (owned) company contact.","type":"string"},"relationType":{"description":"Kind of relationship.","anyOf":[{"const":"subsidiary","type":"string"},{"const":"franchisee","type":"string"},{"const":"sister","type":"string"},{"const":"joint_venture","type":"string"},{"const":"silent_partner","type":"string"}]},"ownershipPercent":{"nullable":true,"anyOf":[{"minimum":0,"maximum":100,"description":"Ownership percent (0–100).","type":"number"},{"type":"null"}]},"validFrom":{"nullable":true,"anyOf":[{"description":"ISO YYYY-MM-DD.","type":"string"},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"ISO YYYY-MM-DD.","type":"string"},{"type":"null"}]},"notes":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/branch/holding/unlink":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"boolean"}},"required":["success","deleted"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"boolean"}},"required":["success","deleted"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"boolean"}},"required":["success","deleted"]}}}}},"operationId":"postBffBranchHoldingUnlink","tags":["Branch"],"description":"Hard-deletes the holding-link row. Always scoped by organisation. Idempotent — deleting a missing row returns `{ deleted: false }` rather than throwing.","summary":"Delete a holding link","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["linkId"],"properties":{"linkId":{"description":"Internal id of the holding-link row (from /holding-tree).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["linkId"],"properties":{"linkId":{"description":"Internal id of the holding-link row (from /holding-tree).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["linkId"],"properties":{"linkId":{"description":"Internal id of the holding-link row (from /holding-tree).","type":"string"}}}}}}}},"/bff/branch/attachable-locks":{"get":{"parameters":[{"description":"Branch slug — locks already attached to this branch are flagged.","schema":{"type":"string"},"in":"query","name":"slug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["lockId","active","attached"],"properties":{"lockId":{"type":"number"},"alias":{"type":"string"},"electricQuantity":{"type":"number"},"hasGateway":{"type":"boolean"},"active":{"type":"boolean"},"attached":{"description":"True if already attached to this branch.","type":"boolean"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["lockId","active","attached"],"properties":{"lockId":{"type":"number"},"alias":{"type":"string"},"electricQuantity":{"type":"number"},"hasGateway":{"type":"boolean"},"active":{"type":"boolean"},"attached":{"description":"True if already attached to this branch.","type":"boolean"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["lockId","active","attached"],"properties":{"lockId":{"type":"number"},"alias":{"type":"string"},"electricQuantity":{"type":"number"},"hasGateway":{"type":"boolean"},"active":{"type":"boolean"},"attached":{"description":"True if already attached to this branch.","type":"boolean"}}}}},"required":["items"]}}}}},"operationId":"getBffBranchAttachable-locks","tags":["Branch"],"description":"Returns every lock in the organisation that is either unattached or already attached to THIS branch. Locks linked to a different branch are filtered out — the operator must detach them first.","summary":"List locks available to attach"}},"/bff/branch/attach-lock":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"lockId":{"type":"number"},"branchId":{"type":"number"},"branchSlug":{"type":"string"}},"required":["success","lockId","branchId","branchSlug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"lockId":{"type":"number"},"branchId":{"type":"number"},"branchSlug":{"type":"string"}},"required":["success","lockId","branchId","branchSlug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"lockId":{"type":"number"},"branchId":{"type":"number"},"branchSlug":{"type":"string"}},"required":["success","lockId","branchId","branchSlug"]}}}}},"operationId":"postBffBranchAttach-lock","tags":["Branch"],"description":"Sets iot__ttlock_lock.branch_id to the branch identified by `slug`. Overwrites any previous branch assignment on the lock — locks have at-most-one branch. The branch then becomes the operational technical contact for the lock.","summary":"Attach a lock to a branch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","lockId"],"properties":{"slug":{"description":"Branch slug to attach the lock to.","type":"string"},"lockId":{"description":"External TTLock identifier (matches the lock detail URL).","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","lockId"],"properties":{"slug":{"description":"Branch slug to attach the lock to.","type":"string"},"lockId":{"description":"External TTLock identifier (matches the lock detail URL).","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["slug","lockId"],"properties":{"slug":{"description":"Branch slug to attach the lock to.","type":"string"},"lockId":{"description":"External TTLock identifier (matches the lock detail URL).","type":"number"}}}}}}}},"/bff/branch/order-items-summary":{"get":{"parameters":[{"description":"Branch slug.","examples":["gymroom-plzen"],"schema":{"type":"string"},"in":"query","name":"branchSlug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"branchId":{"type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"currency":{"description":"ISO 4217 code of the organisation default currency.","type":"string"},"totalPriceMoney":{"type":"number"},"totalCreditAmount":{"type":"number"},"itemCount":{"type":"number"},"franchiseFeePercentage":{"description":"Franchise fee skimmed off turnover, in percent. Omitted when not configured.","type":"number"},"franchiseFeeAmount":{"description":"totalPriceMoney × franchiseFeePercentage ÷ 100, rounded. Omitted when not configured.","type":"number"},"franchiseFeeRemainder":{"description":"totalPriceMoney − franchiseFeeAmount. Omitted when not configured.","type":"number"}},"required":["branchId","branchSlug","branchName","currency","totalPriceMoney","totalCreditAmount","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"branchId":{"type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"currency":{"description":"ISO 4217 code of the organisation default currency.","type":"string"},"totalPriceMoney":{"type":"number"},"totalCreditAmount":{"type":"number"},"itemCount":{"type":"number"},"franchiseFeePercentage":{"description":"Franchise fee skimmed off turnover, in percent. Omitted when not configured.","type":"number"},"franchiseFeeAmount":{"description":"totalPriceMoney × franchiseFeePercentage ÷ 100, rounded. Omitted when not configured.","type":"number"},"franchiseFeeRemainder":{"description":"totalPriceMoney − franchiseFeeAmount. Omitted when not configured.","type":"number"}},"required":["branchId","branchSlug","branchName","currency","totalPriceMoney","totalCreditAmount","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"branchId":{"type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"currency":{"description":"ISO 4217 code of the organisation default currency.","type":"string"},"totalPriceMoney":{"type":"number"},"totalCreditAmount":{"type":"number"},"itemCount":{"type":"number"},"franchiseFeePercentage":{"description":"Franchise fee skimmed off turnover, in percent. Omitted when not configured.","type":"number"},"franchiseFeeAmount":{"description":"totalPriceMoney × franchiseFeePercentage ÷ 100, rounded. Omitted when not configured.","type":"number"},"franchiseFeeRemainder":{"description":"totalPriceMoney − franchiseFeeAmount. Omitted when not configured.","type":"number"}},"required":["branchId","branchSlug","branchName","currency","totalPriceMoney","totalCreditAmount","itemCount"]}}}}},"operationId":"getBffBranchOrder-items-summary","tags":["Branch"],"description":"Returns the headline numbers (total turnover, total credit balance, total item count, currency, branch name) over EVERY `shop__order_item` attributed to the branch. Independent of pagination — drives the header above the paginated `/order-items` grid. When the branch has a `franchise_fee_percentage` configured the response also includes the rounded fee amount and remainder; otherwise those fields are omitted so the admin hides the franchise row.","summary":"Headline aggregates for the branch order-item ledger"}},"/bff/branch/order-items":{"get":{"parameters":[{"description":"Branch slug.","examples":["gymroom-plzen"],"schema":{"type":"string"},"in":"query","name":"branchSlug","required":true},{"description":"Page number (1-based).","schema":{"minimum":1,"anyOf":[{"format":"numeric","default":0,"type":"string"},{"minimum":1,"description":"Page number (1-based).","type":"number"}]},"in":"query","name":"page","required":false},{"description":"Items per page.","schema":{"minimum":1,"maximum":500,"anyOf":[{"format":"numeric","default":0,"type":"string"},{"minimum":1,"maximum":500,"description":"Items per page.","type":"number"}]},"in":"query","name":"limit","required":false},{"description":"Sort directive in `field:direction` form. Supported fields: insertedDate, label, count, price, sale, creditAmount, order, customer.","examples":["insertedDate:desc","price:asc"],"schema":{"type":"string"},"in":"query","name":"orderBy","required":false},{"description":"Free-text search across label, order number and customer fields.","schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","label","count","price","sale","creditAmount","isStorno","insertedDate","order"],"properties":{"id":{"description":"External item id (\"hash_internalId\") for cross-references.","type":"string"},"label":{"type":"string"},"count":{"type":"number"},"price":{"description":"Unit price in the order currency.","type":"number"},"sale":{"description":"Per-line discount in the order currency.","type":"number"},"unit":{"type":"string"},"vat":{"type":"number"},"creditAmount":{"type":"number"},"isStorno":{"type":"boolean"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"order":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"},"payDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"statusCode":{"type":"string"}}},"customer":{"type":"object","required":["contactId"],"properties":{"contactId":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"}}}}}},"itemCount":{"description":"Total number of items matching the current filter — paginator denominator.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","label","count","price","sale","creditAmount","isStorno","insertedDate","order"],"properties":{"id":{"description":"External item id (\"hash_internalId\") for cross-references.","type":"string"},"label":{"type":"string"},"count":{"type":"number"},"price":{"description":"Unit price in the order currency.","type":"number"},"sale":{"description":"Per-line discount in the order currency.","type":"number"},"unit":{"type":"string"},"vat":{"type":"number"},"creditAmount":{"type":"number"},"isStorno":{"type":"boolean"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"order":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"},"payDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"statusCode":{"type":"string"}}},"customer":{"type":"object","required":["contactId"],"properties":{"contactId":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"}}}}}},"itemCount":{"description":"Total number of items matching the current filter — paginator denominator.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","label","count","price","sale","creditAmount","isStorno","insertedDate","order"],"properties":{"id":{"description":"External item id (\"hash_internalId\") for cross-references.","type":"string"},"label":{"type":"string"},"count":{"type":"number"},"price":{"description":"Unit price in the order currency.","type":"number"},"sale":{"description":"Per-line discount in the order currency.","type":"number"},"unit":{"type":"string"},"vat":{"type":"number"},"creditAmount":{"type":"number"},"isStorno":{"type":"boolean"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"order":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"},"payDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"statusCode":{"type":"string"}}},"customer":{"type":"object","required":["contactId"],"properties":{"contactId":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"}}}}}},"itemCount":{"description":"Total number of items matching the current filter — paginator denominator.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffBranchOrder-items","tags":["Branch"],"description":"Returns one DataGrid page of `shop__order_item` rows whose `branch_id` resolves to the requested branch. Drives the \"Order items\" tab grid in `apiUrl` mode — accepts `page`, `limit`, `orderBy`, `filterFulltextQuery` and returns `{ items, itemCount }` where `itemCount` is the count over the FILTERED set so the paginator math is correct. Use `/order-items-summary` for the header turnover / credit / total-item-count numbers.","summary":"Paginated list of order items attributed to a branch"}},"/bff/branch/customers-summary":{"get":{"parameters":[{"description":"Branch slug.","examples":["gymroom-plzen"],"schema":{"type":"string"},"in":"query","name":"branchSlug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"branchId":{"type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"itemCount":{"type":"number"}},"required":["branchId","branchSlug","branchName","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"branchId":{"type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"itemCount":{"type":"number"}},"required":["branchId","branchSlug","branchName","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"branchId":{"type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"itemCount":{"type":"number"}},"required":["branchId","branchSlug","branchName","itemCount"]}}}}},"operationId":"getBffBranchCustomers-summary","tags":["Branch"],"description":"Returns the total count of distinct customers attached to the branch via `shop__order_item.branch_id`. Drives the header above the paginated `/customers` grid.","summary":"Headline aggregates for the branch customer ledger"}},"/bff/branch/customers":{"get":{"parameters":[{"description":"Branch slug.","examples":["gymroom-plzen"],"schema":{"type":"string"},"in":"query","name":"branchSlug","required":true},{"description":"Page number (1-based).","schema":{"minimum":1,"anyOf":[{"format":"numeric","default":0,"type":"string"},{"minimum":1,"description":"Page number (1-based).","type":"number"}]},"in":"query","name":"page","required":false},{"description":"Items per page.","schema":{"minimum":1,"maximum":500,"anyOf":[{"format":"numeric","default":0,"type":"string"},{"minimum":1,"maximum":500,"description":"Items per page.","type":"number"}]},"in":"query","name":"limit","required":false},{"description":"Sort directive in `field:direction` form. Supported fields: firstVisitDate, lastVisitDate, orderCount, itemCount, totalRevenue, name, email.","examples":["lastVisitDate:desc","totalRevenue:desc"],"schema":{"type":"string"},"in":"query","name":"orderBy","required":false},{"description":"Free-text search across name, email and phone.","schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","email","firstVisitDate","lastVisitDate","orderCount","itemCount","totalRevenue","lastOrder","score","accountAgeDays","orderPaid","orderNotPaid","orderNew","orderProcessing","orderStorno","orderDone"],"properties":{"id":{"description":"Contact external id.","type":"string"},"name":{"description":"Pre-formatted display name: \"First Last (Company)\" if both, else whichever is available.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts — UI should fall back to `name` / `companyName` / `phone`.","type":"string"},{"type":"null"}]},"phone":{"type":"string"},"firstVisitDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastVisitDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderCount":{"type":"number"},"itemCount":{"type":"number"},"totalRevenue":{"description":"Sum of (price × count − sale) over every order item the customer has at this branch; storno items subtract.","type":"number"},"lastOrder":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"}}},"score":{"type":"number"},"accountAgeDays":{"type":"number"},"orderPaid":{"type":"number"},"orderNotPaid":{"type":"number"},"orderNew":{"type":"number"},"orderProcessing":{"type":"number"},"orderStorno":{"type":"number"},"orderDone":{"type":"number"}}}},"itemCount":{"description":"Total number of distinct customers matching the current filter — paginator denominator.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","email","firstVisitDate","lastVisitDate","orderCount","itemCount","totalRevenue","lastOrder","score","accountAgeDays","orderPaid","orderNotPaid","orderNew","orderProcessing","orderStorno","orderDone"],"properties":{"id":{"description":"Contact external id.","type":"string"},"name":{"description":"Pre-formatted display name: \"First Last (Company)\" if both, else whichever is available.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts — UI should fall back to `name` / `companyName` / `phone`.","type":"string"},{"type":"null"}]},"phone":{"type":"string"},"firstVisitDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastVisitDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderCount":{"type":"number"},"itemCount":{"type":"number"},"totalRevenue":{"description":"Sum of (price × count − sale) over every order item the customer has at this branch; storno items subtract.","type":"number"},"lastOrder":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"}}},"score":{"type":"number"},"accountAgeDays":{"type":"number"},"orderPaid":{"type":"number"},"orderNotPaid":{"type":"number"},"orderNew":{"type":"number"},"orderProcessing":{"type":"number"},"orderStorno":{"type":"number"},"orderDone":{"type":"number"}}}},"itemCount":{"description":"Total number of distinct customers matching the current filter — paginator denominator.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","email","firstVisitDate","lastVisitDate","orderCount","itemCount","totalRevenue","lastOrder","score","accountAgeDays","orderPaid","orderNotPaid","orderNew","orderProcessing","orderStorno","orderDone"],"properties":{"id":{"description":"Contact external id.","type":"string"},"name":{"description":"Pre-formatted display name: \"First Last (Company)\" if both, else whichever is available.","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts — UI should fall back to `name` / `companyName` / `phone`.","type":"string"},{"type":"null"}]},"phone":{"type":"string"},"firstVisitDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastVisitDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderCount":{"type":"number"},"itemCount":{"type":"number"},"totalRevenue":{"description":"Sum of (price × count − sale) over every order item the customer has at this branch; storno items subtract.","type":"number"},"lastOrder":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"}}},"score":{"type":"number"},"accountAgeDays":{"type":"number"},"orderPaid":{"type":"number"},"orderNotPaid":{"type":"number"},"orderNew":{"type":"number"},"orderProcessing":{"type":"number"},"orderStorno":{"type":"number"},"orderDone":{"type":"number"}}}},"itemCount":{"description":"Total number of distinct customers matching the current filter — paginator denominator.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffBranchCustomers","tags":["Branch"],"description":"Returns one DataGrid page of distinct customers (`shop__contact`) that have at least one `shop__order_item` attributed to the branch via `branch_id`. Drives the \"Customers\" tab grid in `apiUrl` mode — accepts `page`, `limit`, `orderBy`, `filterFulltextQuery`. `itemCount` is the count over the FILTERED set so paginator math is correct. Use `/customers-summary` for the header total.","summary":"Paginated list of customers who visited a branch"}},"/bff/branch/detach-lock":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"lockId":{"type":"number"},"branchSlug":{"type":"string"}},"required":["success","lockId","branchSlug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"lockId":{"type":"number"},"branchSlug":{"type":"string"}},"required":["success","lockId","branchSlug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"lockId":{"type":"number"},"branchSlug":{"type":"string"}},"required":["success","lockId","branchSlug"]}}}}},"operationId":"postBffBranchDetach-lock","tags":["Branch"],"description":"Sets iot__ttlock_lock.branch_id back to NULL. Rejects when the lock is attached to a different branch than `slug` — that protects against stale-UI races.","summary":"Detach a lock from a branch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","lockId"],"properties":{"slug":{"description":"Branch slug the lock is currently attached to.","type":"string"},"lockId":{"description":"External TTLock identifier of the lock to detach.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["slug","lockId"],"properties":{"slug":{"description":"Branch slug the lock is currently attached to.","type":"string"},"lockId":{"description":"External TTLock identifier of the lock to detach.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["slug","lockId"],"properties":{"slug":{"description":"Branch slug the lock is currently attached to.","type":"string"},"lockId":{"description":"External TTLock identifier of the lock to detach.","type":"number"}}}}}}}},"/bff/branch-writeoff/list":{"get":{"parameters":[{"description":"Branch slug.","examples":["flagship-praha-1"],"schema":{"type":"string"},"in":"query","name":"branchSlug","required":true}],"operationId":"getBffBranch-writeoffList","tags":["Branch Writeoff"],"summary":"List branch write-offs","description":"Returns the append-only ledger of monetary write-offs (oprávky) recorded against a branch, ordered by effective date desc. `total` is the signed sum of all entries in the organisation's default currency.","responses":{"200":{}}}},"/bff/branch-writeoff/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"transactionId":{"description":"External ID of the created write-off (16 chars).","type":"string"}},"required":["success","transactionId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"transactionId":{"description":"External ID of the created write-off (16 chars).","type":"string"}},"required":["success","transactionId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"transactionId":{"description":"External ID of the created write-off (16 chars).","type":"string"}},"required":["success","transactionId"]}}}}},"operationId":"postBffBranch-writeoffCreate","tags":["Branch Writeoff"],"summary":"Create branch write-off","description":"Appends a new write-off entry to a branch. The entry is immutable — there is no delete or update endpoint; mistakes are corrected by booking a compensating entry with the opposite sign. The author is auto-resolved from the logged-in identity.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["branchSlug","amountMoney","description","effectiveDate"],"properties":{"branchSlug":{"description":"Branch slug.","examples":["flagship-praha-1"],"type":"string"},"amountMoney":{"description":"Signed write-off amount in the organisation default currency (whole units, e.g. CZK). Positive credits the branch, negative debits it. Zero is rejected.","examples":[-1500,250],"type":"number"},"description":{"description":"Reason / description of the write-off. Required for audit transparency.","minLength":1,"maxLength":1000,"examples":["Reklamace úklidu — neuhrazená sleva pro objednávku 25000087."],"type":"string"},"effectiveDate":{"description":"ISO date when the write-off actually took effect (\"datum započtení\").","examples":["2026-05-31"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["branchSlug","amountMoney","description","effectiveDate"],"properties":{"branchSlug":{"description":"Branch slug.","examples":["flagship-praha-1"],"type":"string"},"amountMoney":{"description":"Signed write-off amount in the organisation default currency (whole units, e.g. CZK). Positive credits the branch, negative debits it. Zero is rejected.","examples":[-1500,250],"type":"number"},"description":{"description":"Reason / description of the write-off. Required for audit transparency.","minLength":1,"maxLength":1000,"examples":["Reklamace úklidu — neuhrazená sleva pro objednávku 25000087."],"type":"string"},"effectiveDate":{"description":"ISO date when the write-off actually took effect (\"datum započtení\").","examples":["2026-05-31"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["branchSlug","amountMoney","description","effectiveDate"],"properties":{"branchSlug":{"description":"Branch slug.","examples":["flagship-praha-1"],"type":"string"},"amountMoney":{"description":"Signed write-off amount in the organisation default currency (whole units, e.g. CZK). Positive credits the branch, negative debits it. Zero is rejected.","examples":[-1500,250],"type":"number"},"description":{"description":"Reason / description of the write-off. Required for audit transparency.","minLength":1,"maxLength":1000,"examples":["Reklamace úklidu — neuhrazená sleva pro objednávku 25000087."],"type":"string"},"effectiveDate":{"description":"ISO date when the write-off actually took effect (\"datum započtení\").","examples":["2026-05-31"],"type":"string"}}}}}}}},"/bff/calendar/calendar-list":{"get":{"responses":{"200":{"description":"List of calendars with live event status.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Calendar item with live status.","type":"object","required":["id","name","color","timezone","insertedDate","hasLock","totalEvents","upcomingEvents"],"properties":{"id":{"description":"External calendar code.","type":"string"},"name":{"description":"Calendar display name.","type":"string"},"internalDescription":{"description":"Internal note (not shown to customers).","type":"string"},"color":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"insertedDate":{"description":"Date when the calendar was created.","anyOf":[{"description":"Date when the calendar was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"hasLock":{"description":"Whether a smart lock device is connected.","type":"boolean"},"totalEvents":{"description":"Total number of non-cancelled events.","type":"number"},"upcomingEvents":{"description":"Number of future events (start_time > now).","type":"number"},"currentEvent":{"description":"Event that is running right now (start <= now < end). Undefined if idle.","type":"object","required":["id","title","startTime","endTime"],"properties":{"id":{"description":"External event code.","type":"string"},"title":{"description":"Title of the currently running event.","type":"string"},"startTime":{"description":"Start time of the current event.","anyOf":[{"description":"Start time of the current event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"End time of the current event.","anyOf":[{"description":"End time of the current event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"nextEvent":{"description":"Nearest future event. Undefined if nothing is scheduled.","type":"object","required":["id","title","startTime"],"properties":{"id":{"description":"External event code.","type":"string"},"title":{"description":"Title of the next upcoming event.","type":"string"},"startTime":{"description":"Start time of the next event.","anyOf":[{"description":"Start time of the next event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"lastEventEnd":{"description":"End time of the most recent past event. Useful for \"last active\" display.","anyOf":[{"description":"End time of the most recent past event. Useful for \"last active\" display.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of calendars returned.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Calendar item with live status.","type":"object","required":["id","name","color","timezone","insertedDate","hasLock","totalEvents","upcomingEvents"],"properties":{"id":{"description":"External calendar code.","type":"string"},"name":{"description":"Calendar display name.","type":"string"},"internalDescription":{"description":"Internal note (not shown to customers).","type":"string"},"color":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"insertedDate":{"description":"Date when the calendar was created.","anyOf":[{"description":"Date when the calendar was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"hasLock":{"description":"Whether a smart lock device is connected.","type":"boolean"},"totalEvents":{"description":"Total number of non-cancelled events.","type":"number"},"upcomingEvents":{"description":"Number of future events (start_time > now).","type":"number"},"currentEvent":{"description":"Event that is running right now (start <= now < end). Undefined if idle.","type":"object","required":["id","title","startTime","endTime"],"properties":{"id":{"description":"External event code.","type":"string"},"title":{"description":"Title of the currently running event.","type":"string"},"startTime":{"description":"Start time of the current event.","anyOf":[{"description":"Start time of the current event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"End time of the current event.","anyOf":[{"description":"End time of the current event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"nextEvent":{"description":"Nearest future event. Undefined if nothing is scheduled.","type":"object","required":["id","title","startTime"],"properties":{"id":{"description":"External event code.","type":"string"},"title":{"description":"Title of the next upcoming event.","type":"string"},"startTime":{"description":"Start time of the next event.","anyOf":[{"description":"Start time of the next event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"lastEventEnd":{"description":"End time of the most recent past event. Useful for \"last active\" display.","anyOf":[{"description":"End time of the most recent past event. Useful for \"last active\" display.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of calendars returned.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Calendar item with live status.","type":"object","required":["id","name","color","timezone","insertedDate","hasLock","totalEvents","upcomingEvents"],"properties":{"id":{"description":"External calendar code.","type":"string"},"name":{"description":"Calendar display name.","type":"string"},"internalDescription":{"description":"Internal note (not shown to customers).","type":"string"},"color":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"insertedDate":{"description":"Date when the calendar was created.","anyOf":[{"description":"Date when the calendar was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"hasLock":{"description":"Whether a smart lock device is connected.","type":"boolean"},"totalEvents":{"description":"Total number of non-cancelled events.","type":"number"},"upcomingEvents":{"description":"Number of future events (start_time > now).","type":"number"},"currentEvent":{"description":"Event that is running right now (start <= now < end). Undefined if idle.","type":"object","required":["id","title","startTime","endTime"],"properties":{"id":{"description":"External event code.","type":"string"},"title":{"description":"Title of the currently running event.","type":"string"},"startTime":{"description":"Start time of the current event.","anyOf":[{"description":"Start time of the current event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"End time of the current event.","anyOf":[{"description":"End time of the current event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"nextEvent":{"description":"Nearest future event. Undefined if nothing is scheduled.","type":"object","required":["id","title","startTime"],"properties":{"id":{"description":"External event code.","type":"string"},"title":{"description":"Title of the next upcoming event.","type":"string"},"startTime":{"description":"Start time of the next event.","anyOf":[{"description":"Start time of the next event.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"lastEventEnd":{"description":"End time of the most recent past event. Useful for \"last active\" display.","anyOf":[{"description":"End time of the most recent past event. Useful for \"last active\" display.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of calendars returned.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffCalendarCalendar-list","tags":["Calendar"],"summary":"List calendars","description":"Returns all calendars accessible to the authenticated member. Includes live status: currently running event, next upcoming event, and statistics."}},"/bff/calendar/calendar-detail":{"get":{"parameters":[{"description":"External calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"Calendar view mode (e.g., \"day\", \"week\", \"month\", \"report\").","schema":{"type":"string"},"in":"query","name":"view","required":true},{"description":"ISO date string to load events from. Defaults to now.","schema":{"type":"string"},"in":"query","name":"selectorFrom","required":false}],"operationId":"getBffCalendarCalendar-detail","tags":["Calendar"],"summary":"Get calendar detail","description":"Returns calendar metadata and events for the given view and date range. Requires the authenticated member to have permission on the calendar.","responses":{"200":{}}}},"/bff/calendar/calendar-settings":{"get":{"parameters":[{"description":"External calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"operationId":"getBffCalendarCalendar-settings","tags":["Calendar"],"summary":"Get calendar settings (admin shape)","description":"Returns the flat calendar configuration consumed by the admin \"Nastavení kalendáře\" dialog. Field names map one-to-one with the admin form: publicDescription / internalDescription refer to the calendar entity, settingsPublicDescription / settingsInternalDescription to the reservation-page \"important info\" block.","responses":{"200":{}}}},"/bff/calendar/calendar-settings-update":{"post":{"parameters":[],"operationId":"postBffCalendarCalendar-settings-update","tags":["Calendar"],"summary":"Update calendar settings","description":"Partially updates calendar settings. Only provided fields are changed. Requires the authenticated member to have permission on the calendar.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"External calendar code identifier.","type":"string"},"name":{"description":"Calendar display name.","type":"string"},"color":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"publicDescription":{"nullable":true,"anyOf":[{"description":"Public description shown to customers.","type":"string"},{"type":"null"}]},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal note (not shown to customers).","type":"string"},{"type":"null"}]},"emailDescription":{"nullable":true,"anyOf":[{"description":"Description included in email notifications.","type":"string"},{"type":"null"}]},"defaultLocationTitle":{"nullable":true,"anyOf":[{"description":"Default location title for new events.","type":"string"},{"type":"null"}]},"productId":{"nullable":true,"anyOf":[{"description":"Linked product ID.","type":"number"},{"type":"null"}]},"variantId":{"nullable":true,"anyOf":[{"description":"Linked product variant ID.","type":"number"},{"type":"null"}]},"settingsPublicDescription":{"nullable":true,"anyOf":[{"description":"Public description in settings context.","type":"string"},{"type":"null"}]},"settingsInternalDescription":{"nullable":true,"anyOf":[{"description":"Internal description in settings context.","type":"string"},{"type":"null"}]},"onlineChangeDeadline":{"description":"Deadline for online changes (ISO duration or similar).","type":"string"},"reserveFrom":{"description":"Earliest time customers can reserve.","type":"string"},"reserveUntil":{"description":"Latest time customers can reserve.","type":"string"},"timeSlotInterval":{"description":"Time slot interval for the booking grid.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"External calendar code identifier.","type":"string"},"name":{"description":"Calendar display name.","type":"string"},"color":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"publicDescription":{"nullable":true,"anyOf":[{"description":"Public description shown to customers.","type":"string"},{"type":"null"}]},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal note (not shown to customers).","type":"string"},{"type":"null"}]},"emailDescription":{"nullable":true,"anyOf":[{"description":"Description included in email notifications.","type":"string"},{"type":"null"}]},"defaultLocationTitle":{"nullable":true,"anyOf":[{"description":"Default location title for new events.","type":"string"},{"type":"null"}]},"productId":{"nullable":true,"anyOf":[{"description":"Linked product ID.","type":"number"},{"type":"null"}]},"variantId":{"nullable":true,"anyOf":[{"description":"Linked product variant ID.","type":"number"},{"type":"null"}]},"settingsPublicDescription":{"nullable":true,"anyOf":[{"description":"Public description in settings context.","type":"string"},{"type":"null"}]},"settingsInternalDescription":{"nullable":true,"anyOf":[{"description":"Internal description in settings context.","type":"string"},{"type":"null"}]},"onlineChangeDeadline":{"description":"Deadline for online changes (ISO duration or similar).","type":"string"},"reserveFrom":{"description":"Earliest time customers can reserve.","type":"string"},"reserveUntil":{"description":"Latest time customers can reserve.","type":"string"},"timeSlotInterval":{"description":"Time slot interval for the booking grid.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"External calendar code identifier.","type":"string"},"name":{"description":"Calendar display name.","type":"string"},"color":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"publicDescription":{"nullable":true,"anyOf":[{"description":"Public description shown to customers.","type":"string"},{"type":"null"}]},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal note (not shown to customers).","type":"string"},{"type":"null"}]},"emailDescription":{"nullable":true,"anyOf":[{"description":"Description included in email notifications.","type":"string"},{"type":"null"}]},"defaultLocationTitle":{"nullable":true,"anyOf":[{"description":"Default location title for new events.","type":"string"},{"type":"null"}]},"productId":{"nullable":true,"anyOf":[{"description":"Linked product ID.","type":"number"},{"type":"null"}]},"variantId":{"nullable":true,"anyOf":[{"description":"Linked product variant ID.","type":"number"},{"type":"null"}]},"settingsPublicDescription":{"nullable":true,"anyOf":[{"description":"Public description in settings context.","type":"string"},{"type":"null"}]},"settingsInternalDescription":{"nullable":true,"anyOf":[{"description":"Internal description in settings context.","type":"string"},{"type":"null"}]},"onlineChangeDeadline":{"description":"Deadline for online changes (ISO duration or similar).","type":"string"},"reserveFrom":{"description":"Earliest time customers can reserve.","type":"string"},"reserveUntil":{"description":"Latest time customers can reserve.","type":"string"},"timeSlotInterval":{"description":"Time slot interval for the booking grid.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/calendar/calendar-analytics-lost-revenue-capacity":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"soldOutEvents":{"description":"Number of events where product was sold out.","type":"number"},"totalEventsAnalyzed":{"description":"Total number of events analyzed.","type":"number"},"soldOutRate":{"description":"Percentage of events that were sold out (0-100).","type":"number"},"avgRevenuePerAttendee":{"description":"Average revenue per attendee.","type":"number"},"estimatedLostRevenue":{"description":"Estimated lost revenue due to capacity constraints.","type":"number"},"estimatedLostAttendees":{"description":"Estimated number of attendees who could not book.","type":"number"}},"required":["soldOutEvents","totalEventsAnalyzed","soldOutRate","avgRevenuePerAttendee","estimatedLostRevenue","estimatedLostAttendees"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"soldOutEvents":{"description":"Number of events where product was sold out.","type":"number"},"totalEventsAnalyzed":{"description":"Total number of events analyzed.","type":"number"},"soldOutRate":{"description":"Percentage of events that were sold out (0-100).","type":"number"},"avgRevenuePerAttendee":{"description":"Average revenue per attendee.","type":"number"},"estimatedLostRevenue":{"description":"Estimated lost revenue due to capacity constraints.","type":"number"},"estimatedLostAttendees":{"description":"Estimated number of attendees who could not book.","type":"number"}},"required":["soldOutEvents","totalEventsAnalyzed","soldOutRate","avgRevenuePerAttendee","estimatedLostRevenue","estimatedLostAttendees"]}},"text/plain":{"schema":{"type":"object","properties":{"soldOutEvents":{"description":"Number of events where product was sold out.","type":"number"},"totalEventsAnalyzed":{"description":"Total number of events analyzed.","type":"number"},"soldOutRate":{"description":"Percentage of events that were sold out (0-100).","type":"number"},"avgRevenuePerAttendee":{"description":"Average revenue per attendee.","type":"number"},"estimatedLostRevenue":{"description":"Estimated lost revenue due to capacity constraints.","type":"number"},"estimatedLostAttendees":{"description":"Estimated number of attendees who could not book.","type":"number"}},"required":["soldOutEvents","totalEventsAnalyzed","soldOutRate","avgRevenuePerAttendee","estimatedLostRevenue","estimatedLostAttendees"]}}}}},"operationId":"getBffCalendarCalendar-analytics-lost-revenue-capacity","tags":["Calendar Analytics"],"summary":"Lost revenue due to capacity","description":"Estimates how much money was potentially lost because events were sold out. Uses average revenue per attendee and assumes at least 1 additional person wanted to book for each sold-out event."}},"/bff/calendar/calendar-analytics-report":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"timezone":{"description":"Calendar timezone.","type":"string"},"hourUsages":{"description":"Event count aggregated by hour of day.","type":"array","items":{"type":"object","required":["hourOfDay","eventCount"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"eventCount":{"description":"Number of events in this hour.","type":"number"}}}},"hourDayUsages":{"description":"Event count aggregated by hour and day of week (heatmap data).","type":"array","items":{"type":"object","required":["hourOfDay","eventCount"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"dayOfWeek":{"description":"Day of week (0=Sunday, 6=Saturday).","type":"number"},"eventCount":{"description":"Number of events.","type":"number"}}}}},"required":["timezone","hourUsages","hourDayUsages"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"timezone":{"description":"Calendar timezone.","type":"string"},"hourUsages":{"description":"Event count aggregated by hour of day.","type":"array","items":{"type":"object","required":["hourOfDay","eventCount"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"eventCount":{"description":"Number of events in this hour.","type":"number"}}}},"hourDayUsages":{"description":"Event count aggregated by hour and day of week (heatmap data).","type":"array","items":{"type":"object","required":["hourOfDay","eventCount"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"dayOfWeek":{"description":"Day of week (0=Sunday, 6=Saturday).","type":"number"},"eventCount":{"description":"Number of events.","type":"number"}}}}},"required":["timezone","hourUsages","hourDayUsages"]}},"text/plain":{"schema":{"type":"object","properties":{"timezone":{"description":"Calendar timezone.","type":"string"},"hourUsages":{"description":"Event count aggregated by hour of day.","type":"array","items":{"type":"object","required":["hourOfDay","eventCount"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"eventCount":{"description":"Number of events in this hour.","type":"number"}}}},"hourDayUsages":{"description":"Event count aggregated by hour and day of week (heatmap data).","type":"array","items":{"type":"object","required":["hourOfDay","eventCount"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"dayOfWeek":{"description":"Day of week (0=Sunday, 6=Saturday).","type":"number"},"eventCount":{"description":"Number of events.","type":"number"}}}}},"required":["timezone","hourUsages","hourDayUsages"]}}}}},"operationId":"getBffCalendarCalendar-analytics-report","tags":["Calendar Analytics"],"summary":"Get calendar analytics report","description":"Returns the default calendar analytics report with hourly usage patterns. Use the specific analytics endpoints for detailed metrics."}},"/bff/calendar/calendar-analytics-peak-hours-heatmap":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","required":["dayOfWeek","hourOfDay","eventCount"],"properties":{"dayOfWeek":{"description":"Day of week (0=Sunday, 6=Saturday).","type":"number"},"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"eventCount":{"description":"Number of events in this slot.","type":"number"}}}},"maxCount":{"description":"Maximum event count in any slot.","type":"number"}},"required":["data","maxCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","required":["dayOfWeek","hourOfDay","eventCount"],"properties":{"dayOfWeek":{"description":"Day of week (0=Sunday, 6=Saturday).","type":"number"},"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"eventCount":{"description":"Number of events in this slot.","type":"number"}}}},"maxCount":{"description":"Maximum event count in any slot.","type":"number"}},"required":["data","maxCount"]}},"text/plain":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","required":["dayOfWeek","hourOfDay","eventCount"],"properties":{"dayOfWeek":{"description":"Day of week (0=Sunday, 6=Saturday).","type":"number"},"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"eventCount":{"description":"Number of events in this slot.","type":"number"}}}},"maxCount":{"description":"Maximum event count in any slot.","type":"number"}},"required":["data","maxCount"]}}}}},"operationId":"getBffCalendarCalendar-analytics-peak-hours-heatmap","tags":["Calendar Analytics"],"summary":"Peak hours heatmap","description":"Shows when the calendar is most busy by day and hour - critical for pricing, capacity planning, and staffing decisions. Returns a matrix of day×hour with event counts."}},"/bff/calendar/calendar-analytics-weekend-vs-weekday":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"weekdayEvents":{"description":"Total events on weekdays (Mon-Fri).","type":"number"},"weekendEvents":{"description":"Total events on weekends (Sat-Sun).","type":"number"},"weekdayAvgPerDay":{"description":"Average events per weekday.","type":"number"},"weekendAvgPerDay":{"description":"Average events per weekend day.","type":"number"},"weekendRatio":{"description":"Weekend events as % of weekday events.","type":"number"}},"required":["weekdayEvents","weekendEvents","weekdayAvgPerDay","weekendAvgPerDay","weekendRatio"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"weekdayEvents":{"description":"Total events on weekdays (Mon-Fri).","type":"number"},"weekendEvents":{"description":"Total events on weekends (Sat-Sun).","type":"number"},"weekdayAvgPerDay":{"description":"Average events per weekday.","type":"number"},"weekendAvgPerDay":{"description":"Average events per weekend day.","type":"number"},"weekendRatio":{"description":"Weekend events as % of weekday events.","type":"number"}},"required":["weekdayEvents","weekendEvents","weekdayAvgPerDay","weekendAvgPerDay","weekendRatio"]}},"text/plain":{"schema":{"type":"object","properties":{"weekdayEvents":{"description":"Total events on weekdays (Mon-Fri).","type":"number"},"weekendEvents":{"description":"Total events on weekends (Sat-Sun).","type":"number"},"weekdayAvgPerDay":{"description":"Average events per weekday.","type":"number"},"weekendAvgPerDay":{"description":"Average events per weekend day.","type":"number"},"weekendRatio":{"description":"Weekend events as % of weekday events.","type":"number"}},"required":["weekdayEvents","weekendEvents","weekdayAvgPerDay","weekendAvgPerDay","weekendRatio"]}}}}},"operationId":"getBffCalendarCalendar-analytics-weekend-vs-weekday","tags":["Calendar Analytics"],"summary":"Weekend vs weekday comparison","description":"Compares customer behavior between weekdays and weekends. Shows total events, daily averages, and weekend ratio. Critical for weekend pricing and staffing decisions."}},"/bff/calendar/calendar-analytics-monthly-trend":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","required":["month","eventCount","year"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"eventCount":{"description":"Number of events in this month.","type":"number"},"year":{"description":"Year.","type":"number"}}}},"trend":{"description":"Overall trend direction.","anyOf":[{"const":"growing","type":"string"},{"const":"declining","type":"string"},{"const":"stable","type":"string"}]},"growthRate":{"description":"Growth rate percentage.","type":"number"}},"required":["data","trend","growthRate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","required":["month","eventCount","year"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"eventCount":{"description":"Number of events in this month.","type":"number"},"year":{"description":"Year.","type":"number"}}}},"trend":{"description":"Overall trend direction.","anyOf":[{"const":"growing","type":"string"},{"const":"declining","type":"string"},{"const":"stable","type":"string"}]},"growthRate":{"description":"Growth rate percentage.","type":"number"}},"required":["data","trend","growthRate"]}},"text/plain":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","required":["month","eventCount","year"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"eventCount":{"description":"Number of events in this month.","type":"number"},"year":{"description":"Year.","type":"number"}}}},"trend":{"description":"Overall trend direction.","anyOf":[{"const":"growing","type":"string"},{"const":"declining","type":"string"},{"const":"stable","type":"string"}]},"growthRate":{"description":"Growth rate percentage.","type":"number"}},"required":["data","trend","growthRate"]}}}}},"operationId":"getBffCalendarCalendar-analytics-monthly-trend","tags":["Calendar Analytics"],"summary":"Monthly utilization trend","description":"Shows if calendar usage is growing, declining, or stable over the past 12 months. Product health indicator with growth rate calculation."}},"/bff/calendar/calendar-analytics-top-event-types":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"object","required":["typeId","typeName","eventCount","percentage"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"eventCount":{"description":"Number of events of this type.","type":"number"},"percentage":{"description":"Percentage of total events.","type":"number"}}}},"totalEvents":{"description":"Total number of events analyzed.","type":"number"}},"required":["types","totalEvents"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"object","required":["typeId","typeName","eventCount","percentage"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"eventCount":{"description":"Number of events of this type.","type":"number"},"percentage":{"description":"Percentage of total events.","type":"number"}}}},"totalEvents":{"description":"Total number of events analyzed.","type":"number"}},"required":["types","totalEvents"]}},"text/plain":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"object","required":["typeId","typeName","eventCount","percentage"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"eventCount":{"description":"Number of events of this type.","type":"number"},"percentage":{"description":"Percentage of total events.","type":"number"}}}},"totalEvents":{"description":"Total number of events analyzed.","type":"number"}},"required":["types","totalEvents"]}}}}},"operationId":"getBffCalendarCalendar-analytics-top-event-types","tags":["Calendar Analytics"],"summary":"Top event types","description":"Shows which event types dominate the calendar - critical for scaling and resource allocation decisions. Returns top 10 types with counts and percentages."}},"/bff/calendar/calendar-analytics-utilization-rate":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total number of events.","type":"number"},"totalAttendees":{"description":"Total number of attendees.","type":"number"},"avgAttendeesPerEvent":{"description":"Average attendees per event.","type":"number"}},"required":["totalEvents","totalAttendees","avgAttendeesPerEvent"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total number of events.","type":"number"},"totalAttendees":{"description":"Total number of attendees.","type":"number"},"avgAttendeesPerEvent":{"description":"Average attendees per event.","type":"number"}},"required":["totalEvents","totalAttendees","avgAttendeesPerEvent"]}},"text/plain":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total number of events.","type":"number"},"totalAttendees":{"description":"Total number of attendees.","type":"number"},"avgAttendeesPerEvent":{"description":"Average attendees per event.","type":"number"}},"required":["totalEvents","totalAttendees","avgAttendeesPerEvent"]}}}}},"operationId":"getBffCalendarCalendar-analytics-utilization-rate","tags":["Calendar Analytics"],"summary":"Attendance utilization rate","description":"Shows average attendance per event - key metric for calendar usage. Analyzes events in 30-day window around current date."}},"/bff/calendar/calendar-analytics-sold-out-rate":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Number of events analyzed.","type":"number"},"topAttendedEvents":{"type":"array","items":{"type":"object","required":["eventId","title","attendeeCount"],"properties":{"eventId":{"description":"Event ID.","type":"number"},"title":{"description":"Event title.","type":"string"},"attendeeCount":{"description":"Number of attendees.","type":"number"}}}},"avgAttendeesPerEvent":{"description":"Average attendees per event.","type":"number"}},"required":["totalEvents","topAttendedEvents","avgAttendeesPerEvent"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Number of events analyzed.","type":"number"},"topAttendedEvents":{"type":"array","items":{"type":"object","required":["eventId","title","attendeeCount"],"properties":{"eventId":{"description":"Event ID.","type":"number"},"title":{"description":"Event title.","type":"string"},"attendeeCount":{"description":"Number of attendees.","type":"number"}}}},"avgAttendeesPerEvent":{"description":"Average attendees per event.","type":"number"}},"required":["totalEvents","topAttendedEvents","avgAttendeesPerEvent"]}},"text/plain":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Number of events analyzed.","type":"number"},"topAttendedEvents":{"type":"array","items":{"type":"object","required":["eventId","title","attendeeCount"],"properties":{"eventId":{"description":"Event ID.","type":"number"},"title":{"description":"Event title.","type":"string"},"attendeeCount":{"description":"Number of attendees.","type":"number"}}}},"avgAttendeesPerEvent":{"description":"Average attendees per event.","type":"number"}},"required":["totalEvents","topAttendedEvents","avgAttendeesPerEvent"]}}}}},"operationId":"getBffCalendarCalendar-analytics-sold-out-rate","tags":["Calendar Analytics"],"summary":"Event attendance analysis","description":"Shows which events have the most attendees - helps identify popular events. Returns top 10 most attended events."}},"/bff/calendar/calendar-analytics-lead-time-booking":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"averageDays":{"description":"Average booking lead time in days.","type":"number"},"medianDays":{"description":"Median booking lead time in days.","type":"number"},"distribution":{"type":"array","items":{"type":"object","required":["range","count","percentage"],"properties":{"range":{"description":"Time range (e.g., \"0-1 days\", \"2-7 days\").","type":"string"},"count":{"description":"Number of bookings in this range.","type":"number"},"percentage":{"description":"Percentage of total bookings.","type":"number"}}}}},"required":["averageDays","medianDays","distribution"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"averageDays":{"description":"Average booking lead time in days.","type":"number"},"medianDays":{"description":"Median booking lead time in days.","type":"number"},"distribution":{"type":"array","items":{"type":"object","required":["range","count","percentage"],"properties":{"range":{"description":"Time range (e.g., \"0-1 days\", \"2-7 days\").","type":"string"},"count":{"description":"Number of bookings in this range.","type":"number"},"percentage":{"description":"Percentage of total bookings.","type":"number"}}}}},"required":["averageDays","medianDays","distribution"]}},"text/plain":{"schema":{"type":"object","properties":{"averageDays":{"description":"Average booking lead time in days.","type":"number"},"medianDays":{"description":"Median booking lead time in days.","type":"number"},"distribution":{"type":"array","items":{"type":"object","required":["range","count","percentage"],"properties":{"range":{"description":"Time range (e.g., \"0-1 days\", \"2-7 days\").","type":"string"},"count":{"description":"Number of bookings in this range.","type":"number"},"percentage":{"description":"Percentage of total bookings.","type":"number"}}}}},"required":["averageDays","medianDays","distribution"]}}}}},"operationId":"getBffCalendarCalendar-analytics-lead-time-booking","tags":["Calendar Analytics"],"summary":"Lead time booking analysis","description":"Shows how far in advance people book events - critical for reminder timing and campaign planning. Includes average, median, and distribution by time ranges."}},"/bff/calendar/calendar-analytics-last-minute-bookings":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"totalBookings":{"description":"Total number of bookings.","type":"number"},"lastMinuteBookings":{"description":"Bookings made within 24 hours of event.","type":"number"},"lastMinuteRate":{"description":"Last-minute booking percentage (0-100).","type":"number"}},"required":["totalBookings","lastMinuteBookings","lastMinuteRate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalBookings":{"description":"Total number of bookings.","type":"number"},"lastMinuteBookings":{"description":"Bookings made within 24 hours of event.","type":"number"},"lastMinuteRate":{"description":"Last-minute booking percentage (0-100).","type":"number"}},"required":["totalBookings","lastMinuteBookings","lastMinuteRate"]}},"text/plain":{"schema":{"type":"object","properties":{"totalBookings":{"description":"Total number of bookings.","type":"number"},"lastMinuteBookings":{"description":"Bookings made within 24 hours of event.","type":"number"},"lastMinuteRate":{"description":"Last-minute booking percentage (0-100).","type":"number"}},"required":["totalBookings","lastMinuteBookings","lastMinuteRate"]}}}}},"operationId":"getBffCalendarCalendar-analytics-last-minute-bookings","tags":["Calendar Analytics"],"summary":"Last-minute bookings (<24h)","description":"Shows how many people book within 24 hours of event start. Useful for dynamic pricing strategies and last-minute promotions."}},"/bff/calendar/calendar-analytics-event-completion-rate":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total events in period.","type":"number"},"completedEvents":{"description":"Events that completed successfully.","type":"number"},"cancelledEvents":{"description":"Events that were cancelled.","type":"number"},"completionRate":{"description":"Completion percentage (0-100).","type":"number"},"cancellationRate":{"description":"Cancellation percentage (0-100).","type":"number"}},"required":["totalEvents","completedEvents","cancelledEvents","completionRate","cancellationRate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total events in period.","type":"number"},"completedEvents":{"description":"Events that completed successfully.","type":"number"},"cancelledEvents":{"description":"Events that were cancelled.","type":"number"},"completionRate":{"description":"Completion percentage (0-100).","type":"number"},"cancellationRate":{"description":"Cancellation percentage (0-100).","type":"number"}},"required":["totalEvents","completedEvents","cancelledEvents","completionRate","cancellationRate"]}},"text/plain":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total events in period.","type":"number"},"completedEvents":{"description":"Events that completed successfully.","type":"number"},"cancelledEvents":{"description":"Events that were cancelled.","type":"number"},"completionRate":{"description":"Completion percentage (0-100).","type":"number"},"cancellationRate":{"description":"Cancellation percentage (0-100).","type":"number"}},"required":["totalEvents","completedEvents","cancelledEvents","completionRate","cancellationRate"]}}}}},"operationId":"getBffCalendarCalendar-analytics-event-completion-rate","tags":["Calendar Analytics"],"summary":"Event completion rate","description":"Shows how many events actually happen versus get cancelled - operational stability indicator. High completion rate indicates reliable operations."}},"/bff/calendar/calendar-analytics-cancellation-analysis":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total number of events.","type":"number"},"cancelledEvents":{"description":"Number of cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation percentage (0-100).","type":"number"}},"required":["totalEvents","cancelledEvents","cancellationRate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total number of events.","type":"number"},"cancelledEvents":{"description":"Number of cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation percentage (0-100).","type":"number"}},"required":["totalEvents","cancelledEvents","cancellationRate"]}},"text/plain":{"schema":{"type":"object","properties":{"totalEvents":{"description":"Total number of events.","type":"number"},"cancelledEvents":{"description":"Number of cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation percentage (0-100).","type":"number"}},"required":["totalEvents","cancelledEvents","cancellationRate"]}}}}},"operationId":"getBffCalendarCalendar-analytics-cancellation-analysis","tags":["Calendar Analytics"],"summary":"Cancellation analysis","description":"Shows how often events get cancelled - operational stability indicator. Analyzes events from the last 90 days."}},"/bff/calendar/calendar-analytics-average-event-duration":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"overallAvgMinutes":{"description":"Overall average duration across all events.","type":"number"},"byType":{"type":"array","items":{"type":"object","required":["typeId","typeName","avgMinutes","eventCount"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"avgMinutes":{"description":"Average duration in minutes.","type":"number"},"eventCount":{"description":"Number of events of this type.","type":"number"}}}}},"required":["overallAvgMinutes","byType"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"overallAvgMinutes":{"description":"Overall average duration across all events.","type":"number"},"byType":{"type":"array","items":{"type":"object","required":["typeId","typeName","avgMinutes","eventCount"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"avgMinutes":{"description":"Average duration in minutes.","type":"number"},"eventCount":{"description":"Number of events of this type.","type":"number"}}}}},"required":["overallAvgMinutes","byType"]}},"text/plain":{"schema":{"type":"object","properties":{"overallAvgMinutes":{"description":"Overall average duration across all events.","type":"number"},"byType":{"type":"array","items":{"type":"object","required":["typeId","typeName","avgMinutes","eventCount"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"avgMinutes":{"description":"Average duration in minutes.","type":"number"},"eventCount":{"description":"Number of events of this type.","type":"number"}}}}},"required":["overallAvgMinutes","byType"]}}}}},"operationId":"getBffCalendarCalendar-analytics-average-event-duration","tags":["Calendar Analytics"],"summary":"Average event duration","description":"Shows how long events actually are, broken down by event type. Critical for realistic slot planning and capacity estimation."}},"/bff/calendar/calendar-analytics-simultaneous-events":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"maxSimultaneous":{"description":"Maximum concurrent events ever.","type":"number"},"avgSimultaneous":{"description":"Average concurrent events.","type":"number"},"currentSimultaneous":{"description":"Currently running events right now.","type":"number"}},"required":["maxSimultaneous","avgSimultaneous","currentSimultaneous"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"maxSimultaneous":{"description":"Maximum concurrent events ever.","type":"number"},"avgSimultaneous":{"description":"Average concurrent events.","type":"number"},"currentSimultaneous":{"description":"Currently running events right now.","type":"number"}},"required":["maxSimultaneous","avgSimultaneous","currentSimultaneous"]}},"text/plain":{"schema":{"type":"object","properties":{"maxSimultaneous":{"description":"Maximum concurrent events ever.","type":"number"},"avgSimultaneous":{"description":"Average concurrent events.","type":"number"},"currentSimultaneous":{"description":"Currently running events right now.","type":"number"}},"required":["maxSimultaneous","avgSimultaneous","currentSimultaneous"]}}}}},"operationId":"getBffCalendarCalendar-analytics-simultaneous-events","tags":["Calendar Analytics"],"summary":"Simultaneous events analysis","description":"Shows how many events run concurrently (max and average). Critical for understanding capacity and staffing limits."}},"/bff/calendar/calendar-analytics-revenue-per-event-type":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"object","required":["typeId","typeName","totalRevenue","eventCount","avgRevenuePerEvent","percentage"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"totalRevenue":{"description":"Total revenue from this type.","type":"number"},"eventCount":{"description":"Number of events.","type":"number"},"avgRevenuePerEvent":{"description":"Average revenue per event.","type":"number"},"percentage":{"description":"Percentage of total revenue.","type":"number"}}}},"totalRevenue":{"description":"Total revenue across all types.","type":"number"}},"required":["types","totalRevenue"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"object","required":["typeId","typeName","totalRevenue","eventCount","avgRevenuePerEvent","percentage"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"totalRevenue":{"description":"Total revenue from this type.","type":"number"},"eventCount":{"description":"Number of events.","type":"number"},"avgRevenuePerEvent":{"description":"Average revenue per event.","type":"number"},"percentage":{"description":"Percentage of total revenue.","type":"number"}}}},"totalRevenue":{"description":"Total revenue across all types.","type":"number"}},"required":["types","totalRevenue"]}},"text/plain":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"object","required":["typeId","typeName","totalRevenue","eventCount","avgRevenuePerEvent","percentage"],"properties":{"typeId":{"description":"Event type ID.","type":"number"},"typeName":{"description":"Event type name.","type":"string"},"totalRevenue":{"description":"Total revenue from this type.","type":"number"},"eventCount":{"description":"Number of events.","type":"number"},"avgRevenuePerEvent":{"description":"Average revenue per event.","type":"number"},"percentage":{"description":"Percentage of total revenue.","type":"number"}}}},"totalRevenue":{"description":"Total revenue across all types.","type":"number"}},"required":["types","totalRevenue"]}}}}},"operationId":"getBffCalendarCalendar-analytics-revenue-per-event-type","tags":["Calendar Analytics"],"summary":"Revenue per event type","description":"Shows which event types generate the most revenue - critical insight to avoid confusing utilization with profitability. Returns total revenue, event count, and average per event for each type."}},"/bff/calendar/calendar-analytics-revenue-per-hour":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"hourly":{"type":"array","items":{"type":"object","required":["hourOfDay","revenue","eventCount","avgRevenuePerEvent"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"revenue":{"description":"Total revenue in this hour.","type":"number"},"eventCount":{"description":"Number of events.","type":"number"},"avgRevenuePerEvent":{"description":"Average revenue per event.","type":"number"}}}},"peakHour":{"description":"Hour with highest revenue.","type":"number"},"peakRevenue":{"description":"Revenue in peak hour.","type":"number"},"totalRevenue":{"description":"Total revenue across all hours.","type":"number"}},"required":["hourly","peakHour","peakRevenue","totalRevenue"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"hourly":{"type":"array","items":{"type":"object","required":["hourOfDay","revenue","eventCount","avgRevenuePerEvent"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"revenue":{"description":"Total revenue in this hour.","type":"number"},"eventCount":{"description":"Number of events.","type":"number"},"avgRevenuePerEvent":{"description":"Average revenue per event.","type":"number"}}}},"peakHour":{"description":"Hour with highest revenue.","type":"number"},"peakRevenue":{"description":"Revenue in peak hour.","type":"number"},"totalRevenue":{"description":"Total revenue across all hours.","type":"number"}},"required":["hourly","peakHour","peakRevenue","totalRevenue"]}},"text/plain":{"schema":{"type":"object","properties":{"hourly":{"type":"array","items":{"type":"object","required":["hourOfDay","revenue","eventCount","avgRevenuePerEvent"],"properties":{"hourOfDay":{"description":"Hour of day (0-23).","type":"number"},"revenue":{"description":"Total revenue in this hour.","type":"number"},"eventCount":{"description":"Number of events.","type":"number"},"avgRevenuePerEvent":{"description":"Average revenue per event.","type":"number"}}}},"peakHour":{"description":"Hour with highest revenue.","type":"number"},"peakRevenue":{"description":"Revenue in peak hour.","type":"number"},"totalRevenue":{"description":"Total revenue across all hours.","type":"number"}},"required":["hourly","peakHour","peakRevenue","totalRevenue"]}}}}},"operationId":"getBffCalendarCalendar-analytics-revenue-per-hour","tags":["Calendar Analytics"],"summary":"Revenue per hour of day","description":"Shows how much each hour of the calendar day earns - brutally powerful metric for pricing optimization. Identifies peak revenue hours and opportunities for dynamic pricing."}},"/bff/calendar/calendar-analytics-time-to-fill":{"get":{"parameters":[{"description":"Calendar code identifier.","schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"averageHours":{"description":"Average hours to fill capacity.","type":"number"},"medianHours":{"description":"Median hours to fill capacity.","type":"number"},"fastestHours":{"description":"Fastest fill time ever recorded.","type":"number"},"distribution":{"type":"array","items":{"type":"object","required":["range","count","percentage"],"properties":{"range":{"description":"Time range (e.g., \"0-1 hours\").","type":"string"},"count":{"description":"Events that filled in this range.","type":"number"},"percentage":{"description":"Percentage of total filled events.","type":"number"}}}}},"required":["averageHours","medianHours","fastestHours","distribution"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"averageHours":{"description":"Average hours to fill capacity.","type":"number"},"medianHours":{"description":"Median hours to fill capacity.","type":"number"},"fastestHours":{"description":"Fastest fill time ever recorded.","type":"number"},"distribution":{"type":"array","items":{"type":"object","required":["range","count","percentage"],"properties":{"range":{"description":"Time range (e.g., \"0-1 hours\").","type":"string"},"count":{"description":"Events that filled in this range.","type":"number"},"percentage":{"description":"Percentage of total filled events.","type":"number"}}}}},"required":["averageHours","medianHours","fastestHours","distribution"]}},"text/plain":{"schema":{"type":"object","properties":{"averageHours":{"description":"Average hours to fill capacity.","type":"number"},"medianHours":{"description":"Median hours to fill capacity.","type":"number"},"fastestHours":{"description":"Fastest fill time ever recorded.","type":"number"},"distribution":{"type":"array","items":{"type":"object","required":["range","count","percentage"],"properties":{"range":{"description":"Time range (e.g., \"0-1 hours\").","type":"string"},"count":{"description":"Events that filled in this range.","type":"number"},"percentage":{"description":"Percentage of total filled events.","type":"number"}}}}},"required":["averageHours","medianHours","fastestHours","distribution"]}}}}},"operationId":"getBffCalendarCalendar-analytics-time-to-fill","tags":["Calendar Analytics"],"summary":"Time-to-fill analysis","description":"Shows how fast events fill to capacity - ideal metric for pricing optimization and demand prediction. Fast fill times indicate high demand and pricing power."}},"/bff/calendar/calendar-add":{"post":{"operationId":"postBffCalendarCalendar-add","tags":["Calendar"],"summary":"Create a new calendar","description":"Creates a new calendar for the authenticated organisation. Body is validated via createCalendarSchema.","responses":{"200":{}}}},"/bff/calendar/detail-reservations":{"get":{"parameters":[{"description":"Customer reference number to filter reservations by.","schema":{"type":"string"},"in":"query","name":"customerId","required":false},{"description":"Calendar code to filter reservations by.","schema":{"type":"string"},"in":"query","name":"calendarId","required":false},{"description":"Page number for pagination (default 1).","schema":{"type":"number"},"in":"query","name":"page","required":false},{"description":"Number of items per page (default 100).","schema":{"type":"number"},"in":"query","name":"limit","required":false}],"operationId":"getBffCalendarDetail-reservations","tags":["Calendar"],"summary":"List reservations","description":"Returns a paginated list of calendar event reservations. Can be filtered by customer and/or calendar.","responses":{"200":{}}}},"/bff/calendar/event-detail":{"get":{"parameters":[{"description":"External event code identifier.","schema":{"type":"string"},"in":"query","name":"eventId","required":true}],"responses":{"200":{"description":"Full event detail with all associated data.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"External event code identifier.","type":"string"},"calendarId":{"description":"External calendar code.","type":"string"},"calendarName":{"description":"Calendar display name.","type":"string"},"calendarColor":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"startTime":{"description":"Event start time (UTC).","anyOf":[{"description":"Event start time (UTC).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time (UTC).","anyOf":[{"description":"Event end time (UTC).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"durationMinutes":{"description":"Computed event duration in minutes.","type":"number"},"reservedBlockingTo":{"description":"Time until which the event blocks the calendar slot.","anyOf":[{"description":"Time until which the event blocks the calendar slot.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"description":"Event title.","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks conflicting reservations.","type":"boolean"},"isStorno":{"description":"Whether the event has been cancelled.","type":"boolean"},"isOpenButtonAvailable":{"description":"Whether a smart lock unlock button should be shown.","type":"boolean"},"typeCode":{"description":"Event type code (e.g., \"workshop\").","type":"string"},"typeLabel":{"description":"Event type display label.","type":"string"},"color":{"description":"Event type hex color.","type":"string"},"description":{"description":"Event description (rich text).","type":"string"},"agenda":{"description":"Event agenda / schedule.","type":"string"},"url":{"description":"External URL associated with the event.","type":"string"},"insertedDate":{"description":"Date when the event was created.","anyOf":[{"description":"Date when the event was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locationTitle":{"description":"Location name / label.","type":"string"},"location":{"description":"Full location address resolved from the address registry.","type":"object","properties":{"title":{"description":"Location name.","type":"string"},"streetAddress":{"description":"Street and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"postalCode":{"description":"Postal / ZIP code.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"cityPart":{"description":"City district / part.","type":"string"},"latitude":{"description":"GPS latitude.","type":"string"},"longitude":{"description":"GPS longitude.","type":"string"}}},"eventTypeProduct":{"description":"Product linked to the event type (for pricing / inventory).","type":"object","required":["code","name","price"],"properties":{"code":{"description":"Product code.","type":"string"},"name":{"description":"Product name.","type":"string"},"price":{"description":"Product price.","type":"string"}}},"reminderList":{"description":"Active reminders for this event.","type":"array","items":{"type":"object","required":["date","relativeTime"],"properties":{"date":{"description":"Absolute reminder trigger time.","anyOf":[{"description":"Absolute reminder trigger time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"relativeTime":{"description":"Relative time before event (e.g., \"30m\", \"1h\", \"1d\").","type":"string"}}}},"orderList":{"description":"Orders / reservations linked to this event.","type":"array","items":{"type":"object","required":["orderNumber","hash","paid","isStorno"],"properties":{"orderNumber":{"description":"Order number.","type":"string"},"hash":{"description":"Order hash for URL identification.","type":"string"},"paid":{"description":"Whether the order has been paid.","type":"boolean"},"isStorno":{"description":"Whether the order item is cancelled.","type":"boolean"},"customerId":{"description":"Customer external ID.","type":"string"},"customerName":{"description":"Customer full name.","type":"string"},"email":{"description":"Customer email.","type":"string"},"phone":{"description":"Customer phone.","type":"string"}}}},"attendeeList":{"description":"Event attendees / participants sorted by organizer status and date.","type":"array","items":{"type":"object","required":["organizer","required","accepted","insertedDate"],"properties":{"name":{"description":"Attendee name.","type":"string"},"email":{"description":"Attendee email.","type":"string"},"phone":{"description":"Attendee phone.","type":"string"},"organizer":{"description":"Whether this attendee is the event organizer.","type":"boolean"},"required":{"description":"Whether attendance is required.","type":"boolean"},"accepted":{"description":"Whether the attendee has accepted the invitation.","type":"boolean"},"insertedDate":{"description":"Date when the attendee was added.","anyOf":[{"description":"Date when the attendee was added.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"passwordList":{"description":"Smart lock passwords generated for this event.","type":"array","items":{"type":"object","required":["password","deleted"],"properties":{"password":{"description":"Smart lock temporary password.","type":"string"},"deleted":{"description":"Whether the password has been revoked.","type":"boolean"}}}},"reservation":{"description":"Reservation status when event type is linked to a product.","type":"object","required":["confirmed","limit"],"properties":{"confirmed":{"description":"Number of confirmed reservations.","type":"number"},"limit":{"description":"Maximum capacity from product warehouse limit.","type":"number"}}},"recurrence":{"description":"Recurrence series information with all related events.","type":"object","required":["isRecurrence","items"],"properties":{"isRecurrence":{"description":"Whether this event is part of a recurring series.","type":"boolean"},"items":{"type":"array","items":{"type":"object","required":["id","title","startTime","endTime","isStorno"],"properties":{"id":{"description":"External event code.","type":"string"},"isParent":{"description":"Whether this is the root/parent event.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"startTime":{"description":"Event start time.","anyOf":[{"description":"Event start time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time.","anyOf":[{"description":"Event end time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isStorno":{"description":"Whether this occurrence is cancelled.","type":"boolean"}}}}}},"recurrenceRule":{"description":"iCalendar RRULE string (e.g., \"FREQ=WEEKLY;BYDAY=MO,WE,FR\").","type":"string"}},"required":["id","calendarId","calendarName","calendarColor","timezone","startTime","endTime","durationMinutes","title","isAllDay","isBlocking","isStorno","insertedDate","reminderList","orderList","attendeeList","passwordList","recurrence"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"External event code identifier.","type":"string"},"calendarId":{"description":"External calendar code.","type":"string"},"calendarName":{"description":"Calendar display name.","type":"string"},"calendarColor":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"startTime":{"description":"Event start time (UTC).","anyOf":[{"description":"Event start time (UTC).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time (UTC).","anyOf":[{"description":"Event end time (UTC).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"durationMinutes":{"description":"Computed event duration in minutes.","type":"number"},"reservedBlockingTo":{"description":"Time until which the event blocks the calendar slot.","anyOf":[{"description":"Time until which the event blocks the calendar slot.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"description":"Event title.","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks conflicting reservations.","type":"boolean"},"isStorno":{"description":"Whether the event has been cancelled.","type":"boolean"},"isOpenButtonAvailable":{"description":"Whether a smart lock unlock button should be shown.","type":"boolean"},"typeCode":{"description":"Event type code (e.g., \"workshop\").","type":"string"},"typeLabel":{"description":"Event type display label.","type":"string"},"color":{"description":"Event type hex color.","type":"string"},"description":{"description":"Event description (rich text).","type":"string"},"agenda":{"description":"Event agenda / schedule.","type":"string"},"url":{"description":"External URL associated with the event.","type":"string"},"insertedDate":{"description":"Date when the event was created.","anyOf":[{"description":"Date when the event was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locationTitle":{"description":"Location name / label.","type":"string"},"location":{"description":"Full location address resolved from the address registry.","type":"object","properties":{"title":{"description":"Location name.","type":"string"},"streetAddress":{"description":"Street and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"postalCode":{"description":"Postal / ZIP code.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"cityPart":{"description":"City district / part.","type":"string"},"latitude":{"description":"GPS latitude.","type":"string"},"longitude":{"description":"GPS longitude.","type":"string"}}},"eventTypeProduct":{"description":"Product linked to the event type (for pricing / inventory).","type":"object","required":["code","name","price"],"properties":{"code":{"description":"Product code.","type":"string"},"name":{"description":"Product name.","type":"string"},"price":{"description":"Product price.","type":"string"}}},"reminderList":{"description":"Active reminders for this event.","type":"array","items":{"type":"object","required":["date","relativeTime"],"properties":{"date":{"description":"Absolute reminder trigger time.","anyOf":[{"description":"Absolute reminder trigger time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"relativeTime":{"description":"Relative time before event (e.g., \"30m\", \"1h\", \"1d\").","type":"string"}}}},"orderList":{"description":"Orders / reservations linked to this event.","type":"array","items":{"type":"object","required":["orderNumber","hash","paid","isStorno"],"properties":{"orderNumber":{"description":"Order number.","type":"string"},"hash":{"description":"Order hash for URL identification.","type":"string"},"paid":{"description":"Whether the order has been paid.","type":"boolean"},"isStorno":{"description":"Whether the order item is cancelled.","type":"boolean"},"customerId":{"description":"Customer external ID.","type":"string"},"customerName":{"description":"Customer full name.","type":"string"},"email":{"description":"Customer email.","type":"string"},"phone":{"description":"Customer phone.","type":"string"}}}},"attendeeList":{"description":"Event attendees / participants sorted by organizer status and date.","type":"array","items":{"type":"object","required":["organizer","required","accepted","insertedDate"],"properties":{"name":{"description":"Attendee name.","type":"string"},"email":{"description":"Attendee email.","type":"string"},"phone":{"description":"Attendee phone.","type":"string"},"organizer":{"description":"Whether this attendee is the event organizer.","type":"boolean"},"required":{"description":"Whether attendance is required.","type":"boolean"},"accepted":{"description":"Whether the attendee has accepted the invitation.","type":"boolean"},"insertedDate":{"description":"Date when the attendee was added.","anyOf":[{"description":"Date when the attendee was added.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"passwordList":{"description":"Smart lock passwords generated for this event.","type":"array","items":{"type":"object","required":["password","deleted"],"properties":{"password":{"description":"Smart lock temporary password.","type":"string"},"deleted":{"description":"Whether the password has been revoked.","type":"boolean"}}}},"reservation":{"description":"Reservation status when event type is linked to a product.","type":"object","required":["confirmed","limit"],"properties":{"confirmed":{"description":"Number of confirmed reservations.","type":"number"},"limit":{"description":"Maximum capacity from product warehouse limit.","type":"number"}}},"recurrence":{"description":"Recurrence series information with all related events.","type":"object","required":["isRecurrence","items"],"properties":{"isRecurrence":{"description":"Whether this event is part of a recurring series.","type":"boolean"},"items":{"type":"array","items":{"type":"object","required":["id","title","startTime","endTime","isStorno"],"properties":{"id":{"description":"External event code.","type":"string"},"isParent":{"description":"Whether this is the root/parent event.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"startTime":{"description":"Event start time.","anyOf":[{"description":"Event start time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time.","anyOf":[{"description":"Event end time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isStorno":{"description":"Whether this occurrence is cancelled.","type":"boolean"}}}}}},"recurrenceRule":{"description":"iCalendar RRULE string (e.g., \"FREQ=WEEKLY;BYDAY=MO,WE,FR\").","type":"string"}},"required":["id","calendarId","calendarName","calendarColor","timezone","startTime","endTime","durationMinutes","title","isAllDay","isBlocking","isStorno","insertedDate","reminderList","orderList","attendeeList","passwordList","recurrence"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"External event code identifier.","type":"string"},"calendarId":{"description":"External calendar code.","type":"string"},"calendarName":{"description":"Calendar display name.","type":"string"},"calendarColor":{"description":"Calendar hex color (e.g., \"#FF5733\").","type":"string"},"timezone":{"description":"Calendar timezone (e.g., \"Europe/Prague\").","type":"string"},"startTime":{"description":"Event start time (UTC).","anyOf":[{"description":"Event start time (UTC).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time (UTC).","anyOf":[{"description":"Event end time (UTC).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"durationMinutes":{"description":"Computed event duration in minutes.","type":"number"},"reservedBlockingTo":{"description":"Time until which the event blocks the calendar slot.","anyOf":[{"description":"Time until which the event blocks the calendar slot.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"description":"Event title.","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks conflicting reservations.","type":"boolean"},"isStorno":{"description":"Whether the event has been cancelled.","type":"boolean"},"isOpenButtonAvailable":{"description":"Whether a smart lock unlock button should be shown.","type":"boolean"},"typeCode":{"description":"Event type code (e.g., \"workshop\").","type":"string"},"typeLabel":{"description":"Event type display label.","type":"string"},"color":{"description":"Event type hex color.","type":"string"},"description":{"description":"Event description (rich text).","type":"string"},"agenda":{"description":"Event agenda / schedule.","type":"string"},"url":{"description":"External URL associated with the event.","type":"string"},"insertedDate":{"description":"Date when the event was created.","anyOf":[{"description":"Date when the event was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locationTitle":{"description":"Location name / label.","type":"string"},"location":{"description":"Full location address resolved from the address registry.","type":"object","properties":{"title":{"description":"Location name.","type":"string"},"streetAddress":{"description":"Street and house number.","type":"string"},"city":{"description":"City name.","type":"string"},"postalCode":{"description":"Postal / ZIP code.","type":"string"},"stateRegion":{"description":"State or region.","type":"string"},"cityPart":{"description":"City district / part.","type":"string"},"latitude":{"description":"GPS latitude.","type":"string"},"longitude":{"description":"GPS longitude.","type":"string"}}},"eventTypeProduct":{"description":"Product linked to the event type (for pricing / inventory).","type":"object","required":["code","name","price"],"properties":{"code":{"description":"Product code.","type":"string"},"name":{"description":"Product name.","type":"string"},"price":{"description":"Product price.","type":"string"}}},"reminderList":{"description":"Active reminders for this event.","type":"array","items":{"type":"object","required":["date","relativeTime"],"properties":{"date":{"description":"Absolute reminder trigger time.","anyOf":[{"description":"Absolute reminder trigger time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"relativeTime":{"description":"Relative time before event (e.g., \"30m\", \"1h\", \"1d\").","type":"string"}}}},"orderList":{"description":"Orders / reservations linked to this event.","type":"array","items":{"type":"object","required":["orderNumber","hash","paid","isStorno"],"properties":{"orderNumber":{"description":"Order number.","type":"string"},"hash":{"description":"Order hash for URL identification.","type":"string"},"paid":{"description":"Whether the order has been paid.","type":"boolean"},"isStorno":{"description":"Whether the order item is cancelled.","type":"boolean"},"customerId":{"description":"Customer external ID.","type":"string"},"customerName":{"description":"Customer full name.","type":"string"},"email":{"description":"Customer email.","type":"string"},"phone":{"description":"Customer phone.","type":"string"}}}},"attendeeList":{"description":"Event attendees / participants sorted by organizer status and date.","type":"array","items":{"type":"object","required":["organizer","required","accepted","insertedDate"],"properties":{"name":{"description":"Attendee name.","type":"string"},"email":{"description":"Attendee email.","type":"string"},"phone":{"description":"Attendee phone.","type":"string"},"organizer":{"description":"Whether this attendee is the event organizer.","type":"boolean"},"required":{"description":"Whether attendance is required.","type":"boolean"},"accepted":{"description":"Whether the attendee has accepted the invitation.","type":"boolean"},"insertedDate":{"description":"Date when the attendee was added.","anyOf":[{"description":"Date when the attendee was added.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"passwordList":{"description":"Smart lock passwords generated for this event.","type":"array","items":{"type":"object","required":["password","deleted"],"properties":{"password":{"description":"Smart lock temporary password.","type":"string"},"deleted":{"description":"Whether the password has been revoked.","type":"boolean"}}}},"reservation":{"description":"Reservation status when event type is linked to a product.","type":"object","required":["confirmed","limit"],"properties":{"confirmed":{"description":"Number of confirmed reservations.","type":"number"},"limit":{"description":"Maximum capacity from product warehouse limit.","type":"number"}}},"recurrence":{"description":"Recurrence series information with all related events.","type":"object","required":["isRecurrence","items"],"properties":{"isRecurrence":{"description":"Whether this event is part of a recurring series.","type":"boolean"},"items":{"type":"array","items":{"type":"object","required":["id","title","startTime","endTime","isStorno"],"properties":{"id":{"description":"External event code.","type":"string"},"isParent":{"description":"Whether this is the root/parent event.","type":"boolean"},"title":{"description":"Event title.","type":"string"},"startTime":{"description":"Event start time.","anyOf":[{"description":"Event start time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time.","anyOf":[{"description":"Event end time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"isStorno":{"description":"Whether this occurrence is cancelled.","type":"boolean"}}}}}},"recurrenceRule":{"description":"iCalendar RRULE string (e.g., \"FREQ=WEEKLY;BYDAY=MO,WE,FR\").","type":"string"}},"required":["id","calendarId","calendarName","calendarColor","timezone","startTime","endTime","durationMinutes","title","isAllDay","isBlocking","isStorno","insertedDate","reminderList","orderList","attendeeList","passwordList","recurrence"]}}}}},"operationId":"getBffCalendarEvent-detail","tags":["Calendar Event"],"summary":"Get full event detail","description":"Returns comprehensive event information including calendar context, event type, attendees, orders, reminders, location address, passwords, reservation status, and recurrence data."}},"/bff/calendar/event-find-conflict":{"post":{"parameters":[],"operationId":"postBffCalendarEvent-find-conflict","tags":["Calendar Event"],"summary":"Find calendar event conflicts","description":"Checks whether proposed events conflict with existing events on the given calendar. Returns a list of conflicting time slots.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["calendarId","eventList"],"properties":{"calendarId":{"description":"External calendar code.","type":"string"},"eventList":{"description":"List of proposed events to check for conflicts.","type":"array","items":{"type":"object","required":["startTime","endTime"],"properties":{"startTime":{"description":"Proposed start time (ISO 8601).","type":"string"},"endTime":{"description":"Proposed end time (ISO 8601).","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks the calendar slot.","type":"boolean"}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["calendarId","eventList"],"properties":{"calendarId":{"description":"External calendar code.","type":"string"},"eventList":{"description":"List of proposed events to check for conflicts.","type":"array","items":{"type":"object","required":["startTime","endTime"],"properties":{"startTime":{"description":"Proposed start time (ISO 8601).","type":"string"},"endTime":{"description":"Proposed end time (ISO 8601).","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks the calendar slot.","type":"boolean"}}}}}}},"text/plain":{"schema":{"type":"object","required":["calendarId","eventList"],"properties":{"calendarId":{"description":"External calendar code.","type":"string"},"eventList":{"description":"List of proposed events to check for conflicts.","type":"array","items":{"type":"object","required":["startTime","endTime"],"properties":{"startTime":{"description":"Proposed start time (ISO 8601).","type":"string"},"endTime":{"description":"Proposed end time (ISO 8601).","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks the calendar slot.","type":"boolean"}}}}}}}}},"responses":{"200":{}}}},"/bff/calendar/event-add":{"post":{"operationId":"postBffCalendarEvent-add","tags":["Calendar Event"],"summary":"Create calendar event","description":"Creates a new calendar event. The request body is validated against the calendar event server schema.","responses":{"200":{}}}},"/bff/calendar/event-type-list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["label","code","color"],"properties":{"label":{"description":"Event type display label.","type":"string"},"code":{"description":"Unique event type code.","type":"string"},"color":{"description":"Hex color for the event type.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["label","code","color"],"properties":{"label":{"description":"Event type display label.","type":"string"},"code":{"description":"Unique event type code.","type":"string"},"color":{"description":"Hex color for the event type.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["label","code","color"],"properties":{"label":{"description":"Event type display label.","type":"string"},"code":{"description":"Unique event type code.","type":"string"},"color":{"description":"Hex color for the event type.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffCalendarEvent-type-list","tags":["Calendar Event"],"summary":"List event types","description":"Returns all event types available for the organisation."}},"/bff/calendar/event-type-add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"description":"Code of the created event type.","type":"string"}},"required":["code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"code":{"description":"Code of the created event type.","type":"string"}},"required":["code"]}},"text/plain":{"schema":{"type":"object","properties":{"code":{"description":"Code of the created event type.","type":"string"}},"required":["code"]}}}}},"operationId":"postBffCalendarEvent-type-add","tags":["Calendar Event"],"summary":"Add event type","description":"Creates a new event type for the organisation. Code must be unique within the organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","label","color"],"properties":{"code":{"description":"Unique event type code (e.g., \"workshop\", \"meeting\").","type":"string"},"label":{"description":"Display label (e.g., \"Workshop\", \"Meeting\").","type":"string"},"color":{"description":"Hex color (e.g., \"#FF5733\" or \"FF5733\").","type":"string"},"productId":{"nullable":true,"anyOf":[{"description":"Product ID to link for pricing / inventory. Null if none.","type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","label","color"],"properties":{"code":{"description":"Unique event type code (e.g., \"workshop\", \"meeting\").","type":"string"},"label":{"description":"Display label (e.g., \"Workshop\", \"Meeting\").","type":"string"},"color":{"description":"Hex color (e.g., \"#FF5733\" or \"FF5733\").","type":"string"},"productId":{"nullable":true,"anyOf":[{"description":"Product ID to link for pricing / inventory. Null if none.","type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code","label","color"],"properties":{"code":{"description":"Unique event type code (e.g., \"workshop\", \"meeting\").","type":"string"},"label":{"description":"Display label (e.g., \"Workshop\", \"Meeting\").","type":"string"},"color":{"description":"Hex color (e.g., \"#FF5733\" or \"FF5733\").","type":"string"},"productId":{"nullable":true,"anyOf":[{"description":"Product ID to link for pricing / inventory. Null if none.","type":"number"},{"type":"null"}]}}}}}}}},"/bff/calendar/event-edit":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffCalendarEvent-edit","tags":["Calendar Event"],"summary":"Edit calendar event","description":"Updates an existing calendar event. All fields are optional - only provided fields are changed. Nullable fields can be set to null to clear the value. When start time changes, existing reminders are automatically recalculated.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["eventId"],"properties":{"eventId":{"description":"External event code identifier.","type":"string"},"title":{"description":"Event title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Event description (rich text). Set null to clear.","type":"string"},{"type":"null"}]},"agenda":{"nullable":true,"anyOf":[{"description":"Event agenda / schedule. Set null to clear.","type":"string"},{"type":"null"}]},"url":{"nullable":true,"anyOf":[{"description":"External URL associated with the event. Set null to clear.","type":"string"},{"type":"null"}]},"startTime":{"description":"New start time (ISO 8601).","type":"string"},"endTime":{"description":"New end time (ISO 8601).","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks conflicting reservations in the same slot.","type":"boolean"},"locationTitle":{"nullable":true,"anyOf":[{"description":"Location name / label. Set null to clear.","type":"string"},{"type":"null"}]},"reservedBlockingTo":{"nullable":true,"anyOf":[{"description":"Time until which the calendar slot is blocked (ISO 8601). Set null to clear.","type":"string"},{"type":"null"}]},"type":{"nullable":true,"anyOf":[{"description":"Event type code (e.g., \"workshop\"). Set null to remove type assignment.","type":"string"},{"type":"null"}]},"notifyBefore":{"nullable":true,"anyOf":[{"description":"Reminder relative time before event start (e.g., \"30m\", \"1h\", \"1d\"). Replaces existing reminder. Set null to remove all reminders.","type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["eventId"],"properties":{"eventId":{"description":"External event code identifier.","type":"string"},"title":{"description":"Event title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Event description (rich text). Set null to clear.","type":"string"},{"type":"null"}]},"agenda":{"nullable":true,"anyOf":[{"description":"Event agenda / schedule. Set null to clear.","type":"string"},{"type":"null"}]},"url":{"nullable":true,"anyOf":[{"description":"External URL associated with the event. Set null to clear.","type":"string"},{"type":"null"}]},"startTime":{"description":"New start time (ISO 8601).","type":"string"},"endTime":{"description":"New end time (ISO 8601).","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks conflicting reservations in the same slot.","type":"boolean"},"locationTitle":{"nullable":true,"anyOf":[{"description":"Location name / label. Set null to clear.","type":"string"},{"type":"null"}]},"reservedBlockingTo":{"nullable":true,"anyOf":[{"description":"Time until which the calendar slot is blocked (ISO 8601). Set null to clear.","type":"string"},{"type":"null"}]},"type":{"nullable":true,"anyOf":[{"description":"Event type code (e.g., \"workshop\"). Set null to remove type assignment.","type":"string"},{"type":"null"}]},"notifyBefore":{"nullable":true,"anyOf":[{"description":"Reminder relative time before event start (e.g., \"30m\", \"1h\", \"1d\"). Replaces existing reminder. Set null to remove all reminders.","type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["eventId"],"properties":{"eventId":{"description":"External event code identifier.","type":"string"},"title":{"description":"Event title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Event description (rich text). Set null to clear.","type":"string"},{"type":"null"}]},"agenda":{"nullable":true,"anyOf":[{"description":"Event agenda / schedule. Set null to clear.","type":"string"},{"type":"null"}]},"url":{"nullable":true,"anyOf":[{"description":"External URL associated with the event. Set null to clear.","type":"string"},{"type":"null"}]},"startTime":{"description":"New start time (ISO 8601).","type":"string"},"endTime":{"description":"New end time (ISO 8601).","type":"string"},"isAllDay":{"description":"Whether the event spans the entire day.","type":"boolean"},"isBlocking":{"description":"Whether the event blocks conflicting reservations in the same slot.","type":"boolean"},"locationTitle":{"nullable":true,"anyOf":[{"description":"Location name / label. Set null to clear.","type":"string"},{"type":"null"}]},"reservedBlockingTo":{"nullable":true,"anyOf":[{"description":"Time until which the calendar slot is blocked (ISO 8601). Set null to clear.","type":"string"},{"type":"null"}]},"type":{"nullable":true,"anyOf":[{"description":"Event type code (e.g., \"workshop\"). Set null to remove type assignment.","type":"string"},{"type":"null"}]},"notifyBefore":{"nullable":true,"anyOf":[{"description":"Reminder relative time before event start (e.g., \"30m\", \"1h\", \"1d\"). Replaces existing reminder. Set null to remove all reminders.","type":"string"},{"type":"null"}]}}}}}}}},"/bff/calendar/event-make-recurring":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the conversion was successful.","type":"boolean"},"addedCount":{"description":"Number of sibling occurrences created.","type":"number"}},"required":["success","addedCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the conversion was successful.","type":"boolean"},"addedCount":{"description":"Number of sibling occurrences created.","type":"number"}},"required":["success","addedCount"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the conversion was successful.","type":"boolean"},"addedCount":{"description":"Number of sibling occurrences created.","type":"number"}},"required":["success","addedCount"]}}}}},"operationId":"postBffCalendarEvent-make-recurring","tags":["Calendar Event"],"summary":"Convert a single event into a recurring series","description":"Turns a standalone event into a recurring template (\"vzor\") by creating sibling events that point to it via parent_event_id. Fields (title, description, agenda, url, location, type, blocking flag, all-day flag, reservedBlockingTo) are copied from the parent. Refuses if the event is already part of a recurring series.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["eventId","periodDates"],"properties":{"eventId":{"description":"External event code of the (currently non-recurring) event that should become the series parent.","type":"string"},"periodDates":{"description":"List of occurrences for the new recurring series. The occurrence whose start/end exactly matches the parent event is skipped automatically.","type":"array","items":{"type":"object","required":["dateFrom","dateTo"],"properties":{"dateFrom":{"description":"Occurrence start time (ISO 8601).","type":"string"},"dateTo":{"description":"Occurrence end time (ISO 8601).","type":"string"}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["eventId","periodDates"],"properties":{"eventId":{"description":"External event code of the (currently non-recurring) event that should become the series parent.","type":"string"},"periodDates":{"description":"List of occurrences for the new recurring series. The occurrence whose start/end exactly matches the parent event is skipped automatically.","type":"array","items":{"type":"object","required":["dateFrom","dateTo"],"properties":{"dateFrom":{"description":"Occurrence start time (ISO 8601).","type":"string"},"dateTo":{"description":"Occurrence end time (ISO 8601).","type":"string"}}}}}}},"text/plain":{"schema":{"type":"object","required":["eventId","periodDates"],"properties":{"eventId":{"description":"External event code of the (currently non-recurring) event that should become the series parent.","type":"string"},"periodDates":{"description":"List of occurrences for the new recurring series. The occurrence whose start/end exactly matches the parent event is skipped automatically.","type":"array","items":{"type":"object","required":["dateFrom","dateTo"],"properties":{"dateFrom":{"description":"Occurrence start time (ISO 8601).","type":"string"},"dateTo":{"description":"Occurrence end time (ISO 8601).","type":"string"}}}}}}}}}}},"/bff/calendar/event-storno":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was found and updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was found and updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was found and updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffCalendarEvent-storno","tags":["Calendar Event"],"summary":"Storno single calendar event","description":"Cancels or restores a single calendar event. Sends storno notification emails to all attendees and logs the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["calendarId","eventId","isStorno"],"properties":{"calendarId":{"description":"Calendar code.","type":"string"},"eventId":{"description":"External event code identifier.","type":"string"},"isStorno":{"description":"true = cancel, false = restore.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["calendarId","eventId","isStorno"],"properties":{"calendarId":{"description":"Calendar code.","type":"string"},"eventId":{"description":"External event code identifier.","type":"string"},"isStorno":{"description":"true = cancel, false = restore.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["calendarId","eventId","isStorno"],"properties":{"calendarId":{"description":"Calendar code.","type":"string"},"eventId":{"description":"External event code identifier.","type":"string"},"isStorno":{"description":"true = cancel, false = restore.","type":"boolean"}}}}}}}},"/bff/calendar/event-storno-series":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation completed.","type":"boolean"},"affectedCount":{"description":"Number of events that were actually updated (excludes already-stornoed events).","type":"number"}},"required":["success","affectedCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation completed.","type":"boolean"},"affectedCount":{"description":"Number of events that were actually updated (excludes already-stornoed events).","type":"number"}},"required":["success","affectedCount"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the operation completed.","type":"boolean"},"affectedCount":{"description":"Number of events that were actually updated (excludes already-stornoed events).","type":"number"}},"required":["success","affectedCount"]}}}}},"operationId":"postBffCalendarEvent-storno-series","tags":["Calendar Event"],"summary":"Storno entire recurring event series","description":"Cancels or restores all events in a recurring series at once. Pass any event code from the series (parent or child) and all related events will be updated. Each event is processed individually — storno notifications are sent per event and each action is logged. Events that already have the desired storno status are skipped. For non-recurring events this behaves like a single storno.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["calendarId","eventId","isStorno"],"properties":{"calendarId":{"description":"Calendar code.","type":"string"},"eventId":{"description":"Any event code from the recurring series (parent or child). The system automatically finds all events in the series.","type":"string"},"isStorno":{"description":"true = cancel all events in series, false = restore all.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["calendarId","eventId","isStorno"],"properties":{"calendarId":{"description":"Calendar code.","type":"string"},"eventId":{"description":"Any event code from the recurring series (parent or child). The system automatically finds all events in the series.","type":"string"},"isStorno":{"description":"true = cancel all events in series, false = restore all.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["calendarId","eventId","isStorno"],"properties":{"calendarId":{"description":"Calendar code.","type":"string"},"eventId":{"description":"Any event code from the recurring series (parent or child). The system automatically finds all events in the series.","type":"string"},"isStorno":{"description":"true = cancel all events in series, false = restore all.","type":"boolean"}}}}}}}},"/bff/calendar/event-download-ics":{"get":{"parameters":[{"description":"External event code identifier.","schema":{"type":"string"},"in":"query","name":"eventId","required":true}],"operationId":"getBffCalendarEvent-download-ics","tags":["Calendar Event"],"summary":"Download event as ICS file","description":"Generates and downloads an iCalendar (.ics) file for the given event.","responses":{"200":{}}}},"/bff/calendar/event-unlock-now":{"get":{"parameters":[{"description":"External event code identifier.","schema":{"type":"string"},"in":"query","name":"eventId","required":true}],"operationId":"getBffCalendarEvent-unlock-now","tags":["Calendar Event"],"summary":"Unlock smart lock now","description":"Triggers an immediate smart lock unlock for the lock associated with the given event.","responses":{"200":{}}}},"/bff/calendar/event-retry-access":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"description":"Final lock_access_status after this attempt: one of ready, fallback_backup, failed, manual_override, pending.","type":"string"},"failureReason":{"description":"Underlying error message when status=failed.","type":"string"},"passcodeId":{"description":"Internal id of the linked passcode (when present).","type":"number"}},"required":["status"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"status":{"description":"Final lock_access_status after this attempt: one of ready, fallback_backup, failed, manual_override, pending.","type":"string"},"failureReason":{"description":"Underlying error message when status=failed.","type":"string"},"passcodeId":{"description":"Internal id of the linked passcode (when present).","type":"number"}},"required":["status"]}},"text/plain":{"schema":{"type":"object","properties":{"status":{"description":"Final lock_access_status after this attempt: one of ready, fallback_backup, failed, manual_override, pending.","type":"string"},"failureReason":{"description":"Underlying error message when status=failed.","type":"string"},"passcodeId":{"description":"Internal id of the linked passcode (when present).","type":"number"}},"required":["status"]}}}}},"operationId":"postBffCalendarEvent-retry-access","tags":["Calendar Event"],"summary":"Retry lock access code generation for an event","description":"Runs the same passcode-generation pipeline that the cron uses (`connectPasscodeWithCalendarEvent`). Returns the resulting lifecycle status: `ready` (primary code created), `fallback_backup` (gateway still offline, the lock's backup code is now linked), or `failed` (primary failed and no usable backup). Idempotent — safe to retry from the UI as a \"fix it\" button.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["eventId"],"properties":{"eventId":{"description":"External event code identifier.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["eventId"],"properties":{"eventId":{"description":"External event code identifier.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["eventId"],"properties":{"eventId":{"description":"External event code identifier.","type":"string"}}}}}}}},"/bff/calendar/upcoming-without-access":{"get":{"operationId":"getBffCalendarUpcoming-without-access","tags":["Calendar Event"],"summary":"Upcoming events without a working lock access code","description":"Events scheduled in the next 24h whose calendar has a lock attached but whose `lock_access_status` is anything other than `ready` (or `manual_override` / `not_required`). Drives the \"Events at risk\" dashboard tile.","responses":{"200":{}}}},"/bff/cart/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Max items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Free-text search across cart identifier and customer email / first / last name.","examples":["jan@example.com","a1b2c3"],"schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false},{"description":"\"true\" = only carts with at least one item, \"false\" = only empty carts.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"hasItems","required":false},{"description":"\"true\" = only carts linked to a contact, \"false\" = only anonymous carts.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"hasCustomer","required":false},{"description":"Inclusive lower bound on `updated_date` (ISO date or datetime).","schema":{"type":"string"},"in":"query","name":"updatedFrom","required":false},{"description":"Inclusive upper bound on `updated_date` (ISO date or datetime).","schema":{"type":"string"},"in":"query","name":"updatedTo","required":false}],"operationId":"getBffCartList","tags":["Cart"],"summary":"List shopping carts","description":"Returns a paginated list of carts for the authenticated organisation, sorted by `updated_date` descending. Each row includes a precomputed item count and a total price (in cart currency). Filters cover full-text search, empty / non-empty carts, anonymous vs identified, and a date range on `updated_date`.","responses":{"200":{}}}},"/bff/cart/detail":{"get":{"parameters":[{"description":"Cart identifier (32-char `shop__cart.identifier`).","examples":["a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffCartDetail","tags":["Cart"],"summary":"Get cart detail","description":"Full detail of a single cart — items (with main image preview URL), associated vouchers, customer (when known), delivery and payment method, free-text public notice, and the GeoIP record of the visitor who created the cart. Returns `{ exist: false }` when the cart does not exist or belongs to another organisation.","responses":{"200":{}}}},"/bff/cart/stats":{"get":{"operationId":"getBffCartStats","tags":["Cart"],"summary":"Cart statistics","description":"Aggregated cart metrics: total carts, carts with items, identified carts, recently active (24h / 7d), abandoned carts (with items, untouched 14+ days), potential pipeline revenue, and the dominant currency.","responses":{"200":{}}}},"/bff/cart/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"deleted":{"type":"boolean"},"itemCount":{"description":"Number of cart items removed alongside the cart.","type":"number"},"voucherCount":{"description":"Number of cart-voucher rows removed alongside the cart.","type":"number"}},"required":["success","deleted","itemCount","voucherCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"deleted":{"type":"boolean"},"itemCount":{"description":"Number of cart items removed alongside the cart.","type":"number"},"voucherCount":{"description":"Number of cart-voucher rows removed alongside the cart.","type":"number"}},"required":["success","deleted","itemCount","voucherCount"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"deleted":{"type":"boolean"},"itemCount":{"description":"Number of cart items removed alongside the cart.","type":"number"},"voucherCount":{"description":"Number of cart-voucher rows removed alongside the cart.","type":"number"}},"required":["success","deleted","itemCount","voucherCount"]}}}}},"operationId":"postBffCartDelete","tags":["Cart"],"summary":"Delete cart","description":"Hard-deletes a cart together with its line items and applied vouchers. Multi-tenant safe — only carts of the calling organisation can be removed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Cart identifier (32-char `shop__cart.identifier`) to delete.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Cart identifier (32-char `shop__cart.identifier`) to delete.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Cart identifier (32-char `shop__cart.identifier`) to delete.","type":"string"}}}}}}}},"/bff/cms/menu":{"get":{"operationId":"getBffCmsMenu","tags":["CMS"],"summary":"Get navigation menu","description":"Returns the hierarchical navigation menu for the authenticated user. Menu items are filtered based on user permissions and organisation settings. Returns an empty array if user is not authenticated. Each item contains: id, module (ApplicationModule), uri, and optional subLinks (recursive children).","responses":{"200":{}}}},"/bff/cms/menu/pins":{"get":{"responses":{"200":{"description":"List of pinned menu items for the current user and organisation.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["uri","position","pinnedAt"],"properties":{"uri":{"description":"Pinned menu URI.","examples":["/order"],"type":"string"},"position":{"description":"0-based display order.","examples":[0],"type":"number"},"pinnedAt":{"description":"ISO-8601 timestamp of when the pin was first created.","examples":["2026-04-12T10:34:11Z"],"type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["uri","position","pinnedAt"],"properties":{"uri":{"description":"Pinned menu URI.","examples":["/order"],"type":"string"},"position":{"description":"0-based display order.","examples":[0],"type":"number"},"pinnedAt":{"description":"ISO-8601 timestamp of when the pin was first created.","examples":["2026-04-12T10:34:11Z"],"type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["uri","position","pinnedAt"],"properties":{"uri":{"description":"Pinned menu URI.","examples":["/order"],"type":"string"},"position":{"description":"0-based display order.","examples":[0],"type":"number"},"pinnedAt":{"description":"ISO-8601 timestamp of when the pin was first created.","examples":["2026-04-12T10:34:11Z"],"type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffCmsMenuPins","tags":["CMS"],"summary":"List pinned menu items","description":"Returns the pinned menu items of the authenticated user inside the active organisation, ordered by their stored position (0-based, ascending). Pin identity is the menu URI; menu node ids are not stable across releases. If the URI no longer resolves in the current menu the client filters it out at render time. Returns 401 when no session is present and 403 when the user has no active organisation."},"put":{"parameters":[],"operationId":"putBffCmsMenuPins","tags":["CMS"],"summary":"Replace pinned menu items","description":"Atomically replaces the entire pin collection of the authenticated user inside the active organisation. The order of URIs in the request becomes the display order (position 0..N-1). Used for pin / unpin / reorder in a single round-trip — the client always sends the full set. Validation errors return 422 with `{ error: \"validation\", fields }`. Duplicate URIs, malformed URIs, and counts above 30 are rejected. On success, returns the updated list so the client can replace its cache directly.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["uris"],"properties":{"uris":{"maxItems":30,"description":"Full ordered set of pinned URIs. Position in the array becomes the display position. Sending an empty array clears all pins for the current (user, organisation).","type":"array","items":{"minLength":1,"maxLength":200,"description":"Menu URI to pin. Must start with \"/\" and contain URL-safe characters only.","examples":["/order"],"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["uris"],"properties":{"uris":{"maxItems":30,"description":"Full ordered set of pinned URIs. Position in the array becomes the display position. Sending an empty array clears all pins for the current (user, organisation).","type":"array","items":{"minLength":1,"maxLength":200,"description":"Menu URI to pin. Must start with \"/\" and contain URL-safe characters only.","examples":["/order"],"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["uris"],"properties":{"uris":{"maxItems":30,"description":"Full ordered set of pinned URIs. Position in the array becomes the display position. Sending an empty array clears all pins for the current (user, organisation).","type":"array","items":{"minLength":1,"maxLength":200,"description":"Menu URI to pin. Must start with \"/\" and contain URL-safe characters only.","examples":["/order"],"type":"string"}}}}}}},"responses":{"200":{}}}},"/bff/cms/organisation-create":{"post":{"parameters":[],"responses":{"200":{"description":"Organisation created successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffCmsOrganisation-create","tags":["CMS"],"summary":"Create new organisation","description":"Creates a new organisation linked to the current user. The user becomes an admin member of the new organisation. Requires authenticated user.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationName","timezone"],"properties":{"organisationName":{"minLength":1,"description":"Name of the new organisation. Must be unique.","examples":["Acme Corp"],"type":"string"},"timezone":{"description":"Timezone identifier (e.g., \"Europe/Prague\", \"America/New_York\").","examples":["Europe/Prague"],"type":"string"},"description":{"description":"Optional description of the organisation.","examples":["Our main production workspace."],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationName","timezone"],"properties":{"organisationName":{"minLength":1,"description":"Name of the new organisation. Must be unique.","examples":["Acme Corp"],"type":"string"},"timezone":{"description":"Timezone identifier (e.g., \"Europe/Prague\", \"America/New_York\").","examples":["Europe/Prague"],"type":"string"},"description":{"description":"Optional description of the organisation.","examples":["Our main production workspace."],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationName","timezone"],"properties":{"organisationName":{"minLength":1,"description":"Name of the new organisation. Must be unique.","examples":["Acme Corp"],"type":"string"},"timezone":{"description":"Timezone identifier (e.g., \"Europe/Prague\", \"America/New_York\").","examples":["Europe/Prague"],"type":"string"},"description":{"description":"Optional description of the organisation.","examples":["Our main production workspace."],"type":"string"}}}}}}}},"/bff/cms/create-organisation-check":{"post":{"parameters":[],"responses":{"200":{"description":"Organisation name availability check result.","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"description":"Whether the organisation name is available for use.","examples":[true],"type":"boolean"},"name":{"description":"The organisation name that was checked.","examples":["Acme Corp"],"type":"string"},"slug":{"description":"Generated URL-friendly slug for the organisation. Guaranteed to be unique.","examples":["acme-corp"],"type":"string"}},"required":["available","name","slug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"available":{"description":"Whether the organisation name is available for use.","examples":[true],"type":"boolean"},"name":{"description":"The organisation name that was checked.","examples":["Acme Corp"],"type":"string"},"slug":{"description":"Generated URL-friendly slug for the organisation. Guaranteed to be unique.","examples":["acme-corp"],"type":"string"}},"required":["available","name","slug"]}},"text/plain":{"schema":{"type":"object","properties":{"available":{"description":"Whether the organisation name is available for use.","examples":[true],"type":"boolean"},"name":{"description":"The organisation name that was checked.","examples":["Acme Corp"],"type":"string"},"slug":{"description":"Generated URL-friendly slug for the organisation. Guaranteed to be unique.","examples":["acme-corp"],"type":"string"}},"required":["available","name","slug"]}}}}},"operationId":"postBffCmsCreate-organisation-check","tags":["CMS"],"summary":"Check organisation name availability","description":"Checks if the proposed organisation name is available and generates a unique URL slug. Use this endpoint before creating an organisation to validate the name.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationName"],"properties":{"organisationName":{"description":"Proposed organisation name to check availability.","examples":["Acme Corp"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationName"],"properties":{"organisationName":{"description":"Proposed organisation name to check availability.","examples":["Acme Corp"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationName"],"properties":{"organisationName":{"description":"Proposed organisation name to check availability.","examples":["Acme Corp"],"type":"string"}}}}}}}},"/bff/cms/switch-organisation":{"post":{"parameters":[],"responses":{"200":{"description":"Organisation switch result.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"},"identityId":{"description":"New identity ID for the switched organisation session.","examples":["xyz789-new-identity"],"type":"string"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"},"identityId":{"description":"New identity ID for the switched organisation session.","examples":["xyz789-new-identity"],"type":"string"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"},"identityId":{"description":"New identity ID for the switched organisation session.","examples":["xyz789-new-identity"],"type":"string"}},"required":["success"]}}}}},"operationId":"postBffCmsSwitch-organisation","tags":["CMS"],"summary":"Switch organisation context","description":"Switches the user session to a different organisation. Creates a new identity session for the target organisation. User must be a member of the target organisation. Updates the organisation order in the user menu (most recently accessed first).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identityCookies","organisation"],"properties":{"identityCookies":{"description":"Current user identity cookie value.","examples":["abc123-identity-token"],"type":"string"},"organisation":{"description":"Slug of the organisation to switch to.","examples":["acme-corp"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["identityCookies","organisation"],"properties":{"identityCookies":{"description":"Current user identity cookie value.","examples":["abc123-identity-token"],"type":"string"},"organisation":{"description":"Slug of the organisation to switch to.","examples":["acme-corp"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["identityCookies","organisation"],"properties":{"identityCookies":{"description":"Current user identity cookie value.","examples":["abc123-identity-token"],"type":"string"},"organisation":{"description":"Slug of the organisation to switch to.","examples":["acme-corp"],"type":"string"}}}}}}}},"/bff/cms/switch-locale":{"post":{"parameters":[],"responses":{"200":{"description":"Locale changed successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"description":"Always true on success.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffCmsSwitch-locale","tags":["CMS"],"summary":"Switch user locale","description":"Changes the preferred locale/language for the authenticated user. This affects the UI language and date/number formatting across all sessions.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identityCookies","locale"],"properties":{"identityCookies":{"description":"Current user identity cookie value.","examples":["abc123-identity-token"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["identityCookies","locale"],"properties":{"identityCookies":{"description":"Current user identity cookie value.","examples":["abc123-identity-token"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["identityCookies","locale"],"properties":{"identityCookies":{"description":"Current user identity cookie value.","examples":["abc123-identity-token"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}}}}}},"/bff/complaint/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Filter by complaint variant code defined by organisation.","examples":["reklamace","vraceni"],"schema":{"type":"string"},"in":"query","name":"variantCode","required":false},{"description":"Filter by complaint status.","examples":["new","open","wait","resolve","reject","closed"],"schema":{"type":"string"},"in":"query","name":"status","required":false},{"description":"Filter by resolution state. \"true\" = resolved only, \"false\" = open only.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"isResolved","required":false},{"description":"Full-text search across customer name, email, order number, and description.","examples":["jan@example.com","Novák"],"schema":{"type":"string"},"in":"query","name":"search","required":false},{"description":"Filter complaints created on or after this date (inclusive).","examples":["2026-01-01"],"schema":{"type":"string"},"in":"query","name":"dateFrom","required":false},{"description":"Filter complaints created on or before this date (inclusive).","examples":["2026-01-31"],"schema":{"type":"string"},"in":"query","name":"dateTo","required":false}],"operationId":"getBffComplaintList","tags":["Complaint"],"summary":"List complaints","description":"Returns a paginated list of complaints with variant, status, and customer info. Supports filtering by variant, status, resolution state, date range, and full-text search.","responses":{"200":{}}}},"/bff/complaint/detail":{"get":{"parameters":[{"description":"Complaint ID.","examples":["42"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffComplaintDetail","tags":["Complaint"],"summary":"Complaint detail","description":"Returns full complaint detail including items, events timeline, refund info, and satisfaction feedback.","responses":{"200":{}}}},"/bff/complaint/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created complaint external ID.","examples":["a1b2c3d4"],"type":"string"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created complaint external ID.","examples":["a1b2c3d4"],"type":"string"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created complaint external ID.","examples":["a1b2c3d4"],"type":"string"}},"required":["success","id"]}}}}},"operationId":"postBffComplaintCreate","tags":["Complaint"],"summary":"Create complaint","description":"Creates a new complaint case. Optionally links to an existing order and its items. An initial event is automatically created in the complaint timeline.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["variantCode","description","customerName"],"properties":{"variantCode":{"description":"Organisation-defined complaint variant code.","examples":["reklamace","vraceni","vymena"],"type":"string"},"orderId":{"description":"Internal order ID to link the complaint to an existing order.","examples":[1024],"type":"number"},"orderNumber":{"description":"Human-readable order number. Use when order is external or unavailable by ID.","examples":["25000087"],"type":"string"},"description":{"description":"Customer-provided description and reason for the complaint.","examples":["Product arrived damaged, visible scratch on the surface."],"type":"string"},"customerName":{"description":"Full name of the customer filing the complaint.","examples":["Jan Novák"],"type":"string"},"email":{"description":"Customer e-mail for complaint communication.","examples":["jan@example.com"],"type":"string"},"phone":{"description":"Customer phone number.","examples":["+420 777 123 456"],"type":"string"},"price":{"description":"Total claimed amount in the order-defined currency.","examples":[1500],"type":"number"},"currencyId":{"description":"Currency ID for the claimed amount.","examples":[1],"type":"number"},"refundCountry":{"description":"ISO 3166-1 alpha-2 country code for refund bank account.","examples":["CZ","SK"],"type":"string"},"refundBankAccount":{"description":"Bank account number for refund transfer.","examples":["123456789/0100"],"type":"string"},"refundVariableSymbol":{"description":"Variable symbol for refund bank transfer.","examples":["25000087"],"type":"string"},"branchId":{"description":"Branch ID where the product should be sent for inspection.","examples":[1],"type":"number"},"serviceId":{"description":"External service provider ID handling the complaint.","examples":[1],"type":"number"},"resolutionMethodCode":{"description":"Preferred resolution method code defined by organisation.","examples":["repair","exchange","refund"],"type":"string"},"dueDate":{"description":"Deadline for complaint resolution.","format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"type":"string"},"items":{"description":"List of complained items from the original order.","type":"array","items":{"type":"object","required":["label"],"properties":{"orderItemId":{"description":"Link to original order item being complained about.","examples":[501],"type":"number"},"label":{"description":"Item description as displayed in the complaint.","examples":["Cheese burger"],"type":"string"},"quantity":{"description":"Number of items being complained about. Defaults to 1.","examples":[1],"type":"number"},"price":{"description":"Claimed unit price of the item.","examples":[250],"type":"number"},"currencyId":{"description":"Currency ID for the item price.","examples":[1],"type":"number"}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["variantCode","description","customerName"],"properties":{"variantCode":{"description":"Organisation-defined complaint variant code.","examples":["reklamace","vraceni","vymena"],"type":"string"},"orderId":{"description":"Internal order ID to link the complaint to an existing order.","examples":[1024],"type":"number"},"orderNumber":{"description":"Human-readable order number. Use when order is external or unavailable by ID.","examples":["25000087"],"type":"string"},"description":{"description":"Customer-provided description and reason for the complaint.","examples":["Product arrived damaged, visible scratch on the surface."],"type":"string"},"customerName":{"description":"Full name of the customer filing the complaint.","examples":["Jan Novák"],"type":"string"},"email":{"description":"Customer e-mail for complaint communication.","examples":["jan@example.com"],"type":"string"},"phone":{"description":"Customer phone number.","examples":["+420 777 123 456"],"type":"string"},"price":{"description":"Total claimed amount in the order-defined currency.","examples":[1500],"type":"number"},"currencyId":{"description":"Currency ID for the claimed amount.","examples":[1],"type":"number"},"refundCountry":{"description":"ISO 3166-1 alpha-2 country code for refund bank account.","examples":["CZ","SK"],"type":"string"},"refundBankAccount":{"description":"Bank account number for refund transfer.","examples":["123456789/0100"],"type":"string"},"refundVariableSymbol":{"description":"Variable symbol for refund bank transfer.","examples":["25000087"],"type":"string"},"branchId":{"description":"Branch ID where the product should be sent for inspection.","examples":[1],"type":"number"},"serviceId":{"description":"External service provider ID handling the complaint.","examples":[1],"type":"number"},"resolutionMethodCode":{"description":"Preferred resolution method code defined by organisation.","examples":["repair","exchange","refund"],"type":"string"},"dueDate":{"description":"Deadline for complaint resolution.","format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"type":"string"},"items":{"description":"List of complained items from the original order.","type":"array","items":{"type":"object","required":["label"],"properties":{"orderItemId":{"description":"Link to original order item being complained about.","examples":[501],"type":"number"},"label":{"description":"Item description as displayed in the complaint.","examples":["Cheese burger"],"type":"string"},"quantity":{"description":"Number of items being complained about. Defaults to 1.","examples":[1],"type":"number"},"price":{"description":"Claimed unit price of the item.","examples":[250],"type":"number"},"currencyId":{"description":"Currency ID for the item price.","examples":[1],"type":"number"}}}}}}},"text/plain":{"schema":{"type":"object","required":["variantCode","description","customerName"],"properties":{"variantCode":{"description":"Organisation-defined complaint variant code.","examples":["reklamace","vraceni","vymena"],"type":"string"},"orderId":{"description":"Internal order ID to link the complaint to an existing order.","examples":[1024],"type":"number"},"orderNumber":{"description":"Human-readable order number. Use when order is external or unavailable by ID.","examples":["25000087"],"type":"string"},"description":{"description":"Customer-provided description and reason for the complaint.","examples":["Product arrived damaged, visible scratch on the surface."],"type":"string"},"customerName":{"description":"Full name of the customer filing the complaint.","examples":["Jan Novák"],"type":"string"},"email":{"description":"Customer e-mail for complaint communication.","examples":["jan@example.com"],"type":"string"},"phone":{"description":"Customer phone number.","examples":["+420 777 123 456"],"type":"string"},"price":{"description":"Total claimed amount in the order-defined currency.","examples":[1500],"type":"number"},"currencyId":{"description":"Currency ID for the claimed amount.","examples":[1],"type":"number"},"refundCountry":{"description":"ISO 3166-1 alpha-2 country code for refund bank account.","examples":["CZ","SK"],"type":"string"},"refundBankAccount":{"description":"Bank account number for refund transfer.","examples":["123456789/0100"],"type":"string"},"refundVariableSymbol":{"description":"Variable symbol for refund bank transfer.","examples":["25000087"],"type":"string"},"branchId":{"description":"Branch ID where the product should be sent for inspection.","examples":[1],"type":"number"},"serviceId":{"description":"External service provider ID handling the complaint.","examples":[1],"type":"number"},"resolutionMethodCode":{"description":"Preferred resolution method code defined by organisation.","examples":["repair","exchange","refund"],"type":"string"},"dueDate":{"description":"Deadline for complaint resolution.","format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"type":"string"},"items":{"description":"List of complained items from the original order.","type":"array","items":{"type":"object","required":["label"],"properties":{"orderItemId":{"description":"Link to original order item being complained about.","examples":[501],"type":"number"},"label":{"description":"Item description as displayed in the complaint.","examples":["Cheese burger"],"type":"string"},"quantity":{"description":"Number of items being complained about. Defaults to 1.","examples":[1],"type":"number"},"price":{"description":"Claimed unit price of the item.","examples":[250],"type":"number"},"currencyId":{"description":"Currency ID for the item price.","examples":[1],"type":"number"}}}}}}}}}}},"/bff/complaint/set-status":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintSet-status","tags":["Complaint"],"summary":"Set complaint status","description":"Changes complaint status and records the transition in the event timeline. Statuses \"resolve\" and \"closed\" automatically set is_resolved flag and resolved_date.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["complaintId","status"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"status":{"description":"New status code. Setting \"resolve\" or \"closed\" automatically marks the complaint as resolved.","examples":["new","open","wait","resolve","reject","closed"],"type":"string"},"message":{"description":"Optional note explaining the status change. Visible in the complaint timeline.","examples":["Awaiting customer response."],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["complaintId","status"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"status":{"description":"New status code. Setting \"resolve\" or \"closed\" automatically marks the complaint as resolved.","examples":["new","open","wait","resolve","reject","closed"],"type":"string"},"message":{"description":"Optional note explaining the status change. Visible in the complaint timeline.","examples":["Awaiting customer response."],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["complaintId","status"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"status":{"description":"New status code. Setting \"resolve\" or \"closed\" automatically marks the complaint as resolved.","examples":["new","open","wait","resolve","reject","closed"],"type":"string"},"message":{"description":"Optional note explaining the status change. Visible in the complaint timeline.","examples":["Awaiting customer response."],"type":"string"}}}}}}}},"/bff/complaint/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintUpdate","tags":["Complaint"],"summary":"Update complaint","description":"Updates complaint fields. Only provided fields are modified; omitted fields remain unchanged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["complaintId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"description":{"description":"Updated complaint description and reason.","examples":["Product arrived with a cracked screen."],"type":"string"},"customerName":{"description":"Updated customer full name.","examples":["Jan Novák"],"type":"string"},"email":{"description":"Updated customer e-mail.","examples":["jan@example.com"],"type":"string"},"phone":{"description":"Updated customer phone number.","examples":["+420 777 123 456"],"type":"string"},"refundCountry":{"description":"ISO 3166-1 alpha-2 country code for refund.","examples":["CZ"],"type":"string"},"refundBankAccount":{"description":"Updated bank account number for refund.","examples":["123456789/0100"],"type":"string"},"refundVariableSymbol":{"description":"Updated variable symbol for refund transfer.","examples":["25000087"],"type":"string"},"branchId":{"description":"Updated branch ID for inspection delivery.","examples":[1],"type":"number"},"serviceId":{"description":"Updated external service provider ID.","examples":[1],"type":"number"},"dueDate":{"description":"Updated deadline for complaint resolution.","format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["complaintId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"description":{"description":"Updated complaint description and reason.","examples":["Product arrived with a cracked screen."],"type":"string"},"customerName":{"description":"Updated customer full name.","examples":["Jan Novák"],"type":"string"},"email":{"description":"Updated customer e-mail.","examples":["jan@example.com"],"type":"string"},"phone":{"description":"Updated customer phone number.","examples":["+420 777 123 456"],"type":"string"},"refundCountry":{"description":"ISO 3166-1 alpha-2 country code for refund.","examples":["CZ"],"type":"string"},"refundBankAccount":{"description":"Updated bank account number for refund.","examples":["123456789/0100"],"type":"string"},"refundVariableSymbol":{"description":"Updated variable symbol for refund transfer.","examples":["25000087"],"type":"string"},"branchId":{"description":"Updated branch ID for inspection delivery.","examples":[1],"type":"number"},"serviceId":{"description":"Updated external service provider ID.","examples":[1],"type":"number"},"dueDate":{"description":"Updated deadline for complaint resolution.","format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["complaintId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"description":{"description":"Updated complaint description and reason.","examples":["Product arrived with a cracked screen."],"type":"string"},"customerName":{"description":"Updated customer full name.","examples":["Jan Novák"],"type":"string"},"email":{"description":"Updated customer e-mail.","examples":["jan@example.com"],"type":"string"},"phone":{"description":"Updated customer phone number.","examples":["+420 777 123 456"],"type":"string"},"refundCountry":{"description":"ISO 3166-1 alpha-2 country code for refund.","examples":["CZ"],"type":"string"},"refundBankAccount":{"description":"Updated bank account number for refund.","examples":["123456789/0100"],"type":"string"},"refundVariableSymbol":{"description":"Updated variable symbol for refund transfer.","examples":["25000087"],"type":"string"},"branchId":{"description":"Updated branch ID for inspection delivery.","examples":[1],"type":"number"},"serviceId":{"description":"Updated external service provider ID.","examples":[1],"type":"number"},"dueDate":{"description":"Updated deadline for complaint resolution.","format":"date-time","examples":["2026-02-15T00:00:00.000Z"],"type":"string"}}}}}}}},"/bff/complaint/add-event":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintAdd-event","tags":["Complaint"],"summary":"Add complaint event","description":"Adds a new event to the complaint timeline. Use for internal notes or customer-facing messages. Set shareWithCustomer=true to make the event visible to the customer.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["complaintId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"shareWithCustomer":{"description":"Indicator of whether this event should be visible to the customer. Defaults to false (internal only).","default":false,"type":"boolean"},"subject":{"description":"Event subject line.","examples":["Inspection result"],"type":"string"},"message":{"description":"Event message body. Supports internal notes or customer-facing communication.","examples":["Product defect confirmed. Replacement will be shipped."],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["complaintId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"shareWithCustomer":{"description":"Indicator of whether this event should be visible to the customer. Defaults to false (internal only).","default":false,"type":"boolean"},"subject":{"description":"Event subject line.","examples":["Inspection result"],"type":"string"},"message":{"description":"Event message body. Supports internal notes or customer-facing communication.","examples":["Product defect confirmed. Replacement will be shipped."],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["complaintId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"shareWithCustomer":{"description":"Indicator of whether this event should be visible to the customer. Defaults to false (internal only).","default":false,"type":"boolean"},"subject":{"description":"Event subject line.","examples":["Inspection result"],"type":"string"},"message":{"description":"Event message body. Supports internal notes or customer-facing communication.","examples":["Product defect confirmed. Replacement will be shipped."],"type":"string"}}}}}}}},"/bff/complaint/add-item":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintAdd-item","tags":["Complaint"],"summary":"Add complaint item","description":"Adds a new item to an existing complaint. Optionally links to an original order item.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["complaintId","label"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"orderItemId":{"description":"Link to original order item being complained about.","examples":[501],"type":"number"},"label":{"description":"Item description as displayed in the complaint.","examples":["Wireless headphones"],"type":"string"},"quantity":{"description":"Number of items. Defaults to 1.","examples":[1],"type":"number"},"price":{"description":"Claimed unit price of the item.","examples":[2490],"type":"number"},"currencyId":{"description":"Currency ID for the item price.","examples":[1],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["complaintId","label"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"orderItemId":{"description":"Link to original order item being complained about.","examples":[501],"type":"number"},"label":{"description":"Item description as displayed in the complaint.","examples":["Wireless headphones"],"type":"string"},"quantity":{"description":"Number of items. Defaults to 1.","examples":[1],"type":"number"},"price":{"description":"Claimed unit price of the item.","examples":[2490],"type":"number"},"currencyId":{"description":"Currency ID for the item price.","examples":[1],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["complaintId","label"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"orderItemId":{"description":"Link to original order item being complained about.","examples":[501],"type":"number"},"label":{"description":"Item description as displayed in the complaint.","examples":["Wireless headphones"],"type":"string"},"quantity":{"description":"Number of items. Defaults to 1.","examples":[1],"type":"number"},"price":{"description":"Claimed unit price of the item.","examples":[2490],"type":"number"},"currencyId":{"description":"Currency ID for the item price.","examples":[1],"type":"number"}}}}}}}},"/bff/complaint/remove-item":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintRemove-item","tags":["Complaint"],"summary":"Remove complaint item","description":"Removes an item from the complaint.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["complaintId","itemId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"itemId":{"description":"Complaint item ID to remove.","examples":[12],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["complaintId","itemId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"itemId":{"description":"Complaint item ID to remove.","examples":[12],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["complaintId","itemId"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"itemId":{"description":"Complaint item ID to remove.","examples":[12],"type":"number"}}}}}}}},"/bff/complaint/link-blob":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintLink-blob","tags":["Complaint"],"summary":"Attach file to complaint","description":"Links an already-uploaded blob to a complaint. The file must be uploaded via blob storage first. An event is automatically recorded in the complaint timeline.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["complaintId","blobToken"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"blobToken":{"description":"Blob storage token of the previously uploaded file.","examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"label":{"description":"Human-readable file label.","examples":["Photo of damaged product"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["complaintId","blobToken"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"blobToken":{"description":"Blob storage token of the previously uploaded file.","examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"label":{"description":"Human-readable file label.","examples":["Photo of damaged product"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["complaintId","blobToken"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"blobToken":{"description":"Blob storage token of the previously uploaded file.","examples":["b411056d304d9y6mHe2SoMFBL2Apxfnb"],"type":"string"},"label":{"description":"Human-readable file label.","examples":["Photo of damaged product"],"type":"string"}}}}}}}},"/bff/complaint/satisfaction":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintSatisfaction","tags":["Complaint"],"summary":"Submit satisfaction feedback","description":"Records customer satisfaction feedback for a complaint. Typically called after the complaint has been resolved.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["complaintId","score"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"score":{"minimum":1,"maximum":10,"description":"Customer satisfaction score from 1 (worst) to 10 (best).","examples":[8],"type":"number"},"message":{"description":"Optional free-text feedback from the customer about the complaint resolution.","examples":["Quick and professional resolution, thank you."],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["complaintId","score"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"score":{"minimum":1,"maximum":10,"description":"Customer satisfaction score from 1 (worst) to 10 (best).","examples":[8],"type":"number"},"message":{"description":"Optional free-text feedback from the customer about the complaint resolution.","examples":["Quick and professional resolution, thank you."],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["complaintId","score"],"properties":{"complaintId":{"description":"Complaint external ID.","examples":["a1b2c3d4"],"type":"string"},"score":{"minimum":1,"maximum":10,"description":"Customer satisfaction score from 1 (worst) to 10 (best).","examples":[8],"type":"number"},"message":{"description":"Optional free-text feedback from the customer about the complaint resolution.","examples":["Quick and professional resolution, thank you."],"type":"string"}}}}}}}},"/bff/complaint/variant-list":{"get":{"operationId":"getBffComplaintVariant-list","tags":["Complaint"],"summary":"List complaint variants","description":"Returns all complaint variant types defined by the organisation (e.g. reklamace, vrácení, výměna).","responses":{"200":{}}}},"/bff/complaint/variant-create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created variant ID.","examples":[1],"type":"number"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created variant ID.","examples":[1],"type":"number"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created variant ID.","examples":[1],"type":"number"}},"required":["success","id"]}}}}},"operationId":"postBffComplaintVariant-create","tags":["Complaint"],"summary":"Create complaint variant","description":"Creates a new complaint variant type for the organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","label"],"properties":{"code":{"description":"Unique variant code within the organisation. Used as identifier in API calls.","examples":["reklamace","vraceni","vymena"],"type":"string"},"label":{"description":"Human-readable variant label displayed in UI.","examples":["Reklamace","Vrácení zboží","Výměna"],"type":"string"},"policyId":{"description":"Default complaint policy ID applied to this variant.","examples":[1],"type":"number"},"position":{"description":"Display order position. Lower values appear first.","examples":[0],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","label"],"properties":{"code":{"description":"Unique variant code within the organisation. Used as identifier in API calls.","examples":["reklamace","vraceni","vymena"],"type":"string"},"label":{"description":"Human-readable variant label displayed in UI.","examples":["Reklamace","Vrácení zboží","Výměna"],"type":"string"},"policyId":{"description":"Default complaint policy ID applied to this variant.","examples":[1],"type":"number"},"position":{"description":"Display order position. Lower values appear first.","examples":[0],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["code","label"],"properties":{"code":{"description":"Unique variant code within the organisation. Used as identifier in API calls.","examples":["reklamace","vraceni","vymena"],"type":"string"},"label":{"description":"Human-readable variant label displayed in UI.","examples":["Reklamace","Vrácení zboží","Výměna"],"type":"string"},"policyId":{"description":"Default complaint policy ID applied to this variant.","examples":[1],"type":"number"},"position":{"description":"Display order position. Lower values appear first.","examples":[0],"type":"number"}}}}}}}},"/bff/complaint/variant-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintVariant-update","tags":["Complaint"],"summary":"Update complaint variant","description":"Updates an existing complaint variant. Only provided fields are modified.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Variant ID to update.","examples":[1],"type":"number"},"label":{"description":"Updated human-readable variant label.","examples":["Reklamace"],"type":"string"},"policyId":{"description":"Updated default complaint policy ID.","examples":[1],"type":"number"},"position":{"description":"Updated display order position.","examples":[0],"type":"number"},"isActive":{"description":"Indicator of whether the variant is active and selectable.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Variant ID to update.","examples":[1],"type":"number"},"label":{"description":"Updated human-readable variant label.","examples":["Reklamace"],"type":"string"},"policyId":{"description":"Updated default complaint policy ID.","examples":[1],"type":"number"},"position":{"description":"Updated display order position.","examples":[0],"type":"number"},"isActive":{"description":"Indicator of whether the variant is active and selectable.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Variant ID to update.","examples":[1],"type":"number"},"label":{"description":"Updated human-readable variant label.","examples":["Reklamace"],"type":"string"},"policyId":{"description":"Updated default complaint policy ID.","examples":[1],"type":"number"},"position":{"description":"Updated display order position.","examples":[0],"type":"number"},"isActive":{"description":"Indicator of whether the variant is active and selectable.","type":"boolean"}}}}}}}},"/bff/complaint/resolution-method-list":{"get":{"operationId":"getBffComplaintResolution-method-list","tags":["Complaint"],"summary":"List resolution methods","description":"Returns all complaint resolution methods defined by the organisation (e.g. repair, exchange, refund).","responses":{"200":{}}}},"/bff/complaint/resolution-method-create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created resolution method ID.","examples":[1],"type":"number"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created resolution method ID.","examples":[1],"type":"number"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created resolution method ID.","examples":[1],"type":"number"}},"required":["success","id"]}}}}},"operationId":"postBffComplaintResolution-method-create","tags":["Complaint"],"summary":"Create resolution method","description":"Creates a new complaint resolution method for the organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","label"],"properties":{"code":{"description":"Unique resolution method code within the organisation.","examples":["repair","exchange","refund","credit"],"type":"string"},"label":{"description":"Human-readable resolution method label displayed in UI.","examples":["Oprava","Výměna","Vrácení peněz","Dobropis"],"type":"string"},"position":{"description":"Display order position. Lower values appear first.","examples":[0],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","label"],"properties":{"code":{"description":"Unique resolution method code within the organisation.","examples":["repair","exchange","refund","credit"],"type":"string"},"label":{"description":"Human-readable resolution method label displayed in UI.","examples":["Oprava","Výměna","Vrácení peněz","Dobropis"],"type":"string"},"position":{"description":"Display order position. Lower values appear first.","examples":[0],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["code","label"],"properties":{"code":{"description":"Unique resolution method code within the organisation.","examples":["repair","exchange","refund","credit"],"type":"string"},"label":{"description":"Human-readable resolution method label displayed in UI.","examples":["Oprava","Výměna","Vrácení peněz","Dobropis"],"type":"string"},"position":{"description":"Display order position. Lower values appear first.","examples":[0],"type":"number"}}}}}}}},"/bff/complaint/resolution-method-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintResolution-method-update","tags":["Complaint"],"summary":"Update resolution method","description":"Updates an existing resolution method. Only provided fields are modified.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Resolution method ID to update.","examples":[1],"type":"number"},"label":{"description":"Updated human-readable label.","examples":["Oprava"],"type":"string"},"position":{"description":"Updated display order position.","examples":[0],"type":"number"},"isActive":{"description":"Indicator of whether the resolution method is active and selectable.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Resolution method ID to update.","examples":[1],"type":"number"},"label":{"description":"Updated human-readable label.","examples":["Oprava"],"type":"string"},"position":{"description":"Updated display order position.","examples":[0],"type":"number"},"isActive":{"description":"Indicator of whether the resolution method is active and selectable.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Resolution method ID to update.","examples":[1],"type":"number"},"label":{"description":"Updated human-readable label.","examples":["Oprava"],"type":"string"},"position":{"description":"Updated display order position.","examples":[0],"type":"number"},"isActive":{"description":"Indicator of whether the resolution method is active and selectable.","type":"boolean"}}}}}}}},"/bff/complaint/policy-list":{"get":{"operationId":"getBffComplaintPolicy-list","tags":["Complaint"],"summary":"List complaint policies","description":"Returns all complaint policies for the organisation. Policies define cancellation rules, free storno windows, and fee percentages per product or category.","responses":{"200":{}}}},"/bff/complaint/policy-create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created policy ID.","examples":[1],"type":"number"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created policy ID.","examples":[1],"type":"number"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"},"id":{"description":"Newly created policy ID.","examples":[1],"type":"number"}},"required":["success","id"]}}}}},"operationId":"postBffComplaintPolicy-create","tags":["Complaint"],"summary":"Create complaint policy","description":"Creates a versioned complaint policy with cancellation/storno rules. Assign to a product or category. Multiple versions can coexist with different validity periods.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","body","validFrom"],"properties":{"productId":{"description":"Apply this policy to a specific product.","examples":[42],"type":"number"},"categoryId":{"description":"Apply this policy to all products in a category.","examples":[5],"type":"number"},"title":{"description":"Policy title displayed to staff and optionally to customer.","examples":["Standard return policy"],"type":"string"},"body":{"description":"Full policy text in HTML or plain text. Defines terms and conditions for complaints.","examples":["Items may be returned within 14 days of delivery."],"type":"string"},"validFrom":{"description":"Date from which this policy version is effective.","format":"date-time","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"Date until which this policy is effective. Null means open-ended.","format":"date-time","examples":["2026-12-31T23:59:59.000Z"],"type":"string"},"allowStorno":{"description":"Indicator of whether free cancellation/storno is allowed under this policy.","default":false,"type":"boolean"},"stornoFreeHours":{"description":"Number of hours before the reservation/event during which storno is free of charge.","examples":[48],"type":"number"},"stornoFeePercent":{"description":"Storno fee as a percentage of the order price when cancelled within the fee window.","examples":[50],"type":"number"},"stornoFeeDeadlineHours":{"description":"Number of hours before the reservation/event within which the storno fee applies. Cancellations before this window use stornoFreeHours rules.","examples":[24],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["title","body","validFrom"],"properties":{"productId":{"description":"Apply this policy to a specific product.","examples":[42],"type":"number"},"categoryId":{"description":"Apply this policy to all products in a category.","examples":[5],"type":"number"},"title":{"description":"Policy title displayed to staff and optionally to customer.","examples":["Standard return policy"],"type":"string"},"body":{"description":"Full policy text in HTML or plain text. Defines terms and conditions for complaints.","examples":["Items may be returned within 14 days of delivery."],"type":"string"},"validFrom":{"description":"Date from which this policy version is effective.","format":"date-time","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"Date until which this policy is effective. Null means open-ended.","format":"date-time","examples":["2026-12-31T23:59:59.000Z"],"type":"string"},"allowStorno":{"description":"Indicator of whether free cancellation/storno is allowed under this policy.","default":false,"type":"boolean"},"stornoFreeHours":{"description":"Number of hours before the reservation/event during which storno is free of charge.","examples":[48],"type":"number"},"stornoFeePercent":{"description":"Storno fee as a percentage of the order price when cancelled within the fee window.","examples":[50],"type":"number"},"stornoFeeDeadlineHours":{"description":"Number of hours before the reservation/event within which the storno fee applies. Cancellations before this window use stornoFreeHours rules.","examples":[24],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["title","body","validFrom"],"properties":{"productId":{"description":"Apply this policy to a specific product.","examples":[42],"type":"number"},"categoryId":{"description":"Apply this policy to all products in a category.","examples":[5],"type":"number"},"title":{"description":"Policy title displayed to staff and optionally to customer.","examples":["Standard return policy"],"type":"string"},"body":{"description":"Full policy text in HTML or plain text. Defines terms and conditions for complaints.","examples":["Items may be returned within 14 days of delivery."],"type":"string"},"validFrom":{"description":"Date from which this policy version is effective.","format":"date-time","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"Date until which this policy is effective. Null means open-ended.","format":"date-time","examples":["2026-12-31T23:59:59.000Z"],"type":"string"},"allowStorno":{"description":"Indicator of whether free cancellation/storno is allowed under this policy.","default":false,"type":"boolean"},"stornoFreeHours":{"description":"Number of hours before the reservation/event during which storno is free of charge.","examples":[48],"type":"number"},"stornoFeePercent":{"description":"Storno fee as a percentage of the order price when cancelled within the fee window.","examples":[50],"type":"number"},"stornoFeeDeadlineHours":{"description":"Number of hours before the reservation/event within which the storno fee applies. Cancellations before this window use stornoFreeHours rules.","examples":[24],"type":"number"}}}}}}}},"/bff/complaint/policy-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Indicates whether the operation completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffComplaintPolicy-update","tags":["Complaint"],"summary":"Update complaint policy","description":"Updates an existing complaint policy. Only provided fields are modified.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Policy ID to update.","examples":[1],"type":"number"},"title":{"description":"Updated policy title.","examples":["Standard return policy"],"type":"string"},"body":{"description":"Updated policy text.","examples":["Items may be returned within 14 days of delivery."],"type":"string"},"validTo":{"description":"Updated expiration date.","format":"date-time","examples":["2026-12-31T23:59:59.000Z"],"type":"string"},"allowStorno":{"description":"Updated storno permission flag.","type":"boolean"},"stornoFreeHours":{"description":"Updated free storno hours window.","examples":[48],"type":"number"},"stornoFeePercent":{"description":"Updated storno fee percentage.","examples":[50],"type":"number"},"stornoFeeDeadlineHours":{"description":"Updated storno fee deadline hours.","examples":[24],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Policy ID to update.","examples":[1],"type":"number"},"title":{"description":"Updated policy title.","examples":["Standard return policy"],"type":"string"},"body":{"description":"Updated policy text.","examples":["Items may be returned within 14 days of delivery."],"type":"string"},"validTo":{"description":"Updated expiration date.","format":"date-time","examples":["2026-12-31T23:59:59.000Z"],"type":"string"},"allowStorno":{"description":"Updated storno permission flag.","type":"boolean"},"stornoFreeHours":{"description":"Updated free storno hours window.","examples":[48],"type":"number"},"stornoFeePercent":{"description":"Updated storno fee percentage.","examples":[50],"type":"number"},"stornoFeeDeadlineHours":{"description":"Updated storno fee deadline hours.","examples":[24],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Policy ID to update.","examples":[1],"type":"number"},"title":{"description":"Updated policy title.","examples":["Standard return policy"],"type":"string"},"body":{"description":"Updated policy text.","examples":["Items may be returned within 14 days of delivery."],"type":"string"},"validTo":{"description":"Updated expiration date.","format":"date-time","examples":["2026-12-31T23:59:59.000Z"],"type":"string"},"allowStorno":{"description":"Updated storno permission flag.","type":"boolean"},"stornoFreeHours":{"description":"Updated free storno hours window.","examples":[48],"type":"number"},"stornoFeePercent":{"description":"Updated storno fee percentage.","examples":[50],"type":"number"},"stornoFeeDeadlineHours":{"description":"Updated storno fee deadline hours.","examples":[24],"type":"number"}}}}}}}},"/bff/contact/list":{"get":{"parameters":[{"schema":{"type":"number"},"in":"query","name":"limit","required":false},{"schema":{"type":"number"},"in":"query","name":"page","required":false},{"description":"Full-text search across name, email, phone, and company name.","examples":["jan@example.com","Novák","+420"],"schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false},{"description":"Comma-separated customer group slugs. Use \"#-no-tags-#\" for untagged contacts.","examples":["vip,wholesale","#-no-tags-#"],"schema":{"type":"string"},"in":"query","name":"tagFilter","required":false},{"description":"Sort field and direction. Format: \"field:asc\" or \"field:desc\".","examples":["credit:desc","last_activity_date:asc"],"schema":{"type":"string"},"in":"query","name":"orderBy","required":false},{"description":"Filter VIP/premium customers.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"isPremium","required":false},{"description":"Filter blocked/banned customers.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"isBanned","required":false},{"description":"Filter by registration status (has password = registered account).","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"isRegistered","required":false},{"description":"Filter test accounts. Use \"false\" to exclude them from reports.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"isTestAccount","required":false},{"description":"Filter customers with positive credit balance (\"true\") or zero credit (\"false\").","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"hasCredit","required":false},{"description":"Filter by customer locale.","examples":["cs","en","de"],"schema":{"type":"string"},"in":"query","name":"locale","required":false},{"description":"Filter customers registered on or after this date (inclusive).","examples":["2026-01-01"],"schema":{"type":"string"},"in":"query","name":"registeredFrom","required":false},{"description":"Filter customers registered on or before this date (inclusive).","examples":["2026-01-31"],"schema":{"type":"string"},"in":"query","name":"registeredTo","required":false},{"description":"Filter customers active on or after this date. Use to find recently active or inactive users.","examples":["2026-01-01"],"schema":{"type":"string"},"in":"query","name":"lastActivityFrom","required":false},{"description":"Filter by bulk email opt-out status. \"true\" = opted out, \"false\" = subscribed.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"ignoreBulkMail","required":false}],"responses":{"200":{"description":"Paginated contact list with CRM analytics.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","email","locale","ignoreBulkMail","registered","credit","creditMoney","defaultOrderSale","groupList","insertedDate","updatedDate","lastActivityDate","accountAgeDays","monthLimitMaxCreditSpendHard","monthLimitMaxCreditSpendSoft","orderPaid","orderNotPaid","orderNew","orderProcessing","orderStorno","orderDone","score","totalRevenue","paidOrderCount","refundTotal","stornoOrderCount","voucherOrderCount","activeSubscriptionCount","badges"],"properties":{"id":{"description":"Contact external ID (16-char).","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Primary e-mail. `null` for phone-only contacts (imported by phone with no e-mail) and for contacts anonymised via GDPR right-to-erasure. Use `phone`, `name`, or the external ID for display when null.","type":"string"},{"type":"null"}]},"name":{"description":"Full display name (first + last).","type":"string"},"firstName":{"description":"First name.","type":"string"},"lastName":{"description":"Last name.","type":"string"},"companyName":{"description":"Company name.","type":"string"},"isCompany":{"description":"True if the contact has company registration data attached.","type":"boolean"},"companyRegistrationNumber":{"description":"IČO / company registration number.","type":"string"},"taxIdentificationNumber":{"description":"DIČ / VAT / tax identification number.","type":"string"},"isVatPayer":{"description":"Whether the contact is currently a VAT payer (from registry).","type":"boolean"},"isUnreliableVatPayer":{"description":"Flagged as unreliable VAT payer by the tax authority.","type":"boolean"},"phone":{"description":"Phone number.","type":"string"},"locale":{"description":"Customer locale code (cs, en, de...).","type":"string"},"newsletter":{"nullable":true,"anyOf":[{"description":"Newsletter subscription status.","anyOf":[{"const":"registered","type":"string"},{"const":"authorized","type":"string"},{"const":"canceled","type":"string"},{"const":"ignored","type":"string"}]},{"type":"null"}]},"ignoreBulkMail":{"description":"Opted out of bulk emails.","type":"boolean"},"testAccount":{"description":"Is a test account.","type":"boolean"},"premium":{"description":"VIP/premium customer flag.","type":"boolean"},"ban":{"description":"Blocked/banned customer flag.","type":"boolean"},"registered":{"description":"Has a password (registered account).","type":"boolean"},"credit":{"description":"Current store credit balance.","type":"number"},"creditMoney":{"description":"Current store credit balance in default currency (CZK).","type":"number"},"defaultOrderSale":{"description":"Default order discount for this customer.","type":"number"},"subscriptionActiveCount":{"description":"Number of active subscriptions (computed from subscription table).","type":"number"},"groupList":{"description":"Customer group memberships.","type":"array","items":{"type":"object","required":["slug","name","color"],"properties":{"slug":{"description":"Group slug identifier.","type":"string"},"name":{"description":"Group display name.","type":"string"},"color":{"description":"Group color hex code.","type":"string"},"count":{"description":"Number of contacts in this group.","type":"number"}}}},"avatarUrl":{"description":"Gravatar URL.","type":"string"},"internalNote":{"description":"Internal admin note.","type":"string"},"insertedDate":{"description":"Registration date.","anyOf":[{"description":"Registration date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last profile update date.","anyOf":[{"description":"Last profile update date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"description":"Last activity timestamp.","anyOf":[{"description":"Last activity timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"accountAgeDays":{"description":"Days since registration.","type":"number"},"monthLimitMaxCreditSpendHard":{"description":"Hard monthly credit spend limit.","type":"number"},"monthLimitMaxCreditSpendSoft":{"description":"Soft monthly credit spend limit (warning threshold).","type":"number"},"orderPaid":{"description":"Number of paid orders.","type":"number"},"orderNotPaid":{"description":"Number of unpaid orders.","type":"number"},"orderNew":{"description":"Orders in \"new\" status.","type":"number"},"orderProcessing":{"description":"Orders in \"processing\" status.","type":"number"},"orderStorno":{"description":"Orders in \"storno\" status (from vitals).","type":"number"},"orderDone":{"description":"Orders in \"done\" status.","type":"number"},"score":{"description":"CRM quality score (0–100). Higher = better customer.","type":"number"},"totalRevenue":{"description":"Lifetime revenue from paid orders.","type":"number"},"paidOrderCount":{"description":"Total number of paid orders (materialized).","type":"number"},"refundTotal":{"description":"Total value of refunded/storno items.","type":"number"},"firstOrderDate":{"description":"Date of first order (ISO timestamp).","type":"string"},"lastOrderDate":{"description":"Date of most recent order (ISO timestamp).","type":"string"},"lastPaidOrderDate":{"description":"Date of most recent paid order (ISO timestamp).","type":"string"},"stornoOrderCount":{"description":"Number of cancelled/storno orders.","type":"number"},"voucherOrderCount":{"description":"Number of orders placed with a voucher.","type":"number"},"activeSubscriptionCount":{"description":"Number of active subscriptions (materialized).","type":"number"},"badges":{"description":"Display-ready badge list (operator, ban, premium, company, VAT flags, reverse charge, tax exempt, test account, subscription) plus user-defined group tags. Same order and contents as the contact detail and hover popover — use directly in the UI.","type":"array","items":{"anyOf":[{"type":"object","required":["kind","slug"],"properties":{"kind":{"const":"system","type":"string"},"slug":{"anyOf":[{"const":"operator","type":"string"},{"const":"ban","type":"string"},{"const":"premium","type":"string"},{"const":"company","type":"string"},{"const":"vatPayer","type":"string"},{"const":"unreliableVatPayer","type":"string"},{"const":"reverseCharge","type":"string"},{"const":"taxExempt","type":"string"},{"const":"testAccount","type":"string"},{"const":"subscription","type":"string"}]}}},{"type":"object","required":["kind","slug","name","color"],"properties":{"kind":{"const":"group","type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"color":{"type":"string"}}}]}}}}},"itemCount":{"description":"Total number of contacts matching the filter (before pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","email","locale","ignoreBulkMail","registered","credit","creditMoney","defaultOrderSale","groupList","insertedDate","updatedDate","lastActivityDate","accountAgeDays","monthLimitMaxCreditSpendHard","monthLimitMaxCreditSpendSoft","orderPaid","orderNotPaid","orderNew","orderProcessing","orderStorno","orderDone","score","totalRevenue","paidOrderCount","refundTotal","stornoOrderCount","voucherOrderCount","activeSubscriptionCount","badges"],"properties":{"id":{"description":"Contact external ID (16-char).","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Primary e-mail. `null` for phone-only contacts (imported by phone with no e-mail) and for contacts anonymised via GDPR right-to-erasure. Use `phone`, `name`, or the external ID for display when null.","type":"string"},{"type":"null"}]},"name":{"description":"Full display name (first + last).","type":"string"},"firstName":{"description":"First name.","type":"string"},"lastName":{"description":"Last name.","type":"string"},"companyName":{"description":"Company name.","type":"string"},"isCompany":{"description":"True if the contact has company registration data attached.","type":"boolean"},"companyRegistrationNumber":{"description":"IČO / company registration number.","type":"string"},"taxIdentificationNumber":{"description":"DIČ / VAT / tax identification number.","type":"string"},"isVatPayer":{"description":"Whether the contact is currently a VAT payer (from registry).","type":"boolean"},"isUnreliableVatPayer":{"description":"Flagged as unreliable VAT payer by the tax authority.","type":"boolean"},"phone":{"description":"Phone number.","type":"string"},"locale":{"description":"Customer locale code (cs, en, de...).","type":"string"},"newsletter":{"nullable":true,"anyOf":[{"description":"Newsletter subscription status.","anyOf":[{"const":"registered","type":"string"},{"const":"authorized","type":"string"},{"const":"canceled","type":"string"},{"const":"ignored","type":"string"}]},{"type":"null"}]},"ignoreBulkMail":{"description":"Opted out of bulk emails.","type":"boolean"},"testAccount":{"description":"Is a test account.","type":"boolean"},"premium":{"description":"VIP/premium customer flag.","type":"boolean"},"ban":{"description":"Blocked/banned customer flag.","type":"boolean"},"registered":{"description":"Has a password (registered account).","type":"boolean"},"credit":{"description":"Current store credit balance.","type":"number"},"creditMoney":{"description":"Current store credit balance in default currency (CZK).","type":"number"},"defaultOrderSale":{"description":"Default order discount for this customer.","type":"number"},"subscriptionActiveCount":{"description":"Number of active subscriptions (computed from subscription table).","type":"number"},"groupList":{"description":"Customer group memberships.","type":"array","items":{"type":"object","required":["slug","name","color"],"properties":{"slug":{"description":"Group slug identifier.","type":"string"},"name":{"description":"Group display name.","type":"string"},"color":{"description":"Group color hex code.","type":"string"},"count":{"description":"Number of contacts in this group.","type":"number"}}}},"avatarUrl":{"description":"Gravatar URL.","type":"string"},"internalNote":{"description":"Internal admin note.","type":"string"},"insertedDate":{"description":"Registration date.","anyOf":[{"description":"Registration date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last profile update date.","anyOf":[{"description":"Last profile update date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"description":"Last activity timestamp.","anyOf":[{"description":"Last activity timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"accountAgeDays":{"description":"Days since registration.","type":"number"},"monthLimitMaxCreditSpendHard":{"description":"Hard monthly credit spend limit.","type":"number"},"monthLimitMaxCreditSpendSoft":{"description":"Soft monthly credit spend limit (warning threshold).","type":"number"},"orderPaid":{"description":"Number of paid orders.","type":"number"},"orderNotPaid":{"description":"Number of unpaid orders.","type":"number"},"orderNew":{"description":"Orders in \"new\" status.","type":"number"},"orderProcessing":{"description":"Orders in \"processing\" status.","type":"number"},"orderStorno":{"description":"Orders in \"storno\" status (from vitals).","type":"number"},"orderDone":{"description":"Orders in \"done\" status.","type":"number"},"score":{"description":"CRM quality score (0–100). Higher = better customer.","type":"number"},"totalRevenue":{"description":"Lifetime revenue from paid orders.","type":"number"},"paidOrderCount":{"description":"Total number of paid orders (materialized).","type":"number"},"refundTotal":{"description":"Total value of refunded/storno items.","type":"number"},"firstOrderDate":{"description":"Date of first order (ISO timestamp).","type":"string"},"lastOrderDate":{"description":"Date of most recent order (ISO timestamp).","type":"string"},"lastPaidOrderDate":{"description":"Date of most recent paid order (ISO timestamp).","type":"string"},"stornoOrderCount":{"description":"Number of cancelled/storno orders.","type":"number"},"voucherOrderCount":{"description":"Number of orders placed with a voucher.","type":"number"},"activeSubscriptionCount":{"description":"Number of active subscriptions (materialized).","type":"number"},"badges":{"description":"Display-ready badge list (operator, ban, premium, company, VAT flags, reverse charge, tax exempt, test account, subscription) plus user-defined group tags. Same order and contents as the contact detail and hover popover — use directly in the UI.","type":"array","items":{"anyOf":[{"type":"object","required":["kind","slug"],"properties":{"kind":{"const":"system","type":"string"},"slug":{"anyOf":[{"const":"operator","type":"string"},{"const":"ban","type":"string"},{"const":"premium","type":"string"},{"const":"company","type":"string"},{"const":"vatPayer","type":"string"},{"const":"unreliableVatPayer","type":"string"},{"const":"reverseCharge","type":"string"},{"const":"taxExempt","type":"string"},{"const":"testAccount","type":"string"},{"const":"subscription","type":"string"}]}}},{"type":"object","required":["kind","slug","name","color"],"properties":{"kind":{"const":"group","type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"color":{"type":"string"}}}]}}}}},"itemCount":{"description":"Total number of contacts matching the filter (before pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","email","locale","ignoreBulkMail","registered","credit","creditMoney","defaultOrderSale","groupList","insertedDate","updatedDate","lastActivityDate","accountAgeDays","monthLimitMaxCreditSpendHard","monthLimitMaxCreditSpendSoft","orderPaid","orderNotPaid","orderNew","orderProcessing","orderStorno","orderDone","score","totalRevenue","paidOrderCount","refundTotal","stornoOrderCount","voucherOrderCount","activeSubscriptionCount","badges"],"properties":{"id":{"description":"Contact external ID (16-char).","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Primary e-mail. `null` for phone-only contacts (imported by phone with no e-mail) and for contacts anonymised via GDPR right-to-erasure. Use `phone`, `name`, or the external ID for display when null.","type":"string"},{"type":"null"}]},"name":{"description":"Full display name (first + last).","type":"string"},"firstName":{"description":"First name.","type":"string"},"lastName":{"description":"Last name.","type":"string"},"companyName":{"description":"Company name.","type":"string"},"isCompany":{"description":"True if the contact has company registration data attached.","type":"boolean"},"companyRegistrationNumber":{"description":"IČO / company registration number.","type":"string"},"taxIdentificationNumber":{"description":"DIČ / VAT / tax identification number.","type":"string"},"isVatPayer":{"description":"Whether the contact is currently a VAT payer (from registry).","type":"boolean"},"isUnreliableVatPayer":{"description":"Flagged as unreliable VAT payer by the tax authority.","type":"boolean"},"phone":{"description":"Phone number.","type":"string"},"locale":{"description":"Customer locale code (cs, en, de...).","type":"string"},"newsletter":{"nullable":true,"anyOf":[{"description":"Newsletter subscription status.","anyOf":[{"const":"registered","type":"string"},{"const":"authorized","type":"string"},{"const":"canceled","type":"string"},{"const":"ignored","type":"string"}]},{"type":"null"}]},"ignoreBulkMail":{"description":"Opted out of bulk emails.","type":"boolean"},"testAccount":{"description":"Is a test account.","type":"boolean"},"premium":{"description":"VIP/premium customer flag.","type":"boolean"},"ban":{"description":"Blocked/banned customer flag.","type":"boolean"},"registered":{"description":"Has a password (registered account).","type":"boolean"},"credit":{"description":"Current store credit balance.","type":"number"},"creditMoney":{"description":"Current store credit balance in default currency (CZK).","type":"number"},"defaultOrderSale":{"description":"Default order discount for this customer.","type":"number"},"subscriptionActiveCount":{"description":"Number of active subscriptions (computed from subscription table).","type":"number"},"groupList":{"description":"Customer group memberships.","type":"array","items":{"type":"object","required":["slug","name","color"],"properties":{"slug":{"description":"Group slug identifier.","type":"string"},"name":{"description":"Group display name.","type":"string"},"color":{"description":"Group color hex code.","type":"string"},"count":{"description":"Number of contacts in this group.","type":"number"}}}},"avatarUrl":{"description":"Gravatar URL.","type":"string"},"internalNote":{"description":"Internal admin note.","type":"string"},"insertedDate":{"description":"Registration date.","anyOf":[{"description":"Registration date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last profile update date.","anyOf":[{"description":"Last profile update date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastActivityDate":{"description":"Last activity timestamp.","anyOf":[{"description":"Last activity timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"accountAgeDays":{"description":"Days since registration.","type":"number"},"monthLimitMaxCreditSpendHard":{"description":"Hard monthly credit spend limit.","type":"number"},"monthLimitMaxCreditSpendSoft":{"description":"Soft monthly credit spend limit (warning threshold).","type":"number"},"orderPaid":{"description":"Number of paid orders.","type":"number"},"orderNotPaid":{"description":"Number of unpaid orders.","type":"number"},"orderNew":{"description":"Orders in \"new\" status.","type":"number"},"orderProcessing":{"description":"Orders in \"processing\" status.","type":"number"},"orderStorno":{"description":"Orders in \"storno\" status (from vitals).","type":"number"},"orderDone":{"description":"Orders in \"done\" status.","type":"number"},"score":{"description":"CRM quality score (0–100). Higher = better customer.","type":"number"},"totalRevenue":{"description":"Lifetime revenue from paid orders.","type":"number"},"paidOrderCount":{"description":"Total number of paid orders (materialized).","type":"number"},"refundTotal":{"description":"Total value of refunded/storno items.","type":"number"},"firstOrderDate":{"description":"Date of first order (ISO timestamp).","type":"string"},"lastOrderDate":{"description":"Date of most recent order (ISO timestamp).","type":"string"},"lastPaidOrderDate":{"description":"Date of most recent paid order (ISO timestamp).","type":"string"},"stornoOrderCount":{"description":"Number of cancelled/storno orders.","type":"number"},"voucherOrderCount":{"description":"Number of orders placed with a voucher.","type":"number"},"activeSubscriptionCount":{"description":"Number of active subscriptions (materialized).","type":"number"},"badges":{"description":"Display-ready badge list (operator, ban, premium, company, VAT flags, reverse charge, tax exempt, test account, subscription) plus user-defined group tags. Same order and contents as the contact detail and hover popover — use directly in the UI.","type":"array","items":{"anyOf":[{"type":"object","required":["kind","slug"],"properties":{"kind":{"const":"system","type":"string"},"slug":{"anyOf":[{"const":"operator","type":"string"},{"const":"ban","type":"string"},{"const":"premium","type":"string"},{"const":"company","type":"string"},{"const":"vatPayer","type":"string"},{"const":"unreliableVatPayer","type":"string"},{"const":"reverseCharge","type":"string"},{"const":"taxExempt","type":"string"},{"const":"testAccount","type":"string"},{"const":"subscription","type":"string"}]}}},{"type":"object","required":["kind","slug","name","color"],"properties":{"kind":{"const":"group","type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"color":{"type":"string"}}}]}}}}},"itemCount":{"description":"Total number of contacts matching the filter (before pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffContactList","tags":["Contact"],"summary":"List contacts","description":"Returns a paginated list of contacts/customers with vitals, group membership, newsletter status, and CRM analytics. Supports full-text search, group filtering, and 10 attribute filters. All boolean filters use string values (\"true\"/\"false\"). Pagination via limit/page query params."}},"/bff/contact/detail":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactDetail","tags":["Contact"],"summary":"Get contact detail","description":"Returns full detail of a single contact by external ID, including profile data and CRM info. Vitals include both `credit` (count) and `creditMoney` (monetary value); the response also includes `currency` (ISO 4217 code of the organisation default currency) used for all *Money fields. Values are guaranteed consistent with `/bff/contact/detail-credit` for the same customer.","responses":{"200":{}}}},"/bff/contact/detail-edit":{"post":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactDetail-edit","tags":["Contact"],"summary":"Edit contact detail","description":"Updates profile fields, group memberships, and account flags for a contact. Body is validated via Zod schema."}},"/bff/contact/update-internal-notice":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactUpdate-internal-notice","tags":["Contact"],"summary":"Update contact internal notice","description":"Single-field update of the internal notice on a contact — used by the inline-edit affordance on the contact detail. Endpoint /detail-edit still updates the full profile.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId","internalNotice"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId","internalNotice"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["customerId","internalNotice"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"}}}}}}}},"/bff/contact/company-refresh":{"post":{"parameters":[],"operationId":"postBffContactCompany-refresh","tags":["Contact"],"summary":"Force-refresh company registry record","description":"Forces a fresh fetch from the company registry (ARES for CZ) for a contact and updates the cached company record, including VAT-payer status and the unreliable-VAT-payer cross-check.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/contact/detail-change-email-preview":{"post":{"parameters":[],"operationId":"postBffContactDetail-change-email-preview","tags":["Contact"],"summary":"Preview the effect of changing a contact e-mail","description":"Returns whether submitting the given e-mail would be a no-op, a plain rename, or a merge with an existing contact. Designed for live ajax feedback as the operator types into the change-email form.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","newEmail"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"newEmail":{"description":"Candidate new e-mail address (may be unnormalized).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","newEmail"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"newEmail":{"description":"Candidate new e-mail address (may be unnormalized).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","newEmail"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"newEmail":{"description":"Candidate new e-mail address (may be unnormalized).","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/contact/detail-change-email":{"post":{"parameters":[],"operationId":"postBffContactDetail-change-email","tags":["Contact"],"summary":"Change contact email","description":"Changes the primary email address of a contact. Requires the current email for verification. When the target e-mail is already taken by another contact in the same organisation, the call fails unless `confirmMerge: true` is provided, in which case the duplicate is merged into the current contact first.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","currentEmail","newEmail","reason"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"currentEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"newEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"reason":{"description":"Reason for the email change.","type":"string"},"confirmMerge":{"description":"Set to true to acknowledge that another contact already owns the target e-mail; that contact will be merged into the current one before the rename.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","currentEmail","newEmail","reason"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"currentEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"newEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"reason":{"description":"Reason for the email change.","type":"string"},"confirmMerge":{"description":"Set to true to acknowledge that another contact already owns the target e-mail; that contact will be merged into the current one before the rename.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id","currentEmail","newEmail","reason"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"currentEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"newEmail":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"reason":{"description":"Reason for the email change.","type":"string"},"confirmMerge":{"description":"Set to true to acknowledge that another contact already owns the target e-mail; that contact will be merged into the current one before the rename.","type":"boolean"}}}}}},"responses":{"200":{}}}},"/bff/contact/detail-sessions":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactDetail-sessions","tags":["Contact"],"summary":"List contact sessions","description":"Returns active and recent sessions for a contact.","responses":{"200":{}}}},"/bff/contact/detail-ip-report":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactDetail-ip-report","tags":["Contact"],"summary":"IP address report for a contact","description":"Returns one row per IP address that is or was linked to the contact across all data sources (orders, carts, sessions/logins, registration, consents, email & newsletter opens, blog comments, CRM leads, and the shop__contact_geo tracking aggregate) — including per-source counts, first/last seen timestamps and GeoIP metadata (city, country, hostname, ASN, mobile/proxy/hosting/tor flags).","responses":{"200":{}}}},"/bff/contact/detail-password-log":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactDetail-password-log","tags":["Contact"],"summary":"Get contact password log","description":"Returns a list of password change events for a contact.","responses":{"200":{}}}},"/bff/contact/detail-security-info":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactDetail-security-info","tags":["Contact"],"summary":"Get contact security info","description":"Returns security-related information for a contact, including last password change date.","responses":{"200":{}}}},"/bff/contact/detail-address":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactDetail-address","tags":["Contact"],"summary":"Get contact addresses","description":"Returns a list of addresses associated with a contact.","responses":{"200":{}}}},"/bff/contact/group-list":{"get":{"operationId":"getBffContactGroup-list","tags":["Contact"],"summary":"List contact groups","description":"Returns all contact groups (tags) defined for the organisation.","responses":{"200":{}}}},"/bff/contact/set-password":{"post":{"parameters":[],"operationId":"postBffContactSet-password","tags":["Contact"],"summary":"Set contact password","description":"Sets a new password for a contact account.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId","newPassword"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"newPassword":{"description":"New password to set.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId","newPassword"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"newPassword":{"description":"New password to set.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["customerId","newPassword"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"newPassword":{"description":"New password to set.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/contact/merge-customers":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactMerge-customers","tags":["Contact"],"summary":"Merge two contacts","description":"Merges the legacy contact into the final contact, transferring all related data.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["finalCustomerId","legacyCustomerId"],"properties":{"finalCustomerId":{"description":"External ID of the contact to keep.","type":"string"},"legacyCustomerId":{"description":"External ID of the contact to merge and remove.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["finalCustomerId","legacyCustomerId"],"properties":{"finalCustomerId":{"description":"External ID of the contact to keep.","type":"string"},"legacyCustomerId":{"description":"External ID of the contact to merge and remove.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["finalCustomerId","legacyCustomerId"],"properties":{"finalCustomerId":{"description":"External ID of the contact to keep.","type":"string"},"legacyCustomerId":{"description":"External ID of the contact to merge and remove.","type":"string"}}}}}}}},"/bff/contact/invalidate-sessions":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactInvalidate-sessions","tags":["Contact"],"summary":"Invalidate contact sessions","description":"Invalidates all active sessions for a contact, forcing re-authentication.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"}}}}}}}},"/bff/contact/reset-password":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactReset-password","tags":["Contact"],"summary":"Request password reset","description":"Create a new reset password request and send verification mail to customer automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"}}}}}}}},"/bff/contact/process-set-password":{"post":{"parameters":[],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Change password failed.","You have entered a previously used password. For security reasons, please enter a new and unique password.","Reset password request does not exist.","Reset password request has been expired."],"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Change password failed.","You have entered a previously used password. For security reasons, please enter a new and unique password.","Reset password request does not exist.","Reset password request has been expired."],"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Change password failed.","You have entered a previously used password. For security reasons, please enter a new and unique password.","Reset password request does not exist.","Reset password request has been expired."],"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","errorCode","message"],"properties":{"success":{"const":false,"type":"boolean"},"errorCode":{"examples":["E001","E002","E003","E004"],"type":"string"},"message":{"examples":["Change password failed.","You have entered a previously used password. For security reasons, please enter a new and unique password.","Reset password request does not exist.","Reset password request has been expired."],"type":"string"}}}]}}}}},"operationId":"postBffContactProcess-set-password","tags":["Contact"],"summary":"Process password reset","description":"Validates the reset token and sets the new password for the contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","password"],"properties":{"token":{"description":"Password reset token from the verification email.","type":"string"},"password":{"description":"New password to set.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["token","password"],"properties":{"token":{"description":"Password reset token from the verification email.","type":"string"},"password":{"description":"New password to set.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["token","password"],"properties":{"token":{"description":"Password reset token from the verification email.","type":"string"},"password":{"description":"New password to set.","type":"string"}}}}}}}},"/bff/contact/generate-api-key":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"apiKey":{"type":"string"}},"required":["success","apiKey"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"apiKey":{"type":"string"}},"required":["success","apiKey"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"apiKey":{"type":"string"}},"required":["success","apiKey"]}}}}},"operationId":"postBffContactGenerate-api-key","tags":["Contact"],"summary":"Generate API key","description":"Generates a new API key for a contact, bound to a specific workspace.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","name","workspace"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"name":{"description":"Display name for the API key.","type":"string"},"workspace":{"description":"Workspace code to associate with the key.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","name","workspace"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"name":{"description":"Display name for the API key.","type":"string"},"workspace":{"description":"Workspace code to associate with the key.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","name","workspace"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"name":{"description":"Display name for the API key.","type":"string"},"workspace":{"description":"Workspace code to associate with the key.","type":"string"}}}}}}}},"/bff/contact/workspace-list":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactWorkspace-list","tags":["Contact"],"summary":"List contact workspaces","description":"Returns all workspaces assigned to a contact.","responses":{"200":{}}}},"/bff/contact/add-workspace":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactAdd-workspace","tags":["Contact"],"summary":"Add workspace to contact","description":"Creates a new workspace for a contact with the given name and color.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","name","color"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"name":{"description":"Workspace display name.","type":"string"},"color":{"description":"Workspace color (hex code).","examples":["#ff0000"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","name","color"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"name":{"description":"Workspace display name.","type":"string"},"color":{"description":"Workspace color (hex code).","examples":["#ff0000"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","name","color"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"name":{"description":"Workspace display name.","type":"string"},"color":{"description":"Workspace color (hex code).","examples":["#ff0000"],"type":"string"}}}}}}}},"/bff/contact/block-contact":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactBlock-contact","tags":["Contact"],"summary":"Block or unblock contact","description":"Toggles the block/ban status of a contact. If currently blocked, unblocks; if unblocked, blocks.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"reason":{"description":"Reason for blocking or unblocking.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"reason":{"description":"Reason for blocking or unblocking.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"reason":{"description":"Reason for blocking or unblocking.","type":"string"}}}}}}}},"/bff/contact/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactDelete","tags":["Contact"],"summary":"Soft-delete contact","description":"Marks a contact as deleted (soft delete). The contact cannot already be deleted.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"reason":{"description":"Reason for deletion.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"reason":{"description":"Reason for deletion.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"reason":{"description":"Reason for deletion.","type":"string"}}}}}}}},"/bff/contact/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"customerId":{"description":"External ID of the newly created contact.","type":"string"}},"required":["success","customerId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"customerId":{"description":"External ID of the newly created contact.","type":"string"}},"required":["success","customerId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"customerId":{"description":"External ID of the newly created contact.","type":"string"}},"required":["success","customerId"]}}}}},"operationId":"postBffContactCreate","tags":["Contact"],"summary":"Quick-create contact","description":"Creates a single contact from a minimal form. **Either `email` OR `phone` is required** (both are allowed). First name, last name and IČO are optional. When IČO is provided, the company name and address are auto-filled from ARES. Optionally triggers the registration workflow with the standard confirmation e-mail (requires `email`).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Contact first name.","type":"string"},"lastName":{"description":"Contact last name.","type":"string"},"phone":{"description":"Contact phone number. Normalised to international format using the organisation default country prefix. Required when `email` is omitted (phone-only contact).","type":"string"},"companyRegistrationNumber":{"description":"IČO (Czech company registration number). When provided, the company name and invoice address are auto-filled from ARES.","type":"string"},"sendRegistrationInvite":{"description":"When true, also triggers the standard registration workflow and sends the registration confirmation e-mail to the contact. Requires `email` to be present.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Contact first name.","type":"string"},"lastName":{"description":"Contact last name.","type":"string"},"phone":{"description":"Contact phone number. Normalised to international format using the organisation default country prefix. Required when `email` is omitted (phone-only contact).","type":"string"},"companyRegistrationNumber":{"description":"IČO (Czech company registration number). When provided, the company name and invoice address are auto-filled from ARES.","type":"string"},"sendRegistrationInvite":{"description":"When true, also triggers the standard registration workflow and sends the registration confirmation e-mail to the contact. Requires `email` to be present.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Contact first name.","type":"string"},"lastName":{"description":"Contact last name.","type":"string"},"phone":{"description":"Contact phone number. Normalised to international format using the organisation default country prefix. Required when `email` is omitted (phone-only contact).","type":"string"},"companyRegistrationNumber":{"description":"IČO (Czech company registration number). When provided, the company name and invoice address are auto-filled from ARES.","type":"string"},"sendRegistrationInvite":{"description":"When true, also triggers the standard registration workflow and sends the registration confirmation e-mail to the contact. Requires `email` to be present.","type":"boolean"}}}}}}}},"/bff/contact/check-email-availability":{"post":{"parameters":[],"operationId":"postBffContactCheck-email-availability","tags":["Contact"],"summary":"Check whether an e-mail can be used for a new contact","description":"Normalizes the candidate e-mail via fixEmail() and reports whether it is empty, invalid, available, or already taken by another contact in the organisation. Designed for live ajax feedback as the operator types into the create-contact form.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"description":"Candidate e-mail address (may be unnormalized).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email"],"properties":{"email":{"description":"Candidate e-mail address (may be unnormalized).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email"],"properties":{"email":{"description":"Candidate e-mail address (may be unnormalized).","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/contact/bulk-import":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactBulk-import","tags":["Contact"],"summary":"Bulk import contacts","description":"Imports multiple contacts at once with the given internal note.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contactList","internalNote"],"properties":{"contactList":{"description":"List of contacts to import.","type":"array","items":{"type":"object","required":["email","name"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"description":"Contact display name.","type":"string"}}}},"internalNote":{"description":"Internal note attached to all imported contacts.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["contactList","internalNote"],"properties":{"contactList":{"description":"List of contacts to import.","type":"array","items":{"type":"object","required":["email","name"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"description":"Contact display name.","type":"string"}}}},"internalNote":{"description":"Internal note attached to all imported contacts.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["contactList","internalNote"],"properties":{"contactList":{"description":"List of contacts to import.","type":"array","items":{"type":"object","required":["email","name"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"name":{"description":"Contact display name.","type":"string"}}}},"internalNote":{"description":"Internal note attached to all imported contacts.","type":"string"}}}}}}}},"/bff/contact/consent/grant":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactConsentGrant","tags":["Contact"],"summary":"Grant consent","description":"Grants a specific consent type for a contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"type":{"description":"Consent type.","examples":["newsletter","marketing","gdpr"],"type":"string"},"source":{"description":"Source of the consent grant.","examples":["admin","web"],"type":"string"},"note":{"description":"Optional note about the consent.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","type"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"type":{"description":"Consent type.","examples":["newsletter","marketing","gdpr"],"type":"string"},"source":{"description":"Source of the consent grant.","examples":["admin","web"],"type":"string"},"note":{"description":"Optional note about the consent.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","type"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"type":{"description":"Consent type.","examples":["newsletter","marketing","gdpr"],"type":"string"},"source":{"description":"Source of the consent grant.","examples":["admin","web"],"type":"string"},"note":{"description":"Optional note about the consent.","type":"string"}}}}}}}},"/bff/contact/consent/revoke":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactConsentRevoke","tags":["Contact"],"summary":"Revoke consent","description":"Revokes a specific consent type for a contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","type"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"type":{"description":"Consent type.","examples":["newsletter","marketing","gdpr"],"type":"string"},"source":{"description":"Source of the consent revocation.","examples":["admin","web"],"type":"string"},"note":{"description":"Optional note about the revocation.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","type"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"type":{"description":"Consent type.","examples":["newsletter","marketing","gdpr"],"type":"string"},"source":{"description":"Source of the consent revocation.","examples":["admin","web"],"type":"string"},"note":{"description":"Optional note about the revocation.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","type"],"properties":{"id":{"description":"Contact external ID.","type":"string"},"type":{"description":"Consent type.","examples":["newsletter","marketing","gdpr"],"type":"string"},"source":{"description":"Source of the consent revocation.","examples":["admin","web"],"type":"string"},"note":{"description":"Optional note about the revocation.","type":"string"}}}}}}}},"/bff/contact/custom-field/definition-list":{"get":{"operationId":"getBffContactCustom-fieldDefinition-list","tags":["Contact"],"summary":"List custom field definitions","description":"Returns all custom field definitions configured for the organisation.","responses":{"200":{}}}},"/bff/contact/custom-field/definition-save":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactCustom-fieldDefinition-save","tags":["Contact"],"summary":"Save custom field definition","description":"Creates or updates a custom field definition. Uses upsert on key + organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key","type","label","required","active","position"],"properties":{"key":{"description":"Unique field key identifier.","examples":["company_size"],"type":"string"},"type":{"description":"Field data type.","examples":["text","number","select"],"type":"string"},"label":{"description":"Display label for the field.","type":"string"},"helperText":{"description":"Help text shown below the field.","type":"string"},"placeholder":{"description":"Placeholder text for the input.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"active":{"description":"Whether the field is active and visible.","type":"boolean"},"validationPattern":{"description":"Regex validation pattern.","type":"string"},"position":{"description":"Sort order position.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["key","type","label","required","active","position"],"properties":{"key":{"description":"Unique field key identifier.","examples":["company_size"],"type":"string"},"type":{"description":"Field data type.","examples":["text","number","select"],"type":"string"},"label":{"description":"Display label for the field.","type":"string"},"helperText":{"description":"Help text shown below the field.","type":"string"},"placeholder":{"description":"Placeholder text for the input.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"active":{"description":"Whether the field is active and visible.","type":"boolean"},"validationPattern":{"description":"Regex validation pattern.","type":"string"},"position":{"description":"Sort order position.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["key","type","label","required","active","position"],"properties":{"key":{"description":"Unique field key identifier.","examples":["company_size"],"type":"string"},"type":{"description":"Field data type.","examples":["text","number","select"],"type":"string"},"label":{"description":"Display label for the field.","type":"string"},"helperText":{"description":"Help text shown below the field.","type":"string"},"placeholder":{"description":"Placeholder text for the input.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"active":{"description":"Whether the field is active and visible.","type":"boolean"},"validationPattern":{"description":"Regex validation pattern.","type":"string"},"position":{"description":"Sort order position.","type":"number"}}}}}}}},"/bff/contact/custom-field/set":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactCustom-fieldSet","tags":["Contact"],"summary":"Set custom field value","description":"Sets a custom field value for a specific contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId","key","value"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"key":{"description":"Custom field key.","type":"string"},"value":{"description":"Value to set for the custom field.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId","key","value"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"key":{"description":"Custom field key.","type":"string"},"value":{"description":"Value to set for the custom field.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["customerId","key","value"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"key":{"description":"Custom field key.","type":"string"},"value":{"description":"Value to set for the custom field.","type":"string"}}}}}}}},"/bff/contact/custom-field/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactCustom-fieldDelete","tags":["Contact"],"summary":"Delete custom field value","description":"Removes a custom field value from a specific contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId","key"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"key":{"description":"Custom field key to delete.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId","key"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"key":{"description":"Custom field key to delete.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["customerId","key"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"key":{"description":"Custom field key to delete.","type":"string"}}}}}}}},"/bff/contact/hierarchy":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactHierarchy","tags":["Contact"],"summary":"Get contact hierarchy","description":"Returns the direct superior (single parent), all direct subordinates (children), and colleagues (contacts sharing the same non-null superior) for a contact.","responses":{"200":{}}}},"/bff/contact/set-parent":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactSet-parent","tags":["Contact"],"summary":"Set contact superior","description":"Assigns a parent (superior) contact. Pass null/omit `parentCustomerId` to detach. Rejected when the target would create a cycle or when contact equals parent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID whose superior is being changed.","type":"string"},"parentCustomerId":{"nullable":true,"anyOf":[{"description":"External ID of the new superior. Pass null or omit to detach (contact becomes a root node).","type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID whose superior is being changed.","type":"string"},"parentCustomerId":{"nullable":true,"anyOf":[{"description":"External ID of the new superior. Pass null or omit to detach (contact becomes a root node).","type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID whose superior is being changed.","type":"string"},"parentCustomerId":{"nullable":true,"anyOf":[{"description":"External ID of the new superior. Pass null or omit to detach (contact becomes a root node).","type":"string"},{"type":"null"}]}}}}}}}},"/bff/contact/org-tree":{"get":{"parameters":[{"description":"Focused contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactOrg-tree","tags":["Contact"],"summary":"Get organisational tree around a contact","description":"Returns the focused contact together with its ancestor chain (root-first) and the full subtree rooted at the focused contact. Useful for MS Teams-style org charts. Depth is capped at 32 levels in each direction.","responses":{"200":{}}}},"/bff/contact/set-billing-flags":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactSet-billing-flags","tags":["Contact"],"summary":"Set contact billing flags (reverse charge / tax exempt)","description":"Updates the EU reverse-charge default and tax-exempt status of a contact. Only the provided fields are changed; omit a field to keep its current value.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"reverseCharge":{"description":"When true, invoices for this contact default to 0 % VAT with the \"reverse charge\" note (EU B2B intra-community supply). Set true after a successful VIES validation for non-CZ EU contacts.","type":"boolean"},"taxExempt":{"description":"When true, the contact is exempt from VAT (non-profits, government bodies, etc.).","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"reverseCharge":{"description":"When true, invoices for this contact default to 0 % VAT with the \"reverse charge\" note (EU B2B intra-community supply). Set true after a successful VIES validation for non-CZ EU contacts.","type":"boolean"},"taxExempt":{"description":"When true, the contact is exempt from VAT (non-profits, government bodies, etc.).","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"reverseCharge":{"description":"When true, invoices for this contact default to 0 % VAT with the \"reverse charge\" note (EU B2B intra-community supply). Set true after a successful VIES validation for non-CZ EU contacts.","type":"boolean"},"taxExempt":{"description":"When true, the contact is exempt from VAT (non-profits, government bodies, etc.).","type":"boolean"}}}}}}}},"/bff/contact/email-list":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","email","label","sendInvoices","sendReminders","sendMarketing","position","insertedDate","updatedDate"],"properties":{"id":{"description":"Internal row id (use it for update / delete).","type":"number"},"email":{"type":"string"},"label":{"description":"Free-form role label, e.g. \"Účetní\", \"Project manager\", \"Billing\".","anyOf":[{"type":"string"},{"type":"null"}]},"sendInvoices":{"type":"boolean"},"sendReminders":{"type":"boolean"},"sendMarketing":{"type":"boolean"},"position":{"description":"Display order within the contact (lower = primary).","type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","email","label","sendInvoices","sendReminders","sendMarketing","position","insertedDate","updatedDate"],"properties":{"id":{"description":"Internal row id (use it for update / delete).","type":"number"},"email":{"type":"string"},"label":{"description":"Free-form role label, e.g. \"Účetní\", \"Project manager\", \"Billing\".","anyOf":[{"type":"string"},{"type":"null"}]},"sendInvoices":{"type":"boolean"},"sendReminders":{"type":"boolean"},"sendMarketing":{"type":"boolean"},"position":{"description":"Display order within the contact (lower = primary).","type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","email","label","sendInvoices","sendReminders","sendMarketing","position","insertedDate","updatedDate"],"properties":{"id":{"description":"Internal row id (use it for update / delete).","type":"number"},"email":{"type":"string"},"label":{"description":"Free-form role label, e.g. \"Účetní\", \"Project manager\", \"Billing\".","anyOf":[{"type":"string"},{"type":"null"}]},"sendInvoices":{"type":"boolean"},"sendReminders":{"type":"boolean"},"sendMarketing":{"type":"boolean"},"position":{"description":"Display order within the contact (lower = primary).","type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffContactEmail-list","tags":["Contact"],"summary":"List billing email roles for a contact","description":"Returns every additional email associated with the contact and the channel toggles (invoices / reminders / marketing). The contact's primary `shop__contact.email` is NOT included — render it separately in the UI."}},"/bff/contact/email-upsert":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Row id of the inserted or updated record.","type":"number"},"inserted":{"description":"True for new rows, false when an existing row was updated.","type":"boolean"}},"required":["id","inserted"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Row id of the inserted or updated record.","type":"number"},"inserted":{"description":"True for new rows, false when an existing row was updated.","type":"boolean"}},"required":["id","inserted"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Row id of the inserted or updated record.","type":"number"},"inserted":{"description":"True for new rows, false when an existing row was updated.","type":"boolean"}},"required":["id","inserted"]}}}}},"operationId":"postBffContactEmail-upsert","tags":["Contact"],"summary":"Insert or update a billing email role","description":"Idempotent on (contact, lower(email)). When the same email already exists on the contact, the row is updated; otherwise a new row is inserted. Position auto-fills as \"max + 1\" when omitted.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId","email"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"id":{"description":"Existing row id — provide to update; omit to insert (or upsert by email).","type":"number"},"email":{"description":"Email address.","examples":["accountant@client.cz"],"type":"string"},"label":{"description":"Role label.","examples":["Účetní","PM","Billing"],"type":"string"},"sendInvoices":{"description":"Receive invoices? Default true.","type":"boolean"},"sendReminders":{"description":"Receive overdue reminders? Default true.","type":"boolean"},"sendMarketing":{"description":"Receive marketing? Default false.","type":"boolean"},"position":{"description":"Display order; auto-assigned to \"max + 1\" when omitted.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId","email"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"id":{"description":"Existing row id — provide to update; omit to insert (or upsert by email).","type":"number"},"email":{"description":"Email address.","examples":["accountant@client.cz"],"type":"string"},"label":{"description":"Role label.","examples":["Účetní","PM","Billing"],"type":"string"},"sendInvoices":{"description":"Receive invoices? Default true.","type":"boolean"},"sendReminders":{"description":"Receive overdue reminders? Default true.","type":"boolean"},"sendMarketing":{"description":"Receive marketing? Default false.","type":"boolean"},"position":{"description":"Display order; auto-assigned to \"max + 1\" when omitted.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["customerId","email"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"id":{"description":"Existing row id — provide to update; omit to insert (or upsert by email).","type":"number"},"email":{"description":"Email address.","examples":["accountant@client.cz"],"type":"string"},"label":{"description":"Role label.","examples":["Účetní","PM","Billing"],"type":"string"},"sendInvoices":{"description":"Receive invoices? Default true.","type":"boolean"},"sendReminders":{"description":"Receive overdue reminders? Default true.","type":"boolean"},"sendMarketing":{"description":"Receive marketing? Default false.","type":"boolean"},"position":{"description":"Display order; auto-assigned to \"max + 1\" when omitted.","type":"number"}}}}}}}},"/bff/contact/email-delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContactEmail-delete","tags":["Contact"],"summary":"Remove a billing email role","description":"Deletes one email row from a contact. The primary `shop__contact.email` is unaffected.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId","id"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"id":{"description":"Row id of the email to remove.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId","id"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"id":{"description":"Row id of the email to remove.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["customerId","id"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"},"id":{"description":"Row id of the email to remove.","type":"number"}}}}}}}},"/bff/contact/export-gdpr":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"operationId":"getBffContactExport-gdpr","tags":["Contact"],"summary":"Download personal data export (GDPR Art. 15)","description":"Generates a ZIP bundle with all personal data the organisation holds about the contact — profile, addresses, company record, additional e-mails, consent audit trail, orders, invoices, subscriptions, comments, and the system activity log. Companion `README.md` and `index.html` are rendered in the contact’s preferred language. Internal identifiers, hashes and other non-personal data are deliberately omitted.","responses":{"200":{}}}},"/bff/contact/export-gdpr-email":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"recipientEmail":{"type":"string"},"filename":{"type":"string"}},"required":["success","recipientEmail","filename"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"recipientEmail":{"type":"string"},"filename":{"type":"string"}},"required":["success","recipientEmail","filename"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"recipientEmail":{"type":"string"},"filename":{"type":"string"}},"required":["success","recipientEmail","filename"]}}}}},"operationId":"postBffContactExport-gdpr-email","tags":["Contact"],"summary":"E-mail personal data export to the contact (GDPR Art. 15)","description":"Generates the same ZIP bundle as `/export-gdpr` and dispatches it as an attachment to the contact’s primary e-mail address. The message body is rendered from the `contact-gdpr-export` notification template (per-org override or system default) in the contact’s preferred language. The ZIP is also persisted in blob storage so it remains downloadable from the e-mail audit log.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["customerId"],"properties":{"customerId":{"description":"Contact external ID.","examples":["abc123def456ghij"],"type":"string"}}}}}}}},"/bff/contact-credit/list":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"credit":{"description":"Current credit balance (number of credits).","examples":[3300],"type":"number"},"creditMoney":{"description":"Current credit balance expressed in the organisation default currency.","examples":[3000],"type":"number"},"currency":{"description":"ISO 4217 code of the organisation default currency used for all *Money fields.","examples":["CZK"],"type":"string"},"items":{"description":"Credit transactions ordered from most recent to oldest.","type":"array","items":{"type":"object","required":["id","amount","amountMoney","balance","balanceMoney","insertedDate"],"properties":{"id":{"description":"Transaction external ID.","examples":["HxanU4a1n4El61zx"],"type":"string"},"amount":{"description":"Credit amount (positive = added, negative = spent).","examples":[3300,-100],"type":"number"},"amountMoney":{"description":"Monetary value of the transaction in the organisation default currency. Defaults to the same value as `amount` (1:1) when no explicit money value was stored.","examples":[3000,-100,0],"type":"number"},"balance":{"description":"Running credit balance after this transaction.","examples":[3300],"type":"number"},"balanceMoney":{"description":"Running monetary balance after this transaction (in the organisation default currency).","examples":[3000],"type":"number"},"order":{"type":"object","required":["orderNumber","hash","groupName"],"properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"groupName":{"examples":["GymRoom Vinohrady"],"type":"string"}}},"expiration":{"type":"object","required":["date","status"],"properties":{"date":{"examples":["2026-12-31T00:00:00.000Z"],"anyOf":[{"examples":["2026-12-31T00:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"anyOf":[{"const":"pending","type":"string"},{"const":"processed","type":"string"},{"const":"expired","type":"string"}]},"processed":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"reason":{"type":"object","required":["externalId","code","name"],"properties":{"externalId":{"description":"Credit reason external ID.","examples":["rsn1234567890abc"],"type":"string"},"code":{"description":"Credit reason code.","examples":["cleaning-complaint"],"type":"string"},"name":{"description":"Credit reason display name.","examples":["Reklamace úklidu"],"type":"string"}}},"payerBranch":{"description":"Branch that internally bears the cost of this credit movement. Omitted when the organisation absorbs it.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the branch that internally bears this credit cost.","type":"string"},"name":{"description":"Display name of the payer branch.","type":"string"}}},"description":{"examples":["Order 25000087"],"type":"string"},"insertedDate":{"examples":["2026-04-21T10:00:00.000Z"],"anyOf":[{"examples":["2026-04-21T10:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of credit transactions.","examples":[42],"type":"number"}},"required":["credit","creditMoney","currency","items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"credit":{"description":"Current credit balance (number of credits).","examples":[3300],"type":"number"},"creditMoney":{"description":"Current credit balance expressed in the organisation default currency.","examples":[3000],"type":"number"},"currency":{"description":"ISO 4217 code of the organisation default currency used for all *Money fields.","examples":["CZK"],"type":"string"},"items":{"description":"Credit transactions ordered from most recent to oldest.","type":"array","items":{"type":"object","required":["id","amount","amountMoney","balance","balanceMoney","insertedDate"],"properties":{"id":{"description":"Transaction external ID.","examples":["HxanU4a1n4El61zx"],"type":"string"},"amount":{"description":"Credit amount (positive = added, negative = spent).","examples":[3300,-100],"type":"number"},"amountMoney":{"description":"Monetary value of the transaction in the organisation default currency. Defaults to the same value as `amount` (1:1) when no explicit money value was stored.","examples":[3000,-100,0],"type":"number"},"balance":{"description":"Running credit balance after this transaction.","examples":[3300],"type":"number"},"balanceMoney":{"description":"Running monetary balance after this transaction (in the organisation default currency).","examples":[3000],"type":"number"},"order":{"type":"object","required":["orderNumber","hash","groupName"],"properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"groupName":{"examples":["GymRoom Vinohrady"],"type":"string"}}},"expiration":{"type":"object","required":["date","status"],"properties":{"date":{"examples":["2026-12-31T00:00:00.000Z"],"anyOf":[{"examples":["2026-12-31T00:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"anyOf":[{"const":"pending","type":"string"},{"const":"processed","type":"string"},{"const":"expired","type":"string"}]},"processed":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"reason":{"type":"object","required":["externalId","code","name"],"properties":{"externalId":{"description":"Credit reason external ID.","examples":["rsn1234567890abc"],"type":"string"},"code":{"description":"Credit reason code.","examples":["cleaning-complaint"],"type":"string"},"name":{"description":"Credit reason display name.","examples":["Reklamace úklidu"],"type":"string"}}},"payerBranch":{"description":"Branch that internally bears the cost of this credit movement. Omitted when the organisation absorbs it.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the branch that internally bears this credit cost.","type":"string"},"name":{"description":"Display name of the payer branch.","type":"string"}}},"description":{"examples":["Order 25000087"],"type":"string"},"insertedDate":{"examples":["2026-04-21T10:00:00.000Z"],"anyOf":[{"examples":["2026-04-21T10:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of credit transactions.","examples":[42],"type":"number"}},"required":["credit","creditMoney","currency","items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"credit":{"description":"Current credit balance (number of credits).","examples":[3300],"type":"number"},"creditMoney":{"description":"Current credit balance expressed in the organisation default currency.","examples":[3000],"type":"number"},"currency":{"description":"ISO 4217 code of the organisation default currency used for all *Money fields.","examples":["CZK"],"type":"string"},"items":{"description":"Credit transactions ordered from most recent to oldest.","type":"array","items":{"type":"object","required":["id","amount","amountMoney","balance","balanceMoney","insertedDate"],"properties":{"id":{"description":"Transaction external ID.","examples":["HxanU4a1n4El61zx"],"type":"string"},"amount":{"description":"Credit amount (positive = added, negative = spent).","examples":[3300,-100],"type":"number"},"amountMoney":{"description":"Monetary value of the transaction in the organisation default currency. Defaults to the same value as `amount` (1:1) when no explicit money value was stored.","examples":[3000,-100,0],"type":"number"},"balance":{"description":"Running credit balance after this transaction.","examples":[3300],"type":"number"},"balanceMoney":{"description":"Running monetary balance after this transaction (in the organisation default currency).","examples":[3000],"type":"number"},"order":{"type":"object","required":["orderNumber","hash","groupName"],"properties":{"orderNumber":{"examples":["25000087"],"type":"string"},"hash":{"examples":["sSO98YxzR4KJiOu66Jn6K3wRwa4FPI7S"],"type":"string"},"groupName":{"examples":["GymRoom Vinohrady"],"type":"string"}}},"expiration":{"type":"object","required":["date","status"],"properties":{"date":{"examples":["2026-12-31T00:00:00.000Z"],"anyOf":[{"examples":["2026-12-31T00:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"status":{"anyOf":[{"const":"pending","type":"string"},{"const":"processed","type":"string"},{"const":"expired","type":"string"}]},"processed":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}},"reason":{"type":"object","required":["externalId","code","name"],"properties":{"externalId":{"description":"Credit reason external ID.","examples":["rsn1234567890abc"],"type":"string"},"code":{"description":"Credit reason code.","examples":["cleaning-complaint"],"type":"string"},"name":{"description":"Credit reason display name.","examples":["Reklamace úklidu"],"type":"string"}}},"payerBranch":{"description":"Branch that internally bears the cost of this credit movement. Omitted when the organisation absorbs it.","type":"object","required":["slug","name"],"properties":{"slug":{"description":"Slug of the branch that internally bears this credit cost.","type":"string"},"name":{"description":"Display name of the payer branch.","type":"string"}}},"description":{"examples":["Order 25000087"],"type":"string"},"insertedDate":{"examples":["2026-04-21T10:00:00.000Z"],"anyOf":[{"examples":["2026-04-21T10:00:00.000Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of credit transactions.","examples":[42],"type":"number"}},"required":["credit","creditMoney","currency","items","itemCount"]}}}}},"operationId":"getBffContact-creditList","tags":["Contact Credit"],"summary":"Get contact credit history","description":"Returns the current credit balance (both in credits and monetary value) and a list of credit transactions for a contact. The `creditMoney` / `amountMoney` / `balanceMoney` values are in the organisation default currency (`currency`) and are purely bookkeeping — the order payment logic always uses 1 credit = 1 unit of money. Each item may include an optional `reason` selected from the per-organisation credit-reason catalog."}},"/bff/contact-credit/expiration-breakdown":{"get":{"parameters":[{"description":"Contact external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"customerId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Sum of all buckets — matches shop__contact.credit when outstandingDebt is 0.","examples":[36,3677],"type":"number"},"totalAmountMoney":{"description":"Sum of all bucket money values.","examples":[36,3677],"type":"number"},"outstandingDebt":{"description":"Unpaid debt not yet absorbed by a positive credit. > 0 means the customer is in the red.","examples":[0],"default":0,"type":"number"},"currency":{"description":"ISO 4217 code of the organisation default currency used for all *Money fields.","examples":["CZK"],"type":"string"},"buckets":{"description":"Buckets ordered: overdue first, then by date ascending, never-expires last.","type":"array","items":{"type":"object","required":["expirationDate","overdue","amount","amountMoney","sources"],"properties":{"expirationDate":{"description":"Calendar date when the credits in this bucket expire. null = bucket holds credits with no scheduled expiration.","anyOf":[{"description":"YYYY-MM-DD calendar date.","examples":["2026-06-13"],"type":"string"},{"type":"null"}]},"overdue":{"description":"True when the expiration date is in the past but the cron has not yet processed it. The next cron tick will sweep these.","examples":[false],"default":false,"type":"boolean"},"amount":{"description":"Total unspent credits in this bucket.","examples":[36],"type":"number"},"amountMoney":{"description":"Total money value in this bucket (scaled proportionally).","examples":[36],"type":"number"},"sources":{"type":"array","items":{"type":"object","required":["creditId","creditExternalId","originalAmount","amount","amountMoney","expirationAt"],"properties":{"creditId":{"description":"Internal id of the source credit.","examples":[8422],"type":"number"},"creditExternalId":{"description":"External (16-char) id of the source credit — link target for drill-down.","examples":["4L0jcnkzA8SPW1gE"],"type":"string"},"originalAmount":{"description":"Face value of the source credit before any FIFO consumption.","examples":[300],"type":"number"},"amount":{"description":"Unspent portion of the source credit contributed to this bucket.","examples":[36],"type":"number"},"amountMoney":{"description":"Money value scaled proportionally to `amount`.","examples":[36],"type":"number"},"expirationAt":{"description":"Exact expiration timestamp of the source credit. null when the bucket is the never-expires bucket.","anyOf":[{"description":"Exact ISO timestamp of the source credit expiration.","type":"string"},{"type":"null"}]}}}}}}}},"required":["totalAmount","totalAmountMoney","outstandingDebt","currency","buckets"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Sum of all buckets — matches shop__contact.credit when outstandingDebt is 0.","examples":[36,3677],"type":"number"},"totalAmountMoney":{"description":"Sum of all bucket money values.","examples":[36,3677],"type":"number"},"outstandingDebt":{"description":"Unpaid debt not yet absorbed by a positive credit. > 0 means the customer is in the red.","examples":[0],"default":0,"type":"number"},"currency":{"description":"ISO 4217 code of the organisation default currency used for all *Money fields.","examples":["CZK"],"type":"string"},"buckets":{"description":"Buckets ordered: overdue first, then by date ascending, never-expires last.","type":"array","items":{"type":"object","required":["expirationDate","overdue","amount","amountMoney","sources"],"properties":{"expirationDate":{"description":"Calendar date when the credits in this bucket expire. null = bucket holds credits with no scheduled expiration.","anyOf":[{"description":"YYYY-MM-DD calendar date.","examples":["2026-06-13"],"type":"string"},{"type":"null"}]},"overdue":{"description":"True when the expiration date is in the past but the cron has not yet processed it. The next cron tick will sweep these.","examples":[false],"default":false,"type":"boolean"},"amount":{"description":"Total unspent credits in this bucket.","examples":[36],"type":"number"},"amountMoney":{"description":"Total money value in this bucket (scaled proportionally).","examples":[36],"type":"number"},"sources":{"type":"array","items":{"type":"object","required":["creditId","creditExternalId","originalAmount","amount","amountMoney","expirationAt"],"properties":{"creditId":{"description":"Internal id of the source credit.","examples":[8422],"type":"number"},"creditExternalId":{"description":"External (16-char) id of the source credit — link target for drill-down.","examples":["4L0jcnkzA8SPW1gE"],"type":"string"},"originalAmount":{"description":"Face value of the source credit before any FIFO consumption.","examples":[300],"type":"number"},"amount":{"description":"Unspent portion of the source credit contributed to this bucket.","examples":[36],"type":"number"},"amountMoney":{"description":"Money value scaled proportionally to `amount`.","examples":[36],"type":"number"},"expirationAt":{"description":"Exact expiration timestamp of the source credit. null when the bucket is the never-expires bucket.","anyOf":[{"description":"Exact ISO timestamp of the source credit expiration.","type":"string"},{"type":"null"}]}}}}}}}},"required":["totalAmount","totalAmountMoney","outstandingDebt","currency","buckets"]}},"text/plain":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Sum of all buckets — matches shop__contact.credit when outstandingDebt is 0.","examples":[36,3677],"type":"number"},"totalAmountMoney":{"description":"Sum of all bucket money values.","examples":[36,3677],"type":"number"},"outstandingDebt":{"description":"Unpaid debt not yet absorbed by a positive credit. > 0 means the customer is in the red.","examples":[0],"default":0,"type":"number"},"currency":{"description":"ISO 4217 code of the organisation default currency used for all *Money fields.","examples":["CZK"],"type":"string"},"buckets":{"description":"Buckets ordered: overdue first, then by date ascending, never-expires last.","type":"array","items":{"type":"object","required":["expirationDate","overdue","amount","amountMoney","sources"],"properties":{"expirationDate":{"description":"Calendar date when the credits in this bucket expire. null = bucket holds credits with no scheduled expiration.","anyOf":[{"description":"YYYY-MM-DD calendar date.","examples":["2026-06-13"],"type":"string"},{"type":"null"}]},"overdue":{"description":"True when the expiration date is in the past but the cron has not yet processed it. The next cron tick will sweep these.","examples":[false],"default":false,"type":"boolean"},"amount":{"description":"Total unspent credits in this bucket.","examples":[36],"type":"number"},"amountMoney":{"description":"Total money value in this bucket (scaled proportionally).","examples":[36],"type":"number"},"sources":{"type":"array","items":{"type":"object","required":["creditId","creditExternalId","originalAmount","amount","amountMoney","expirationAt"],"properties":{"creditId":{"description":"Internal id of the source credit.","examples":[8422],"type":"number"},"creditExternalId":{"description":"External (16-char) id of the source credit — link target for drill-down.","examples":["4L0jcnkzA8SPW1gE"],"type":"string"},"originalAmount":{"description":"Face value of the source credit before any FIFO consumption.","examples":[300],"type":"number"},"amount":{"description":"Unspent portion of the source credit contributed to this bucket.","examples":[36],"type":"number"},"amountMoney":{"description":"Money value scaled proportionally to `amount`.","examples":[36],"type":"number"},"expirationAt":{"description":"Exact expiration timestamp of the source credit. null when the bucket is the never-expires bucket.","anyOf":[{"description":"Exact ISO timestamp of the source credit expiration.","type":"string"},{"type":"null"}]}}}}}}}},"required":["totalAmount","totalAmountMoney","outstandingDebt","currency","buckets"]}}}}},"operationId":"getBffContact-creditExpiration-breakdown","tags":["Contact Credit"],"summary":"Get a breakdown of a contact's currently open credits grouped by expiration date","description":"Returns the customer's unspent credits sliced into buckets by their expiration date. FIFO-aware: each bucket reports only what is still unspent of the underlying source credit(s), not the original face value. Buckets are ordered: overdue first (past expiration but not yet processed by the cron), then by date ascending, never-expires last. A non-zero `outstandingDebt` reports a negative running balance that has not yet been paid off."}},"/bff/contact-credit/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContact-creditCreate","tags":["Contact Credit"],"summary":"Create credit transaction","description":"Adds a credit transaction to a contact. Optionally tag it with a per-organisation credit reason via `reasonExternalId`, and optionally attribute the internal cost to a branch via `payerBranchSlug` so the credit shows up in that branch's payer-credit ledger in addition to the customer history.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customerId","amount","useExpiration"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"amount":{"description":"Credit amount to add (positive or negative).","examples":[100,-50],"type":"number"},"amountMoney":{"description":"Value in default currency. If omitted, defaults to same as amount (1:1).","examples":[90,-45],"type":"number"},"description":{"description":"Optional free-form note for the transaction.","type":"string"},"useExpiration":{"description":"Whether the credit has an expiration date.","type":"boolean"},"expirationDate":{"description":"Expiration date for the credit (ISO format).","examples":["2026-12-31"],"type":"string"},"reasonExternalId":{"description":"External ID of a configured credit reason (16 chars). Optional label tagging the transaction.","examples":["rsn1234567890abc"],"type":"string"},"payerBranchSlug":{"description":"Slug of the branch that internally bears the cost of this credit. Omit / empty = the organisation absorbs it (default).","examples":["gymroom-plzen"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["customerId","amount","useExpiration"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"amount":{"description":"Credit amount to add (positive or negative).","examples":[100,-50],"type":"number"},"amountMoney":{"description":"Value in default currency. If omitted, defaults to same as amount (1:1).","examples":[90,-45],"type":"number"},"description":{"description":"Optional free-form note for the transaction.","type":"string"},"useExpiration":{"description":"Whether the credit has an expiration date.","type":"boolean"},"expirationDate":{"description":"Expiration date for the credit (ISO format).","examples":["2026-12-31"],"type":"string"},"reasonExternalId":{"description":"External ID of a configured credit reason (16 chars). Optional label tagging the transaction.","examples":["rsn1234567890abc"],"type":"string"},"payerBranchSlug":{"description":"Slug of the branch that internally bears the cost of this credit. Omit / empty = the organisation absorbs it (default).","examples":["gymroom-plzen"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["customerId","amount","useExpiration"],"properties":{"customerId":{"description":"Contact external ID.","type":"string"},"amount":{"description":"Credit amount to add (positive or negative).","examples":[100,-50],"type":"number"},"amountMoney":{"description":"Value in default currency. If omitted, defaults to same as amount (1:1).","examples":[90,-45],"type":"number"},"description":{"description":"Optional free-form note for the transaction.","type":"string"},"useExpiration":{"description":"Whether the credit has an expiration date.","type":"boolean"},"expirationDate":{"description":"Expiration date for the credit (ISO format).","examples":["2026-12-31"],"type":"string"},"reasonExternalId":{"description":"External ID of a configured credit reason (16 chars). Optional label tagging the transaction.","examples":["rsn1234567890abc"],"type":"string"},"payerBranchSlug":{"description":"Slug of the branch that internally bears the cost of this credit. Omit / empty = the organisation absorbs it (default).","examples":["gymroom-plzen"],"type":"string"}}}}}}}},"/bff/contact-credit/reason/list":{"get":{"parameters":[{"description":"Page number (1-based).","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Items per page (default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffContact-creditReasonList","tags":["Contact Credit"],"summary":"List credit reasons","description":"Paginated list of configured credit reasons for the organisation.","responses":{"200":{}}}},"/bff/contact-credit/reason/list-selectbox":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["externalId","code","name","defaultAmount"],"properties":{"externalId":{"description":"Reason external ID (16 chars).","type":"string"},"code":{"description":"Reason code.","type":"string"},"name":{"description":"Display name.","type":"string"},"description":{"description":"Internal note shown in admin to clarify when this reason should be used.","type":"string"},"defaultAmount":{"description":"Preset credit amount.","type":"number"},"defaultAmountMoney":{"description":"Preset monetary value in the organisation default currency. Omitted when not configured — clients should fall back to `defaultAmount` (1:1).","type":"number"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["externalId","code","name","defaultAmount"],"properties":{"externalId":{"description":"Reason external ID (16 chars).","type":"string"},"code":{"description":"Reason code.","type":"string"},"name":{"description":"Display name.","type":"string"},"description":{"description":"Internal note shown in admin to clarify when this reason should be used.","type":"string"},"defaultAmount":{"description":"Preset credit amount.","type":"number"},"defaultAmountMoney":{"description":"Preset monetary value in the organisation default currency. Omitted when not configured — clients should fall back to `defaultAmount` (1:1).","type":"number"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["externalId","code","name","defaultAmount"],"properties":{"externalId":{"description":"Reason external ID (16 chars).","type":"string"},"code":{"description":"Reason code.","type":"string"},"name":{"description":"Display name.","type":"string"},"description":{"description":"Internal note shown in admin to clarify when this reason should be used.","type":"string"},"defaultAmount":{"description":"Preset credit amount.","type":"number"},"defaultAmountMoney":{"description":"Preset monetary value in the organisation default currency. Omitted when not configured — clients should fall back to `defaultAmount` (1:1).","type":"number"}}}}},"required":["items"]}}}}},"operationId":"getBffContact-creditReasonList-selectbox","tags":["Contact Credit"],"summary":"List credit reasons for selectbox","description":"Returns active, non-deleted credit reasons with default amounts so the admin UI can pre-fill the credit form when a reason is selected."}},"/bff/contact-credit/reason/detail":{"get":{"parameters":[{"description":"Credit reason code.","examples":["cleaning-complaint"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"operationId":"getBffContact-creditReasonDetail","tags":["Contact Credit"],"summary":"Get credit reason detail","description":"Returns full detail of a single credit reason by its code.","responses":{"200":{}}}},"/bff/contact-credit/reason/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"externalId":{"description":"Generated external ID (16 chars).","type":"string"},"code":{"description":"Final code assigned to the reason.","type":"string"}},"required":["success","externalId","code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"externalId":{"description":"Generated external ID (16 chars).","type":"string"},"code":{"description":"Final code assigned to the reason.","type":"string"}},"required":["success","externalId","code"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"externalId":{"description":"Generated external ID (16 chars).","type":"string"},"code":{"description":"Final code assigned to the reason.","type":"string"}},"required":["success","externalId","code"]}}}}},"operationId":"postBffContact-creditReasonCreate","tags":["Contact Credit"],"summary":"Create credit reason","description":"Creates a new credit reason for the organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","defaultAmount"],"properties":{"name":{"description":"Display name.","examples":["Reklamace úklidu"],"type":"string"},"code":{"description":"Unique code (slug-like). Auto-generated from name when omitted.","examples":["cleaning-complaint"],"type":"string"},"description":{"description":"Internal description shown in admin.","type":"string"},"defaultAmount":{"description":"Default credit amount when this reason is selected.","examples":[50],"type":"number"},"defaultAmountMoney":{"description":"Default monetary value in the organisation default currency. Omit to inherit from `defaultAmount` (1:1).","examples":[50],"type":"number"},"active":{"description":"Whether the reason is selectable. Defaults to true.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name","defaultAmount"],"properties":{"name":{"description":"Display name.","examples":["Reklamace úklidu"],"type":"string"},"code":{"description":"Unique code (slug-like). Auto-generated from name when omitted.","examples":["cleaning-complaint"],"type":"string"},"description":{"description":"Internal description shown in admin.","type":"string"},"defaultAmount":{"description":"Default credit amount when this reason is selected.","examples":[50],"type":"number"},"defaultAmountMoney":{"description":"Default monetary value in the organisation default currency. Omit to inherit from `defaultAmount` (1:1).","examples":[50],"type":"number"},"active":{"description":"Whether the reason is selectable. Defaults to true.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["name","defaultAmount"],"properties":{"name":{"description":"Display name.","examples":["Reklamace úklidu"],"type":"string"},"code":{"description":"Unique code (slug-like). Auto-generated from name when omitted.","examples":["cleaning-complaint"],"type":"string"},"description":{"description":"Internal description shown in admin.","type":"string"},"defaultAmount":{"description":"Default credit amount when this reason is selected.","examples":[50],"type":"number"},"defaultAmountMoney":{"description":"Default monetary value in the organisation default currency. Omit to inherit from `defaultAmount` (1:1).","examples":[50],"type":"number"},"active":{"description":"Whether the reason is selectable. Defaults to true.","type":"boolean"}}}}}}}},"/bff/contact-credit/reason/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContact-creditReasonUpdate","tags":["Contact Credit"],"summary":"Update credit reason","description":"Patches an existing credit reason. Only provided fields are changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code identifying the reason to update.","type":"string"},"name":{"description":"New display name.","type":"string"},"description":{"description":"New description.","type":"string"},"defaultAmount":{"description":"New default credit amount.","type":"number"},"defaultAmountMoney":{"nullable":true,"anyOf":[{"description":"New default monetary value. Pass null to clear and inherit from `defaultAmount`.","type":"number"},{"type":"null"}]},"position":{"description":"New ordering position.","type":"number"},"active":{"description":"Whether the reason is active.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code identifying the reason to update.","type":"string"},"name":{"description":"New display name.","type":"string"},"description":{"description":"New description.","type":"string"},"defaultAmount":{"description":"New default credit amount.","type":"number"},"defaultAmountMoney":{"nullable":true,"anyOf":[{"description":"New default monetary value. Pass null to clear and inherit from `defaultAmount`.","type":"number"},{"type":"null"}]},"position":{"description":"New ordering position.","type":"number"},"active":{"description":"Whether the reason is active.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code identifying the reason to update.","type":"string"},"name":{"description":"New display name.","type":"string"},"description":{"description":"New description.","type":"string"},"defaultAmount":{"description":"New default credit amount.","type":"number"},"defaultAmountMoney":{"nullable":true,"anyOf":[{"description":"New default monetary value. Pass null to clear and inherit from `defaultAmount`.","type":"number"},{"type":"null"}]},"position":{"description":"New ordering position.","type":"number"},"active":{"description":"Whether the reason is active.","type":"boolean"}}}}}}}},"/bff/contact-credit/reason/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContact-creditReasonDelete","tags":["Contact Credit"],"summary":"Soft-delete credit reason","description":"Marks a credit reason as deleted. Existing transaction links remain valid; the reason no longer appears in selectbox or list endpoints.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code identifying the reason to soft-delete.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code identifying the reason to soft-delete.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code identifying the reason to soft-delete.","type":"string"}}}}}}}},"/bff/contact-credit/credit-by-payer-branch":{"get":{"parameters":[{"description":"Branch slug.","examples":["gymroom-plzen"],"schema":{"type":"string"},"in":"query","name":"branchSlug","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"branchId":{"description":"Branch internal id as string.","type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"currency":{"description":"ISO 4217 code of the organisation default currency.","type":"string"},"totalAmount":{"description":"Signed sum of credit counts.","type":"number"},"totalAmountMoney":{"description":"Signed sum of monetary values in the org currency.","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","amount","amountMoney","customer","insertedDate"],"properties":{"id":{"description":"Credit transaction external ID.","type":"string"},"amount":{"type":"number"},"amountMoney":{"type":"number"},"customer":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"Customer external ID (CuRefNo).","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"}}},"order":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"}}},"reason":{"type":"object","required":["externalId","code","name"],"properties":{"externalId":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"}}},"description":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["branchId","branchSlug","branchName","currency","totalAmount","totalAmountMoney","items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"branchId":{"description":"Branch internal id as string.","type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"currency":{"description":"ISO 4217 code of the organisation default currency.","type":"string"},"totalAmount":{"description":"Signed sum of credit counts.","type":"number"},"totalAmountMoney":{"description":"Signed sum of monetary values in the org currency.","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","amount","amountMoney","customer","insertedDate"],"properties":{"id":{"description":"Credit transaction external ID.","type":"string"},"amount":{"type":"number"},"amountMoney":{"type":"number"},"customer":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"Customer external ID (CuRefNo).","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"}}},"order":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"}}},"reason":{"type":"object","required":["externalId","code","name"],"properties":{"externalId":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"}}},"description":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["branchId","branchSlug","branchName","currency","totalAmount","totalAmountMoney","items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"branchId":{"description":"Branch internal id as string.","type":"string"},"branchSlug":{"type":"string"},"branchName":{"type":"string"},"currency":{"description":"ISO 4217 code of the organisation default currency.","type":"string"},"totalAmount":{"description":"Signed sum of credit counts.","type":"number"},"totalAmountMoney":{"description":"Signed sum of monetary values in the org currency.","type":"number"},"items":{"type":"array","items":{"type":"object","required":["id","amount","amountMoney","customer","insertedDate"],"properties":{"id":{"description":"Credit transaction external ID.","type":"string"},"amount":{"type":"number"},"amountMoney":{"type":"number"},"customer":{"type":"object","required":["contactId"],"properties":{"contactId":{"description":"Customer external ID (CuRefNo).","type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"companyName":{"type":"string"}}},"order":{"type":"object","required":["orderNumber","hash"],"properties":{"orderNumber":{"type":"string"},"hash":{"type":"string"}}},"reason":{"type":"object","required":["externalId","code","name"],"properties":{"externalId":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"}}},"description":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["branchId","branchSlug","branchName","currency","totalAmount","totalAmountMoney","items","itemCount"]}}}}},"operationId":"getBffContact-creditCredit-by-payer-branch","tags":["Contact Credit"],"summary":"List credit transactions paid by branch","description":"Returns credit transactions whose `payer_branch_id` resolves to the requested branch — i.e. credits the operator attributed to this branch as the internal payer. Ordered by inserted date desc. `totalAmount` is the signed sum of credit counts; `totalAmountMoney` is the signed sum in the organisation default currency."}},"/bff/currency/list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"All currencies, org default first, then alphabetical.","type":"array","items":{"type":"object","required":["code","name","symbol","decimals","numericCode","rateLock","rate","rateDate","hops"],"properties":{"code":{"description":"ISO 4217 alphabetic code.","examples":["EUR"],"type":"string"},"name":{"nullable":true,"anyOf":[{"description":"English display name.","examples":["Euro"],"type":"string"},{"type":"null"}]},"symbol":{"description":"Native symbol or ISO code as fallback.","examples":["€","Kč"],"type":"string"},"decimals":{"description":"ISO 4217 fractional digits (JPY/HUF/KRW=0, BHD=3, others 2).","examples":[2,0],"type":"number"},"numericCode":{"nullable":true,"anyOf":[{"description":"ISO 4217 numeric code (3 chars), null if unknown.","examples":["978"],"type":"string"},{"type":"null"}]},"rateLock":{"description":"When true, the daily multi-source sync skips this currency on either side of the pair (manual override wins).","default":false,"type":"boolean"},"rate":{"nullable":true,"anyOf":[{"description":"Latest available rate: how many units of the org default currency 1 unit of `code` is worth. Null when no rate is reachable in the graph within the lookback window.","examples":[24.355,1,null],"type":"number"},{"type":"null"}]},"rateDate":{"nullable":true,"anyOf":[{"description":"YYYY-MM-DD of the oldest fixing in the resolution path. Null when `rate` is null.","examples":["2026-04-28"],"type":"string"},{"type":"null"}]},"hops":{"nullable":true,"anyOf":[{"description":"Number of pivot hops to reach the rate (0 = direct quote / identity, 1+ = via cross-rate path).","examples":[0,1,2],"type":"number"},{"type":"null"}]}}}},"itemCount":{"examples":[158],"type":"number"},"defaultCurrencyCode":{"description":"ISO code of the organisation default currency.","examples":["CZK"],"type":"string"}},"required":["items","itemCount","defaultCurrencyCode"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"All currencies, org default first, then alphabetical.","type":"array","items":{"type":"object","required":["code","name","symbol","decimals","numericCode","rateLock","rate","rateDate","hops"],"properties":{"code":{"description":"ISO 4217 alphabetic code.","examples":["EUR"],"type":"string"},"name":{"nullable":true,"anyOf":[{"description":"English display name.","examples":["Euro"],"type":"string"},{"type":"null"}]},"symbol":{"description":"Native symbol or ISO code as fallback.","examples":["€","Kč"],"type":"string"},"decimals":{"description":"ISO 4217 fractional digits (JPY/HUF/KRW=0, BHD=3, others 2).","examples":[2,0],"type":"number"},"numericCode":{"nullable":true,"anyOf":[{"description":"ISO 4217 numeric code (3 chars), null if unknown.","examples":["978"],"type":"string"},{"type":"null"}]},"rateLock":{"description":"When true, the daily multi-source sync skips this currency on either side of the pair (manual override wins).","default":false,"type":"boolean"},"rate":{"nullable":true,"anyOf":[{"description":"Latest available rate: how many units of the org default currency 1 unit of `code` is worth. Null when no rate is reachable in the graph within the lookback window.","examples":[24.355,1,null],"type":"number"},{"type":"null"}]},"rateDate":{"nullable":true,"anyOf":[{"description":"YYYY-MM-DD of the oldest fixing in the resolution path. Null when `rate` is null.","examples":["2026-04-28"],"type":"string"},{"type":"null"}]},"hops":{"nullable":true,"anyOf":[{"description":"Number of pivot hops to reach the rate (0 = direct quote / identity, 1+ = via cross-rate path).","examples":[0,1,2],"type":"number"},{"type":"null"}]}}}},"itemCount":{"examples":[158],"type":"number"},"defaultCurrencyCode":{"description":"ISO code of the organisation default currency.","examples":["CZK"],"type":"string"}},"required":["items","itemCount","defaultCurrencyCode"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"All currencies, org default first, then alphabetical.","type":"array","items":{"type":"object","required":["code","name","symbol","decimals","numericCode","rateLock","rate","rateDate","hops"],"properties":{"code":{"description":"ISO 4217 alphabetic code.","examples":["EUR"],"type":"string"},"name":{"nullable":true,"anyOf":[{"description":"English display name.","examples":["Euro"],"type":"string"},{"type":"null"}]},"symbol":{"description":"Native symbol or ISO code as fallback.","examples":["€","Kč"],"type":"string"},"decimals":{"description":"ISO 4217 fractional digits (JPY/HUF/KRW=0, BHD=3, others 2).","examples":[2,0],"type":"number"},"numericCode":{"nullable":true,"anyOf":[{"description":"ISO 4217 numeric code (3 chars), null if unknown.","examples":["978"],"type":"string"},{"type":"null"}]},"rateLock":{"description":"When true, the daily multi-source sync skips this currency on either side of the pair (manual override wins).","default":false,"type":"boolean"},"rate":{"nullable":true,"anyOf":[{"description":"Latest available rate: how many units of the org default currency 1 unit of `code` is worth. Null when no rate is reachable in the graph within the lookback window.","examples":[24.355,1,null],"type":"number"},{"type":"null"}]},"rateDate":{"nullable":true,"anyOf":[{"description":"YYYY-MM-DD of the oldest fixing in the resolution path. Null when `rate` is null.","examples":["2026-04-28"],"type":"string"},{"type":"null"}]},"hops":{"nullable":true,"anyOf":[{"description":"Number of pivot hops to reach the rate (0 = direct quote / identity, 1+ = via cross-rate path).","examples":[0,1,2],"type":"number"},{"type":"null"}]}}}},"itemCount":{"examples":[158],"type":"number"},"defaultCurrencyCode":{"description":"ISO code of the organisation default currency.","examples":["CZK"],"type":"string"}},"required":["items","itemCount","defaultCurrencyCode"]}}}}},"operationId":"getBffCurrencyList","tags":["Currency"],"summary":"List all currencies (with latest rate against org default)","description":"Returns the full currency master with metadata (name, symbol, decimals, ISO 4217 numeric code, rate-lock flag) plus the latest rate against the organisation default currency: `rate` (units of base per 1 unit of code), `rateDate` (the oldest fixing in the resolution path), and `hops` (0 = direct quote / identity, 1+ = via pivot). Sort: org default first, then alphabetical by ISO code."}},"/bff/currency/rate-sheet":{"get":{"parameters":[{"description":"Target date in YYYY-MM-DD. Defaults to today. The actual fixing returned (`fixingDate`) may be earlier when the requested date is a weekend, holiday, or before the daily CNB publication.","examples":["2026-04-27"],"schema":{"type":"string"},"in":"query","name":"date","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"baseCode":{"description":"Base (org default) currency code.","examples":["EUR"],"type":"string"},"baseName":{"nullable":true,"anyOf":[{"examples":["Euro"],"type":"string"},{"type":"null"}]},"baseSymbol":{"examples":["€"],"type":"string"},"fixingDate":{"description":"Latest fixing date represented in the sheet.","examples":["2026-04-27"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["code","name","symbol","decimals","rate","hops","rateDate"],"properties":{"code":{"examples":["USD"],"type":"string"},"name":{"nullable":true,"anyOf":[{"examples":["US Dollar"],"type":"string"},{"type":"null"}]},"symbol":{"examples":["$"],"type":"string"},"decimals":{"examples":[2],"type":"number"},"rate":{"description":"How many units of the base currency 1 unit of `code` is worth on the fixing date.","examples":[0.85],"type":"number"},"hops":{"description":"Number of pivot currencies traversed to reach `code` (0 = direct quote, 1+ = via cross-rate path).","examples":[0,1,2],"type":"number"},"rateDate":{"description":"YYYY-MM-DD of the oldest fixing in the resolution path (the rate is only as fresh as this).","examples":["2026-04-27"],"type":"string"}}}},"itemCount":{"examples":[120],"type":"number"}},"required":["baseCode","baseName","baseSymbol","fixingDate","items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"baseCode":{"description":"Base (org default) currency code.","examples":["EUR"],"type":"string"},"baseName":{"nullable":true,"anyOf":[{"examples":["Euro"],"type":"string"},{"type":"null"}]},"baseSymbol":{"examples":["€"],"type":"string"},"fixingDate":{"description":"Latest fixing date represented in the sheet.","examples":["2026-04-27"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["code","name","symbol","decimals","rate","hops","rateDate"],"properties":{"code":{"examples":["USD"],"type":"string"},"name":{"nullable":true,"anyOf":[{"examples":["US Dollar"],"type":"string"},{"type":"null"}]},"symbol":{"examples":["$"],"type":"string"},"decimals":{"examples":[2],"type":"number"},"rate":{"description":"How many units of the base currency 1 unit of `code` is worth on the fixing date.","examples":[0.85],"type":"number"},"hops":{"description":"Number of pivot currencies traversed to reach `code` (0 = direct quote, 1+ = via cross-rate path).","examples":[0,1,2],"type":"number"},"rateDate":{"description":"YYYY-MM-DD of the oldest fixing in the resolution path (the rate is only as fresh as this).","examples":["2026-04-27"],"type":"string"}}}},"itemCount":{"examples":[120],"type":"number"}},"required":["baseCode","baseName","baseSymbol","fixingDate","items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"baseCode":{"description":"Base (org default) currency code.","examples":["EUR"],"type":"string"},"baseName":{"nullable":true,"anyOf":[{"examples":["Euro"],"type":"string"},{"type":"null"}]},"baseSymbol":{"examples":["€"],"type":"string"},"fixingDate":{"description":"Latest fixing date represented in the sheet.","examples":["2026-04-27"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["code","name","symbol","decimals","rate","hops","rateDate"],"properties":{"code":{"examples":["USD"],"type":"string"},"name":{"nullable":true,"anyOf":[{"examples":["US Dollar"],"type":"string"},{"type":"null"}]},"symbol":{"examples":["$"],"type":"string"},"decimals":{"examples":[2],"type":"number"},"rate":{"description":"How many units of the base currency 1 unit of `code` is worth on the fixing date.","examples":[0.85],"type":"number"},"hops":{"description":"Number of pivot currencies traversed to reach `code` (0 = direct quote, 1+ = via cross-rate path).","examples":[0,1,2],"type":"number"},"rateDate":{"description":"YYYY-MM-DD of the oldest fixing in the resolution path (the rate is only as fresh as this).","examples":["2026-04-27"],"type":"string"}}}},"itemCount":{"examples":[120],"type":"number"}},"required":["baseCode","baseName","baseSymbol","fixingDate","items","itemCount"]}}}}},"operationId":"getBffCurrencyRate-sheet","tags":["Currency"],"summary":"Get rate sheet (in org default currency)","description":"Daily rate sheet re-expressed in the organisation default currency. Combines fixings from CNB, ECB, and Fawaz Ahmed Currency API; pairs without a direct quote are resolved via cross-rate paths through pivot currencies (CZK / EUR / USD). Each `rate` says how many units of the base currency one unit of `code` is worth."}},"/bff/currency/rate-history":{"get":{"parameters":[{"description":"ISO 4217 code to chart.","examples":["USD"],"schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"Window length in calendar days (default 30, max 1825 = 5 years).","examples":["30","90","365"],"schema":{"type":"string"},"in":"query","name":"days","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"examples":["USD"],"type":"string"},"baseCode":{"examples":["EUR"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["date","rate"],"properties":{"date":{"description":"YYYY-MM-DD of the CNB fixing.","examples":["2026-04-27"],"type":"string"},"rate":{"description":"Units of base currency per 1 unit of code on this date.","examples":[24.355],"type":"number"}}}},"itemCount":{"examples":[22],"type":"number"}},"required":["code","baseCode","items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"code":{"examples":["USD"],"type":"string"},"baseCode":{"examples":["EUR"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["date","rate"],"properties":{"date":{"description":"YYYY-MM-DD of the CNB fixing.","examples":["2026-04-27"],"type":"string"},"rate":{"description":"Units of base currency per 1 unit of code on this date.","examples":[24.355],"type":"number"}}}},"itemCount":{"examples":[22],"type":"number"}},"required":["code","baseCode","items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"code":{"examples":["USD"],"type":"string"},"baseCode":{"examples":["EUR"],"type":"string"},"items":{"type":"array","items":{"type":"object","required":["date","rate"],"properties":{"date":{"description":"YYYY-MM-DD of the CNB fixing.","examples":["2026-04-27"],"type":"string"},"rate":{"description":"Units of base currency per 1 unit of code on this date.","examples":[24.355],"type":"number"}}}},"itemCount":{"examples":[22],"type":"number"}},"required":["code","baseCode","items","itemCount"]}}}}},"operationId":"getBffCurrencyRate-history","tags":["Currency"],"summary":"Get rate history (in org default currency)","description":"Daily middle-rate time series for a single currency over the last N days, expressed in the organisation default currency. Each point is resolved through the cross-rate graph, so currencies covered only by Fawaz (e.g., AED, SAR, EGP) work too. Returns one point per business day."}},"/bff/currency/convert":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"description":"Converted amount, rounded to target decimals.","examples":[2435.5],"type":"number"},"rate":{"description":"Effective from→to rate.","examples":[24.355],"type":"number"},"rateDate":{"description":"YYYY-MM-DD of the oldest fixing in the resolution path (rate is only as fresh as this).","examples":["2026-04-27"],"type":"string"}},"required":["amount","rate","rateDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"amount":{"description":"Converted amount, rounded to target decimals.","examples":[2435.5],"type":"number"},"rate":{"description":"Effective from→to rate.","examples":[24.355],"type":"number"},"rateDate":{"description":"YYYY-MM-DD of the oldest fixing in the resolution path (rate is only as fresh as this).","examples":["2026-04-27"],"type":"string"}},"required":["amount","rate","rateDate"]}},"text/plain":{"schema":{"type":"object","properties":{"amount":{"description":"Converted amount, rounded to target decimals.","examples":[2435.5],"type":"number"},"rate":{"description":"Effective from→to rate.","examples":[24.355],"type":"number"},"rateDate":{"description":"YYYY-MM-DD of the oldest fixing in the resolution path (rate is only as fresh as this).","examples":["2026-04-27"],"type":"string"}},"required":["amount","rate","rateDate"]}}}}},"operationId":"postBffCurrencyConvert","tags":["Currency"],"summary":"Convert between currencies","description":"Utility for forms: converts `amount` from `from` to `to` using the cross-rate resolver (CNB / ECB / Fawaz combined; pivots through CZK / EUR / USD when no direct quote exists). Result is rounded to the target currency ISO 4217 decimals.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount","from","to"],"properties":{"amount":{"description":"Amount in the source currency.","examples":[100],"type":"number"},"from":{"description":"Source ISO 4217 code.","examples":["EUR"],"type":"string"},"to":{"description":"Target ISO 4217 code.","examples":["CZK"],"type":"string"},"date":{"description":"Conversion date in YYYY-MM-DD. Defaults to today. Falls back to the most recent earlier fixing.","examples":["2026-04-27"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["amount","from","to"],"properties":{"amount":{"description":"Amount in the source currency.","examples":[100],"type":"number"},"from":{"description":"Source ISO 4217 code.","examples":["EUR"],"type":"string"},"to":{"description":"Target ISO 4217 code.","examples":["CZK"],"type":"string"},"date":{"description":"Conversion date in YYYY-MM-DD. Defaults to today. Falls back to the most recent earlier fixing.","examples":["2026-04-27"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["amount","from","to"],"properties":{"amount":{"description":"Amount in the source currency.","examples":[100],"type":"number"},"from":{"description":"Source ISO 4217 code.","examples":["EUR"],"type":"string"},"to":{"description":"Target ISO 4217 code.","examples":["CZK"],"type":"string"},"date":{"description":"Conversion date in YYYY-MM-DD. Defaults to today. Falls back to the most recent earlier fixing.","examples":["2026-04-27"],"type":"string"}}}}}}}},"/bff/contract/list":{"get":{"parameters":[{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"schema":{"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"in":"query","name":"status","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","title","status","partyCount","hasPdf","validFrom","validTo","insertedDate","updatedDate"],"properties":{"id":{"description":"Contract external ID.","type":"string"},"internalId":{"description":"Contract internal ID.","type":"number"},"title":{"description":"Contract title.","type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"partyCount":{"description":"Number of contract parties.","type":"number"},"hasPdf":{"description":"Whether the contract has a finalized PDF.","type":"boolean"},"validFrom":{"nullable":true,"anyOf":[{"description":"Contract validity start.","anyOf":[{"description":"Contract validity start.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"Contract validity end.","anyOf":[{"description":"Contract validity end.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total matching contracts.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","title","status","partyCount","hasPdf","validFrom","validTo","insertedDate","updatedDate"],"properties":{"id":{"description":"Contract external ID.","type":"string"},"internalId":{"description":"Contract internal ID.","type":"number"},"title":{"description":"Contract title.","type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"partyCount":{"description":"Number of contract parties.","type":"number"},"hasPdf":{"description":"Whether the contract has a finalized PDF.","type":"boolean"},"validFrom":{"nullable":true,"anyOf":[{"description":"Contract validity start.","anyOf":[{"description":"Contract validity start.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"Contract validity end.","anyOf":[{"description":"Contract validity end.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total matching contracts.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","title","status","partyCount","hasPdf","validFrom","validTo","insertedDate","updatedDate"],"properties":{"id":{"description":"Contract external ID.","type":"string"},"internalId":{"description":"Contract internal ID.","type":"number"},"title":{"description":"Contract title.","type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"partyCount":{"description":"Number of contract parties.","type":"number"},"hasPdf":{"description":"Whether the contract has a finalized PDF.","type":"boolean"},"validFrom":{"nullable":true,"anyOf":[{"description":"Contract validity start.","anyOf":[{"description":"Contract validity start.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"Contract validity end.","anyOf":[{"description":"Contract validity end.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total matching contracts.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffContractList","tags":["Contract"],"summary":"List contracts","description":"Returns a paginated list of contracts for the authenticated organisation. Supports filtering by status and full-text search by title."}},"/bff/contract/detail":{"get":{"parameters":[{"description":"Contract external ID.","examples":["ctr_abc123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Contract external ID.","type":"string"},"internalId":{"description":"Contract internal ID.","type":"number"},"title":{"description":"Contract title.","type":"string"},"content":{"description":"Contract body in Markdown format.","type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"locale":{"description":"Locale code of the contract (cs, en, de, ...).","examples":["cs","en"],"type":"string"},"validFrom":{"nullable":true,"anyOf":[{"description":"Validity start.","anyOf":[{"description":"Validity start.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"Validity end.","anyOf":[{"description":"Validity end.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"signedDate":{"nullable":true,"anyOf":[{"description":"Date when the contract was signed.","anyOf":[{"description":"Date when the contract was signed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"hasPdf":{"description":"Whether a finalized PDF exists in blob storage.","type":"boolean"},"templateId":{"nullable":true,"anyOf":[{"description":"ID of the template used to create this contract.","type":"number"},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"parties":{"description":"List of contract parties (signatories).","type":"array","items":{"type":"object","required":["contactId","contactExternalId","role","name","email","companyName"],"properties":{"contactId":{"description":"Internal contact ID.","examples":[42],"type":"number"},"contactExternalId":{"description":"Public contact external ID.","examples":["cnt_abc123"],"type":"string"},"role":{"description":"Party role in the contract (issuer, party).","examples":["party","issuer"],"type":"string"},"name":{"description":"Full name or email as fallback.","examples":["Jan Novak"],"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Party e-mail. `null` for phone-only contacts and anonymised contacts. Contracts with a `null` issuer e-mail cannot be sent for e-signature via e-mail link; UI should warn before letting the user trigger that flow.","examples":["jan@example.com"],"type":"string"},{"type":"null"}]},"companyName":{"nullable":true,"anyOf":[{"description":"Company name if the contact is a legal entity.","examples":["Acme s.r.o."],"type":"string"},{"type":"null"}]}}}}},"required":["id","internalId","title","content","status","locale","validFrom","validTo","signedDate","hasPdf","templateId","insertedDate","updatedDate","parties"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Contract external ID.","type":"string"},"internalId":{"description":"Contract internal ID.","type":"number"},"title":{"description":"Contract title.","type":"string"},"content":{"description":"Contract body in Markdown format.","type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"locale":{"description":"Locale code of the contract (cs, en, de, ...).","examples":["cs","en"],"type":"string"},"validFrom":{"nullable":true,"anyOf":[{"description":"Validity start.","anyOf":[{"description":"Validity start.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"Validity end.","anyOf":[{"description":"Validity end.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"signedDate":{"nullable":true,"anyOf":[{"description":"Date when the contract was signed.","anyOf":[{"description":"Date when the contract was signed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"hasPdf":{"description":"Whether a finalized PDF exists in blob storage.","type":"boolean"},"templateId":{"nullable":true,"anyOf":[{"description":"ID of the template used to create this contract.","type":"number"},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"parties":{"description":"List of contract parties (signatories).","type":"array","items":{"type":"object","required":["contactId","contactExternalId","role","name","email","companyName"],"properties":{"contactId":{"description":"Internal contact ID.","examples":[42],"type":"number"},"contactExternalId":{"description":"Public contact external ID.","examples":["cnt_abc123"],"type":"string"},"role":{"description":"Party role in the contract (issuer, party).","examples":["party","issuer"],"type":"string"},"name":{"description":"Full name or email as fallback.","examples":["Jan Novak"],"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Party e-mail. `null` for phone-only contacts and anonymised contacts. Contracts with a `null` issuer e-mail cannot be sent for e-signature via e-mail link; UI should warn before letting the user trigger that flow.","examples":["jan@example.com"],"type":"string"},{"type":"null"}]},"companyName":{"nullable":true,"anyOf":[{"description":"Company name if the contact is a legal entity.","examples":["Acme s.r.o."],"type":"string"},{"type":"null"}]}}}}},"required":["id","internalId","title","content","status","locale","validFrom","validTo","signedDate","hasPdf","templateId","insertedDate","updatedDate","parties"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Contract external ID.","type":"string"},"internalId":{"description":"Contract internal ID.","type":"number"},"title":{"description":"Contract title.","type":"string"},"content":{"description":"Contract body in Markdown format.","type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"locale":{"description":"Locale code of the contract (cs, en, de, ...).","examples":["cs","en"],"type":"string"},"validFrom":{"nullable":true,"anyOf":[{"description":"Validity start.","anyOf":[{"description":"Validity start.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"nullable":true,"anyOf":[{"description":"Validity end.","anyOf":[{"description":"Validity end.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"signedDate":{"nullable":true,"anyOf":[{"description":"Date when the contract was signed.","anyOf":[{"description":"Date when the contract was signed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"hasPdf":{"description":"Whether a finalized PDF exists in blob storage.","type":"boolean"},"templateId":{"nullable":true,"anyOf":[{"description":"ID of the template used to create this contract.","type":"number"},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"parties":{"description":"List of contract parties (signatories).","type":"array","items":{"type":"object","required":["contactId","contactExternalId","role","name","email","companyName"],"properties":{"contactId":{"description":"Internal contact ID.","examples":[42],"type":"number"},"contactExternalId":{"description":"Public contact external ID.","examples":["cnt_abc123"],"type":"string"},"role":{"description":"Party role in the contract (issuer, party).","examples":["party","issuer"],"type":"string"},"name":{"description":"Full name or email as fallback.","examples":["Jan Novak"],"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Party e-mail. `null` for phone-only contacts and anonymised contacts. Contracts with a `null` issuer e-mail cannot be sent for e-signature via e-mail link; UI should warn before letting the user trigger that flow.","examples":["jan@example.com"],"type":"string"},{"type":"null"}]},"companyName":{"nullable":true,"anyOf":[{"description":"Company name if the contact is a legal entity.","examples":["Acme s.r.o."],"type":"string"},{"type":"null"}]}}}}},"required":["id","internalId","title","content","status","locale","validFrom","validTo","signedDate","hasPdf","templateId","insertedDate","updatedDate","parties"]}}}}},"operationId":"getBffContractDetail","tags":["Contract"],"summary":"Get contract detail","description":"Returns full contract detail including markdown content, status, validity dates, and all contract parties with their roles."}},"/bff/contract/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was created successfully.","type":"boolean"},"id":{"description":"External ID of the created contract.","examples":["ctr_abc123"],"type":"string"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was created successfully.","type":"boolean"},"id":{"description":"External ID of the created contract.","examples":["ctr_abc123"],"type":"string"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was created successfully.","type":"boolean"},"id":{"description":"External ID of the created contract.","examples":["ctr_abc123"],"type":"string"}},"required":["success","id"]}}}}},"operationId":"postBffContractCreate","tags":["Contract"],"summary":"Create contract","description":"Creates a new contract in draft status. The organisation internal contact is automatically added as the issuer party. Additional contacts provided via contactIds are added as regular parties.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content","locale"],"properties":{"title":{"minLength":1,"description":"Contract title.","examples":["Service Agreement 2026"],"type":"string"},"content":{"description":"Contract body in Markdown format.","examples":["# Service Agreement\n\nThis contract..."],"type":"string"},"locale":{"description":"Locale code for the contract language.","examples":["cs","en","de"],"type":"string"},"contactIds":{"description":"Internal IDs of contacts to add as contract parties. The organisation contact is always added automatically as issuer.","examples":[[1,2,3]],"type":"array","items":{"examples":[1],"type":"number"}},"templateId":{"description":"Template ID if the contract was created from a template.","examples":[5],"type":"number"},"validFrom":{"description":"Validity start (ISO timestamp).","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"Validity end (ISO timestamp).","examples":["2027-01-01T00:00:00.000Z"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["title","content","locale"],"properties":{"title":{"minLength":1,"description":"Contract title.","examples":["Service Agreement 2026"],"type":"string"},"content":{"description":"Contract body in Markdown format.","examples":["# Service Agreement\n\nThis contract..."],"type":"string"},"locale":{"description":"Locale code for the contract language.","examples":["cs","en","de"],"type":"string"},"contactIds":{"description":"Internal IDs of contacts to add as contract parties. The organisation contact is always added automatically as issuer.","examples":[[1,2,3]],"type":"array","items":{"examples":[1],"type":"number"}},"templateId":{"description":"Template ID if the contract was created from a template.","examples":[5],"type":"number"},"validFrom":{"description":"Validity start (ISO timestamp).","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"Validity end (ISO timestamp).","examples":["2027-01-01T00:00:00.000Z"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["title","content","locale"],"properties":{"title":{"minLength":1,"description":"Contract title.","examples":["Service Agreement 2026"],"type":"string"},"content":{"description":"Contract body in Markdown format.","examples":["# Service Agreement\n\nThis contract..."],"type":"string"},"locale":{"description":"Locale code for the contract language.","examples":["cs","en","de"],"type":"string"},"contactIds":{"description":"Internal IDs of contacts to add as contract parties. The organisation contact is always added automatically as issuer.","examples":[[1,2,3]],"type":"array","items":{"examples":[1],"type":"number"}},"templateId":{"description":"Template ID if the contract was created from a template.","examples":[5],"type":"number"},"validFrom":{"description":"Validity start (ISO timestamp).","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"Validity end (ISO timestamp).","examples":["2027-01-01T00:00:00.000Z"],"type":"string"}}}}}}}},"/bff/contract/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was updated successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was updated successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was updated successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContractUpdate","tags":["Contract"],"summary":"Update contract","description":"Updates contract fields. Only provided fields are changed. Cannot update a finalized (PDF-generated) contract.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contractId"],"properties":{"contractId":{"description":"Internal contract ID to update.","examples":[10],"type":"number"},"title":{"minLength":1,"description":"New contract title.","examples":["Updated Agreement"],"type":"string"},"content":{"description":"New contract body in Markdown format.","examples":["# Updated content"],"type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"validFrom":{"description":"New validity start (ISO timestamp).","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"New validity end (ISO timestamp).","examples":["2027-01-01T00:00:00.000Z"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["contractId"],"properties":{"contractId":{"description":"Internal contract ID to update.","examples":[10],"type":"number"},"title":{"minLength":1,"description":"New contract title.","examples":["Updated Agreement"],"type":"string"},"content":{"description":"New contract body in Markdown format.","examples":["# Updated content"],"type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"validFrom":{"description":"New validity start (ISO timestamp).","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"New validity end (ISO timestamp).","examples":["2027-01-01T00:00:00.000Z"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["contractId"],"properties":{"contractId":{"description":"Internal contract ID to update.","examples":[10],"type":"number"},"title":{"minLength":1,"description":"New contract title.","examples":["Updated Agreement"],"type":"string"},"content":{"description":"New contract body in Markdown format.","examples":["# Updated content"],"type":"string"},"status":{"description":"Contract lifecycle status.","examples":["draft","active","signed"],"anyOf":[{"const":"draft","type":"string"},{"const":"pending_review","type":"string"},{"const":"approved","type":"string"},{"const":"signed","type":"string"},{"const":"active","type":"string"},{"const":"expired","type":"string"},{"const":"cancelled","type":"string"},{"const":"archived","type":"string"}]},"validFrom":{"description":"New validity start (ISO timestamp).","examples":["2026-01-01T00:00:00.000Z"],"type":"string"},"validTo":{"description":"New validity end (ISO timestamp).","examples":["2027-01-01T00:00:00.000Z"],"type":"string"}}}}}}}},"/bff/contract/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was deleted successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was deleted successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was deleted successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContractDelete","tags":["Contract"],"summary":"Delete contract","description":"Soft-deletes a contract by setting deleted_date. The contract is excluded from listings but remains in the database.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contractId"],"properties":{"contractId":{"description":"Internal contract ID to soft-delete.","examples":[10],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["contractId"],"properties":{"contractId":{"description":"Internal contract ID to soft-delete.","examples":[10],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["contractId"],"properties":{"contractId":{"description":"Internal contract ID to soft-delete.","examples":[10],"type":"number"}}}}}}}},"/bff/contract/party/add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the party was added successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the party was added successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the party was added successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContractPartyAdd","tags":["Contract"],"summary":"Add contract party","description":"Adds a contact as a new contract party with the specified role. There is no limit on the number of parties.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contractId","contactId"],"properties":{"contractId":{"description":"Internal contract ID.","examples":[10],"type":"number"},"contactId":{"description":"Internal contact ID to add as a party.","examples":[42],"type":"number"},"role":{"default":"party","description":"Role of the contact in the contract. Use \"issuer\" for the issuing side or \"party\" for a signatory.","examples":["party","issuer","witness","guarantor"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["contractId","contactId"],"properties":{"contractId":{"description":"Internal contract ID.","examples":[10],"type":"number"},"contactId":{"description":"Internal contact ID to add as a party.","examples":[42],"type":"number"},"role":{"default":"party","description":"Role of the contact in the contract. Use \"issuer\" for the issuing side or \"party\" for a signatory.","examples":["party","issuer","witness","guarantor"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["contractId","contactId"],"properties":{"contractId":{"description":"Internal contract ID.","examples":[10],"type":"number"},"contactId":{"description":"Internal contact ID to add as a party.","examples":[42],"type":"number"},"role":{"default":"party","description":"Role of the contact in the contract. Use \"issuer\" for the issuing side or \"party\" for a signatory.","examples":["party","issuer","witness","guarantor"],"type":"string"}}}}}}}},"/bff/contract/party/remove":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the party was removed successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the party was removed successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the party was removed successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffContractPartyRemove","tags":["Contract"],"summary":"Remove contract party","description":"Removes a contact from the contract parties. Deletes the junction record entirely.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contractId","contactId"],"properties":{"contractId":{"description":"Internal contract ID.","examples":[10],"type":"number"},"contactId":{"description":"Internal contact ID to remove from contract parties.","examples":[42],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["contractId","contactId"],"properties":{"contractId":{"description":"Internal contract ID.","examples":[10],"type":"number"},"contactId":{"description":"Internal contact ID to remove from contract parties.","examples":[42],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["contractId","contactId"],"properties":{"contractId":{"description":"Internal contract ID.","examples":[10],"type":"number"},"contactId":{"description":"Internal contact ID to remove from contract parties.","examples":[42],"type":"number"}}}}}}}},"/bff/contract/pdf-preview":{"get":{"parameters":[{"description":"Contract external ID.","examples":["ctr_abc123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffContractPdf-preview","tags":["Contract"],"summary":"Preview contract as PDF","description":"Renders the current contract content (Markdown to HTML to PDF) and returns the PDF binary for inline preview. This does not persist the PDF — use /finalize for permanent storage.","responses":{"200":{}}}},"/bff/contract/finalize":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was finalized successfully.","type":"boolean"},"blobId":{"description":"Internal blob ID of the stored PDF file.","examples":[101],"type":"number"}},"required":["success","blobId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was finalized successfully.","type":"boolean"},"blobId":{"description":"Internal blob ID of the stored PDF file.","examples":[101],"type":"number"}},"required":["success","blobId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contract was finalized successfully.","type":"boolean"},"blobId":{"description":"Internal blob ID of the stored PDF file.","examples":[101],"type":"number"}},"required":["success","blobId"]}}}}},"operationId":"postBffContractFinalize","tags":["Contract"],"summary":"Finalize contract","description":"Generates the final PDF from the contract content, uploads it to blob storage, and links it to the contract record. Sets the contract status to \"approved\" and records the signed date. A finalized contract is considered ready for signing. This operation is irreversible — once a PDF is generated, the contract cannot be finalized again.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contract external ID to finalize.","examples":["ctr_abc123"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contract external ID to finalize.","examples":["ctr_abc123"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Contract external ID to finalize.","examples":["ctr_abc123"],"type":"string"}}}}}}}},"/bff/contract/template/list":{"get":{"parameters":[{"description":"Filter by template category ID.","examples":["3"],"schema":{"type":"string"},"in":"query","name":"categoryId","required":false},{"description":"Filter by locale code.","examples":["cs","en"],"schema":{"type":"string"},"in":"query","name":"locale","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","title","description","categoryName","locale","active","insertedDate"],"properties":{"id":{"description":"Template external ID.","type":"string"},"internalId":{"description":"Template internal ID.","type":"number"},"title":{"description":"Template title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Short description of the template purpose.","type":"string"},{"type":"null"}]},"categoryName":{"nullable":true,"anyOf":[{"description":"Name of the assigned category.","type":"string"},{"type":"null"}]},"locale":{"description":"Locale code of the template.","examples":["cs","en"],"type":"string"},"active":{"description":"Whether the template is active and available for use.","type":"boolean"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total matching templates.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","title","description","categoryName","locale","active","insertedDate"],"properties":{"id":{"description":"Template external ID.","type":"string"},"internalId":{"description":"Template internal ID.","type":"number"},"title":{"description":"Template title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Short description of the template purpose.","type":"string"},{"type":"null"}]},"categoryName":{"nullable":true,"anyOf":[{"description":"Name of the assigned category.","type":"string"},{"type":"null"}]},"locale":{"description":"Locale code of the template.","examples":["cs","en"],"type":"string"},"active":{"description":"Whether the template is active and available for use.","type":"boolean"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total matching templates.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","title","description","categoryName","locale","active","insertedDate"],"properties":{"id":{"description":"Template external ID.","type":"string"},"internalId":{"description":"Template internal ID.","type":"number"},"title":{"description":"Template title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Short description of the template purpose.","type":"string"},{"type":"null"}]},"categoryName":{"nullable":true,"anyOf":[{"description":"Name of the assigned category.","type":"string"},{"type":"null"}]},"locale":{"description":"Locale code of the template.","examples":["cs","en"],"type":"string"},"active":{"description":"Whether the template is active and available for use.","type":"boolean"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total matching templates.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffContractTemplateList","tags":["Contract"],"summary":"List contract templates","description":"Returns all active contract templates for the organisation. Templates serve as reusable blueprints for creating new contracts with predefined content."}},"/bff/contract/template/detail":{"get":{"parameters":[{"description":"Template external ID.","examples":["tpl_xyz789"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Template external ID.","type":"string"},"internalId":{"description":"Template internal ID.","type":"number"},"title":{"description":"Template title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Template description.","type":"string"},{"type":"null"}]},"content":{"description":"Template body in Markdown format — use as initial contract content.","type":"string"},"categoryId":{"nullable":true,"anyOf":[{"description":"Assigned category ID.","type":"number"},{"type":"null"}]},"categoryName":{"nullable":true,"anyOf":[{"description":"Assigned category name.","type":"string"},{"type":"null"}]},"locale":{"description":"Locale code.","examples":["cs","en"],"type":"string"},"active":{"description":"Whether the template is active.","type":"boolean"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","internalId","title","description","content","categoryId","categoryName","locale","active","insertedDate","updatedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Template external ID.","type":"string"},"internalId":{"description":"Template internal ID.","type":"number"},"title":{"description":"Template title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Template description.","type":"string"},{"type":"null"}]},"content":{"description":"Template body in Markdown format — use as initial contract content.","type":"string"},"categoryId":{"nullable":true,"anyOf":[{"description":"Assigned category ID.","type":"number"},{"type":"null"}]},"categoryName":{"nullable":true,"anyOf":[{"description":"Assigned category name.","type":"string"},{"type":"null"}]},"locale":{"description":"Locale code.","examples":["cs","en"],"type":"string"},"active":{"description":"Whether the template is active.","type":"boolean"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","internalId","title","description","content","categoryId","categoryName","locale","active","insertedDate","updatedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Template external ID.","type":"string"},"internalId":{"description":"Template internal ID.","type":"number"},"title":{"description":"Template title.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Template description.","type":"string"},{"type":"null"}]},"content":{"description":"Template body in Markdown format — use as initial contract content.","type":"string"},"categoryId":{"nullable":true,"anyOf":[{"description":"Assigned category ID.","type":"number"},{"type":"null"}]},"categoryName":{"nullable":true,"anyOf":[{"description":"Assigned category name.","type":"string"},{"type":"null"}]},"locale":{"description":"Locale code.","examples":["cs","en"],"type":"string"},"active":{"description":"Whether the template is active.","type":"boolean"},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","internalId","title","description","content","categoryId","categoryName","locale","active","insertedDate","updatedDate"]}}}}},"operationId":"getBffContractTemplateDetail","tags":["Contract"],"summary":"Get contract template detail","description":"Returns full template detail including the Markdown content. Use this content as the initial body when creating a new contract from a template."}},"/bff/dashboard/daily-revenue":{"get":{"parameters":[{"description":"Number of days to fetch. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Daily revenue response with period comparison.","content":{"application/json":{"schema":{"type":"object","properties":{"currentPeriod":{"description":"Summary for the current period.","type":"object","required":["totalRevenue","orderCount","startDate","endDate"],"properties":{"totalRevenue":{"description":"Total revenue in current period.","type":"number"},"orderCount":{"description":"Number of paid orders in current period.","type":"number"},"startDate":{"description":"Start date of current period (YYYY-MM-DD).","type":"string"},"endDate":{"description":"End date of current period (YYYY-MM-DD).","type":"string"}}},"previousPeriod":{"description":"Summary for the previous period (same length, for comparison).","type":"object","required":["totalRevenue","orderCount","startDate","endDate"],"properties":{"totalRevenue":{"description":"Total revenue in previous period.","type":"number"},"orderCount":{"description":"Number of paid orders in previous period.","type":"number"},"startDate":{"description":"Start date of previous period (YYYY-MM-DD).","type":"string"},"endDate":{"description":"End date of previous period (YYYY-MM-DD).","type":"string"}}},"revenueChange":{"description":"Percentage change in revenue vs previous period.","type":"number"},"orderCountChange":{"description":"Percentage change in order count vs previous period.","type":"number"},"dailyData":{"description":"Array of daily revenue data for charting.","type":"array","items":{"description":"Daily revenue data point.","type":"object","required":["date","revenue","orderCount"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"revenue":{"description":"Revenue for this day.","type":"number"},"orderCount":{"description":"Number of paid orders for this day.","type":"number"}}}}},"required":["currentPeriod","previousPeriod","revenueChange","orderCountChange","dailyData"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"currentPeriod":{"description":"Summary for the current period.","type":"object","required":["totalRevenue","orderCount","startDate","endDate"],"properties":{"totalRevenue":{"description":"Total revenue in current period.","type":"number"},"orderCount":{"description":"Number of paid orders in current period.","type":"number"},"startDate":{"description":"Start date of current period (YYYY-MM-DD).","type":"string"},"endDate":{"description":"End date of current period (YYYY-MM-DD).","type":"string"}}},"previousPeriod":{"description":"Summary for the previous period (same length, for comparison).","type":"object","required":["totalRevenue","orderCount","startDate","endDate"],"properties":{"totalRevenue":{"description":"Total revenue in previous period.","type":"number"},"orderCount":{"description":"Number of paid orders in previous period.","type":"number"},"startDate":{"description":"Start date of previous period (YYYY-MM-DD).","type":"string"},"endDate":{"description":"End date of previous period (YYYY-MM-DD).","type":"string"}}},"revenueChange":{"description":"Percentage change in revenue vs previous period.","type":"number"},"orderCountChange":{"description":"Percentage change in order count vs previous period.","type":"number"},"dailyData":{"description":"Array of daily revenue data for charting.","type":"array","items":{"description":"Daily revenue data point.","type":"object","required":["date","revenue","orderCount"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"revenue":{"description":"Revenue for this day.","type":"number"},"orderCount":{"description":"Number of paid orders for this day.","type":"number"}}}}},"required":["currentPeriod","previousPeriod","revenueChange","orderCountChange","dailyData"]}},"text/plain":{"schema":{"type":"object","properties":{"currentPeriod":{"description":"Summary for the current period.","type":"object","required":["totalRevenue","orderCount","startDate","endDate"],"properties":{"totalRevenue":{"description":"Total revenue in current period.","type":"number"},"orderCount":{"description":"Number of paid orders in current period.","type":"number"},"startDate":{"description":"Start date of current period (YYYY-MM-DD).","type":"string"},"endDate":{"description":"End date of current period (YYYY-MM-DD).","type":"string"}}},"previousPeriod":{"description":"Summary for the previous period (same length, for comparison).","type":"object","required":["totalRevenue","orderCount","startDate","endDate"],"properties":{"totalRevenue":{"description":"Total revenue in previous period.","type":"number"},"orderCount":{"description":"Number of paid orders in previous period.","type":"number"},"startDate":{"description":"Start date of previous period (YYYY-MM-DD).","type":"string"},"endDate":{"description":"End date of previous period (YYYY-MM-DD).","type":"string"}}},"revenueChange":{"description":"Percentage change in revenue vs previous period.","type":"number"},"orderCountChange":{"description":"Percentage change in order count vs previous period.","type":"number"},"dailyData":{"description":"Array of daily revenue data for charting.","type":"array","items":{"description":"Daily revenue data point.","type":"object","required":["date","revenue","orderCount"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"revenue":{"description":"Revenue for this day.","type":"number"},"orderCount":{"description":"Number of paid orders for this day.","type":"number"}}}}},"required":["currentPeriod","previousPeriod","revenueChange","orderCountChange","dailyData"]}}}}},"operationId":"getBffDashboardDaily-revenue","tags":["Dashboard"],"summary":"Daily revenue overview","description":"Returns daily revenue data for the specified period with comparison to the previous period. Essential for monitoring business health and cash flow trends."}},"/bff/dashboard/unpaid-orders":{"get":{"responses":{"200":{"description":"Unpaid orders summary with expiration breakdown.","content":{"application/json":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Total value of all unpaid orders.","type":"number"},"orderCount":{"description":"Number of unpaid orders.","type":"number"},"expiringWithin24h":{"description":"Orders at imminent risk of expiration.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Value of orders expiring within 24 hours.","type":"number"},"count":{"description":"Count of orders expiring within 24 hours.","type":"number"}}},"expiringWithin7d":{"description":"Orders expiring soon.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Value of orders expiring within 7 days.","type":"number"},"count":{"description":"Count of orders expiring within 7 days.","type":"number"}}},"oldestUnpaidDays":{"description":"Age of the oldest unpaid order in days. Undefined if no unpaid orders.","type":"number"},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalAmount","orderCount","expiringWithin24h","expiringWithin7d","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Total value of all unpaid orders.","type":"number"},"orderCount":{"description":"Number of unpaid orders.","type":"number"},"expiringWithin24h":{"description":"Orders at imminent risk of expiration.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Value of orders expiring within 24 hours.","type":"number"},"count":{"description":"Count of orders expiring within 24 hours.","type":"number"}}},"expiringWithin7d":{"description":"Orders expiring soon.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Value of orders expiring within 7 days.","type":"number"},"count":{"description":"Count of orders expiring within 7 days.","type":"number"}}},"oldestUnpaidDays":{"description":"Age of the oldest unpaid order in days. Undefined if no unpaid orders.","type":"number"},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalAmount","orderCount","expiringWithin24h","expiringWithin7d","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Total value of all unpaid orders.","type":"number"},"orderCount":{"description":"Number of unpaid orders.","type":"number"},"expiringWithin24h":{"description":"Orders at imminent risk of expiration.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Value of orders expiring within 24 hours.","type":"number"},"count":{"description":"Count of orders expiring within 24 hours.","type":"number"}}},"expiringWithin7d":{"description":"Orders expiring soon.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Value of orders expiring within 7 days.","type":"number"},"count":{"description":"Count of orders expiring within 7 days.","type":"number"}}},"oldestUnpaidDays":{"description":"Age of the oldest unpaid order in days. Undefined if no unpaid orders.","type":"number"},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalAmount","orderCount","expiringWithin24h","expiringWithin7d","currency"]}}}}},"operationId":"getBffDashboardUnpaid-orders","tags":["Dashboard"],"summary":"Unpaid orders summary","description":"Returns summary of orders awaiting payment. Critical for identifying revenue at risk and orders requiring follow-up."}},"/bff/dashboard/overdue-invoices":{"get":{"responses":{"200":{"description":"Overdue invoices summary with aging analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"totalOverdue":{"description":"Total value of all overdue invoices.","type":"number"},"invoiceCount":{"description":"Number of overdue invoices.","type":"number"},"agingBuckets":{"description":"Aging buckets for receivables analysis.","type":"object","required":["days1to7","days8to30","days31to60","days61plus"],"properties":{"days1to7":{"description":"Invoices 1-7 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 1-7 days overdue.","type":"number"},"count":{"description":"Number of invoices 1-7 days overdue.","type":"number"}}},"days8to30":{"description":"Invoices 8-30 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 8-30 days overdue.","type":"number"},"count":{"description":"Number of invoices 8-30 days overdue.","type":"number"}}},"days31to60":{"description":"Invoices 31-60 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 31-60 days overdue.","type":"number"},"count":{"description":"Number of invoices 31-60 days overdue.","type":"number"}}},"days61plus":{"description":"Invoices more than 60 days past due date (high risk).","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 61+ days overdue.","type":"number"},"count":{"description":"Number of invoices 61+ days overdue.","type":"number"}}}}},"topDebtors":{"description":"Top 5 customers with highest overdue amounts.","type":"array","items":{"description":"Customer with overdue invoices.","type":"object","required":["customerId","customerName","amount","invoiceCount","oldestDueDays"],"properties":{"customerId":{"description":"Customer external ID.","type":"string"},"customerName":{"description":"Customer name or email.","type":"string"},"amount":{"description":"Total overdue amount for this customer.","type":"number"},"invoiceCount":{"description":"Number of overdue invoices.","type":"number"},"oldestDueDays":{"description":"Days since the oldest invoice was due.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalOverdue","invoiceCount","agingBuckets","topDebtors","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalOverdue":{"description":"Total value of all overdue invoices.","type":"number"},"invoiceCount":{"description":"Number of overdue invoices.","type":"number"},"agingBuckets":{"description":"Aging buckets for receivables analysis.","type":"object","required":["days1to7","days8to30","days31to60","days61plus"],"properties":{"days1to7":{"description":"Invoices 1-7 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 1-7 days overdue.","type":"number"},"count":{"description":"Number of invoices 1-7 days overdue.","type":"number"}}},"days8to30":{"description":"Invoices 8-30 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 8-30 days overdue.","type":"number"},"count":{"description":"Number of invoices 8-30 days overdue.","type":"number"}}},"days31to60":{"description":"Invoices 31-60 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 31-60 days overdue.","type":"number"},"count":{"description":"Number of invoices 31-60 days overdue.","type":"number"}}},"days61plus":{"description":"Invoices more than 60 days past due date (high risk).","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 61+ days overdue.","type":"number"},"count":{"description":"Number of invoices 61+ days overdue.","type":"number"}}}}},"topDebtors":{"description":"Top 5 customers with highest overdue amounts.","type":"array","items":{"description":"Customer with overdue invoices.","type":"object","required":["customerId","customerName","amount","invoiceCount","oldestDueDays"],"properties":{"customerId":{"description":"Customer external ID.","type":"string"},"customerName":{"description":"Customer name or email.","type":"string"},"amount":{"description":"Total overdue amount for this customer.","type":"number"},"invoiceCount":{"description":"Number of overdue invoices.","type":"number"},"oldestDueDays":{"description":"Days since the oldest invoice was due.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalOverdue","invoiceCount","agingBuckets","topDebtors","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"totalOverdue":{"description":"Total value of all overdue invoices.","type":"number"},"invoiceCount":{"description":"Number of overdue invoices.","type":"number"},"agingBuckets":{"description":"Aging buckets for receivables analysis.","type":"object","required":["days1to7","days8to30","days31to60","days61plus"],"properties":{"days1to7":{"description":"Invoices 1-7 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 1-7 days overdue.","type":"number"},"count":{"description":"Number of invoices 1-7 days overdue.","type":"number"}}},"days8to30":{"description":"Invoices 8-30 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 8-30 days overdue.","type":"number"},"count":{"description":"Number of invoices 8-30 days overdue.","type":"number"}}},"days31to60":{"description":"Invoices 31-60 days past due date.","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 31-60 days overdue.","type":"number"},"count":{"description":"Number of invoices 31-60 days overdue.","type":"number"}}},"days61plus":{"description":"Invoices more than 60 days past due date (high risk).","type":"object","required":["amount","count"],"properties":{"amount":{"description":"Total amount 61+ days overdue.","type":"number"},"count":{"description":"Number of invoices 61+ days overdue.","type":"number"}}}}},"topDebtors":{"description":"Top 5 customers with highest overdue amounts.","type":"array","items":{"description":"Customer with overdue invoices.","type":"object","required":["customerId","customerName","amount","invoiceCount","oldestDueDays"],"properties":{"customerId":{"description":"Customer external ID.","type":"string"},"customerName":{"description":"Customer name or email.","type":"string"},"amount":{"description":"Total overdue amount for this customer.","type":"number"},"invoiceCount":{"description":"Number of overdue invoices.","type":"number"},"oldestDueDays":{"description":"Days since the oldest invoice was due.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalOverdue","invoiceCount","agingBuckets","topDebtors","currency"]}}}}},"operationId":"getBffDashboardOverdue-invoices","tags":["Dashboard"],"summary":"Overdue invoices (receivables)","description":"Returns invoices past their due date grouped by aging buckets. Critical for B2B businesses to manage cash flow and credit risk."}},"/bff/dashboard/orders-by-status":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Orders grouped by status.","content":{"application/json":{"schema":{"type":"object","properties":{"totalOrders":{"description":"Total number of orders in the analyzed period.","type":"number"},"totalValue":{"description":"Total value of all orders.","type":"number"},"byStatus":{"description":"Breakdown by order status, sorted by workflow position.","type":"array","items":{"description":"Status breakdown item.","type":"object","required":["statusId","statusCode","statusLabel","orderCount","totalValue","percentage"],"properties":{"statusId":{"description":"Internal status ID.","type":"number"},"statusCode":{"description":"Status code (e.g., \"new\", \"paid\", \"done\", \"storno\").","type":"string"},"statusLabel":{"description":"Human-readable status label.","type":"string"},"orderCount":{"description":"Number of orders in this status.","type":"number"},"totalValue":{"description":"Total value of orders in this status.","type":"number"},"percentage":{"description":"Percentage of total orders (0-100).","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalOrders","totalValue","byStatus","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalOrders":{"description":"Total number of orders in the analyzed period.","type":"number"},"totalValue":{"description":"Total value of all orders.","type":"number"},"byStatus":{"description":"Breakdown by order status, sorted by workflow position.","type":"array","items":{"description":"Status breakdown item.","type":"object","required":["statusId","statusCode","statusLabel","orderCount","totalValue","percentage"],"properties":{"statusId":{"description":"Internal status ID.","type":"number"},"statusCode":{"description":"Status code (e.g., \"new\", \"paid\", \"done\", \"storno\").","type":"string"},"statusLabel":{"description":"Human-readable status label.","type":"string"},"orderCount":{"description":"Number of orders in this status.","type":"number"},"totalValue":{"description":"Total value of orders in this status.","type":"number"},"percentage":{"description":"Percentage of total orders (0-100).","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalOrders","totalValue","byStatus","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"totalOrders":{"description":"Total number of orders in the analyzed period.","type":"number"},"totalValue":{"description":"Total value of all orders.","type":"number"},"byStatus":{"description":"Breakdown by order status, sorted by workflow position.","type":"array","items":{"description":"Status breakdown item.","type":"object","required":["statusId","statusCode","statusLabel","orderCount","totalValue","percentage"],"properties":{"statusId":{"description":"Internal status ID.","type":"number"},"statusCode":{"description":"Status code (e.g., \"new\", \"paid\", \"done\", \"storno\").","type":"string"},"statusLabel":{"description":"Human-readable status label.","type":"string"},"orderCount":{"description":"Number of orders in this status.","type":"number"},"totalValue":{"description":"Total value of orders in this status.","type":"number"},"percentage":{"description":"Percentage of total orders (0-100).","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["totalOrders","totalValue","byStatus","currency"]}}}}},"operationId":"getBffDashboardOrders-by-status","tags":["Dashboard"],"summary":"Orders by status breakdown","description":"Returns order counts and values grouped by status. Helps identify bottlenecks in order processing workflow."}},"/bff/dashboard/average-order-value":{"get":{"parameters":[{"description":"Number of months to analyze. Defaults to 6.","schema":{"type":"number","default":6},"in":"query","name":"months","required":false}],"responses":{"200":{"description":"AOV analysis with monthly trend.","content":{"application/json":{"schema":{"type":"object","properties":{"currentAov":{"description":"Average order value for the current month.","type":"number"},"previousAov":{"description":"Average order value for the previous month.","type":"number"},"aovChange":{"description":"Percentage change in AOV vs previous month.","type":"number"},"monthlyData":{"description":"Monthly AOV trend data, oldest first.","type":"array","items":{"description":"Monthly AOV data point.","type":"object","required":["month","aov","orderCount","totalRevenue"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"aov":{"description":"Average order value for the month.","type":"number"},"orderCount":{"description":"Number of paid orders in the month.","type":"number"},"totalRevenue":{"description":"Total revenue for the month.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["currentAov","previousAov","aovChange","monthlyData","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"currentAov":{"description":"Average order value for the current month.","type":"number"},"previousAov":{"description":"Average order value for the previous month.","type":"number"},"aovChange":{"description":"Percentage change in AOV vs previous month.","type":"number"},"monthlyData":{"description":"Monthly AOV trend data, oldest first.","type":"array","items":{"description":"Monthly AOV data point.","type":"object","required":["month","aov","orderCount","totalRevenue"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"aov":{"description":"Average order value for the month.","type":"number"},"orderCount":{"description":"Number of paid orders in the month.","type":"number"},"totalRevenue":{"description":"Total revenue for the month.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["currentAov","previousAov","aovChange","monthlyData","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"currentAov":{"description":"Average order value for the current month.","type":"number"},"previousAov":{"description":"Average order value for the previous month.","type":"number"},"aovChange":{"description":"Percentage change in AOV vs previous month.","type":"number"},"monthlyData":{"description":"Monthly AOV trend data, oldest first.","type":"array","items":{"description":"Monthly AOV data point.","type":"object","required":["month","aov","orderCount","totalRevenue"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"aov":{"description":"Average order value for the month.","type":"number"},"orderCount":{"description":"Number of paid orders in the month.","type":"number"},"totalRevenue":{"description":"Total revenue for the month.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["currentAov","previousAov","aovChange","monthlyData","currency"]}}}}},"operationId":"getBffDashboardAverage-order-value","tags":["Dashboard"],"summary":"Average Order Value (AOV) trend","description":"Returns average order value over time. Key metric for pricing optimization, upselling effectiveness, and bundle strategies."}},"/bff/dashboard/payment-success-rate":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Payment success rate analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"overallSuccessRate":{"description":"Overall payment success rate (0-100%).","type":"number"},"totalPayments":{"description":"Total number of payment attempts.","type":"number"},"successfulPayments":{"description":"Number of successful (paid) payments.","type":"number"},"failedPayments":{"description":"Number of failed/cancelled payments.","type":"number"},"pendingPayments":{"description":"Number of pending/in-progress payments.","type":"number"},"byGateway":{"description":"Success rate breakdown by payment gateway.","type":"array","items":{"description":"Payment gateway performance.","type":"object","required":["gatewayCode","gatewayName","successRate","totalPayments","successfulPayments","failedPayments"],"properties":{"gatewayCode":{"description":"Payment gateway identifier code.","type":"string"},"gatewayName":{"description":"Payment gateway display name.","type":"string"},"successRate":{"description":"Success rate for this gateway (0-100%).","type":"number"},"totalPayments":{"description":"Total payments via this gateway.","type":"number"},"successfulPayments":{"description":"Successful payments via this gateway.","type":"number"},"failedPayments":{"description":"Failed payments via this gateway.","type":"number"}}}},"dailyTrend":{"description":"Daily success rate trend for charting.","type":"array","items":{"description":"Daily success rate data point.","type":"object","required":["date","successRate","total"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"successRate":{"description":"Success rate for this day (0-100%).","type":"number"},"total":{"description":"Total payment attempts on this day.","type":"number"}}}}},"required":["overallSuccessRate","totalPayments","successfulPayments","failedPayments","pendingPayments","byGateway","dailyTrend"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"overallSuccessRate":{"description":"Overall payment success rate (0-100%).","type":"number"},"totalPayments":{"description":"Total number of payment attempts.","type":"number"},"successfulPayments":{"description":"Number of successful (paid) payments.","type":"number"},"failedPayments":{"description":"Number of failed/cancelled payments.","type":"number"},"pendingPayments":{"description":"Number of pending/in-progress payments.","type":"number"},"byGateway":{"description":"Success rate breakdown by payment gateway.","type":"array","items":{"description":"Payment gateway performance.","type":"object","required":["gatewayCode","gatewayName","successRate","totalPayments","successfulPayments","failedPayments"],"properties":{"gatewayCode":{"description":"Payment gateway identifier code.","type":"string"},"gatewayName":{"description":"Payment gateway display name.","type":"string"},"successRate":{"description":"Success rate for this gateway (0-100%).","type":"number"},"totalPayments":{"description":"Total payments via this gateway.","type":"number"},"successfulPayments":{"description":"Successful payments via this gateway.","type":"number"},"failedPayments":{"description":"Failed payments via this gateway.","type":"number"}}}},"dailyTrend":{"description":"Daily success rate trend for charting.","type":"array","items":{"description":"Daily success rate data point.","type":"object","required":["date","successRate","total"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"successRate":{"description":"Success rate for this day (0-100%).","type":"number"},"total":{"description":"Total payment attempts on this day.","type":"number"}}}}},"required":["overallSuccessRate","totalPayments","successfulPayments","failedPayments","pendingPayments","byGateway","dailyTrend"]}},"text/plain":{"schema":{"type":"object","properties":{"overallSuccessRate":{"description":"Overall payment success rate (0-100%).","type":"number"},"totalPayments":{"description":"Total number of payment attempts.","type":"number"},"successfulPayments":{"description":"Number of successful (paid) payments.","type":"number"},"failedPayments":{"description":"Number of failed/cancelled payments.","type":"number"},"pendingPayments":{"description":"Number of pending/in-progress payments.","type":"number"},"byGateway":{"description":"Success rate breakdown by payment gateway.","type":"array","items":{"description":"Payment gateway performance.","type":"object","required":["gatewayCode","gatewayName","successRate","totalPayments","successfulPayments","failedPayments"],"properties":{"gatewayCode":{"description":"Payment gateway identifier code.","type":"string"},"gatewayName":{"description":"Payment gateway display name.","type":"string"},"successRate":{"description":"Success rate for this gateway (0-100%).","type":"number"},"totalPayments":{"description":"Total payments via this gateway.","type":"number"},"successfulPayments":{"description":"Successful payments via this gateway.","type":"number"},"failedPayments":{"description":"Failed payments via this gateway.","type":"number"}}}},"dailyTrend":{"description":"Daily success rate trend for charting.","type":"array","items":{"description":"Daily success rate data point.","type":"object","required":["date","successRate","total"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"successRate":{"description":"Success rate for this day (0-100%).","type":"number"},"total":{"description":"Total payment attempts on this day.","type":"number"}}}}},"required":["overallSuccessRate","totalPayments","successfulPayments","failedPayments","pendingPayments","byGateway","dailyTrend"]}}}}},"operationId":"getBffDashboardPayment-success-rate","tags":["Dashboard"],"summary":"Payment success rate","description":"Returns payment success/failure statistics by gateway. Helps detect payment gateway issues before they impact revenue significantly."}},"/bff/dashboard/customer-segmentation":{"get":{"parameters":[{"description":"Number of months to analyze. Defaults to 6.","schema":{"type":"number","default":6},"in":"query","name":"months","required":false}],"responses":{"200":{"description":"Customer segmentation analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"currentMonth":{"description":"Current month customer breakdown.","type":"object","required":["newCustomers","returningCustomers","newCustomerRevenue","returningCustomerRevenue","newCustomerPercentage"],"properties":{"newCustomers":{"description":"Customers making their first-ever order this month.","type":"number"},"returningCustomers":{"description":"Customers with at least one previous order.","type":"number"},"newCustomerRevenue":{"description":"Revenue from new customers.","type":"number"},"returningCustomerRevenue":{"description":"Revenue from returning customers.","type":"number"},"newCustomerPercentage":{"description":"Percentage of customers who are new (0-100).","type":"number"}}},"previousMonth":{"description":"Previous month for comparison.","type":"object","required":["newCustomers","returningCustomers","newCustomerPercentage"],"properties":{"newCustomers":{"description":"New customers in previous month.","type":"number"},"returningCustomers":{"description":"Returning customers in previous month.","type":"number"},"newCustomerPercentage":{"description":"New customer percentage in previous month.","type":"number"}}},"monthlyTrend":{"description":"Monthly trend data, oldest first.","type":"array","items":{"description":"Monthly customer segmentation data point.","type":"object","required":["month","newCustomers","returningCustomers","newCustomerPercentage"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"newCustomers":{"description":"New customers count.","type":"number"},"returningCustomers":{"description":"Returning customers count.","type":"number"},"newCustomerPercentage":{"description":"Percentage of new customers (0-100).","type":"number"}}}},"currency":{"description":"Currency code for revenue amounts (e.g., \"CZK\").","type":"string"}},"required":["currentMonth","previousMonth","monthlyTrend","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"currentMonth":{"description":"Current month customer breakdown.","type":"object","required":["newCustomers","returningCustomers","newCustomerRevenue","returningCustomerRevenue","newCustomerPercentage"],"properties":{"newCustomers":{"description":"Customers making their first-ever order this month.","type":"number"},"returningCustomers":{"description":"Customers with at least one previous order.","type":"number"},"newCustomerRevenue":{"description":"Revenue from new customers.","type":"number"},"returningCustomerRevenue":{"description":"Revenue from returning customers.","type":"number"},"newCustomerPercentage":{"description":"Percentage of customers who are new (0-100).","type":"number"}}},"previousMonth":{"description":"Previous month for comparison.","type":"object","required":["newCustomers","returningCustomers","newCustomerPercentage"],"properties":{"newCustomers":{"description":"New customers in previous month.","type":"number"},"returningCustomers":{"description":"Returning customers in previous month.","type":"number"},"newCustomerPercentage":{"description":"New customer percentage in previous month.","type":"number"}}},"monthlyTrend":{"description":"Monthly trend data, oldest first.","type":"array","items":{"description":"Monthly customer segmentation data point.","type":"object","required":["month","newCustomers","returningCustomers","newCustomerPercentage"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"newCustomers":{"description":"New customers count.","type":"number"},"returningCustomers":{"description":"Returning customers count.","type":"number"},"newCustomerPercentage":{"description":"Percentage of new customers (0-100).","type":"number"}}}},"currency":{"description":"Currency code for revenue amounts (e.g., \"CZK\").","type":"string"}},"required":["currentMonth","previousMonth","monthlyTrend","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"currentMonth":{"description":"Current month customer breakdown.","type":"object","required":["newCustomers","returningCustomers","newCustomerRevenue","returningCustomerRevenue","newCustomerPercentage"],"properties":{"newCustomers":{"description":"Customers making their first-ever order this month.","type":"number"},"returningCustomers":{"description":"Customers with at least one previous order.","type":"number"},"newCustomerRevenue":{"description":"Revenue from new customers.","type":"number"},"returningCustomerRevenue":{"description":"Revenue from returning customers.","type":"number"},"newCustomerPercentage":{"description":"Percentage of customers who are new (0-100).","type":"number"}}},"previousMonth":{"description":"Previous month for comparison.","type":"object","required":["newCustomers","returningCustomers","newCustomerPercentage"],"properties":{"newCustomers":{"description":"New customers in previous month.","type":"number"},"returningCustomers":{"description":"Returning customers in previous month.","type":"number"},"newCustomerPercentage":{"description":"New customer percentage in previous month.","type":"number"}}},"monthlyTrend":{"description":"Monthly trend data, oldest first.","type":"array","items":{"description":"Monthly customer segmentation data point.","type":"object","required":["month","newCustomers","returningCustomers","newCustomerPercentage"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"newCustomers":{"description":"New customers count.","type":"number"},"returningCustomers":{"description":"Returning customers count.","type":"number"},"newCustomerPercentage":{"description":"Percentage of new customers (0-100).","type":"number"}}}},"currency":{"description":"Currency code for revenue amounts (e.g., \"CZK\").","type":"string"}},"required":["currentMonth","previousMonth","monthlyTrend","currency"]}}}}},"operationId":"getBffDashboardCustomer-segmentation","tags":["Dashboard"],"summary":"New vs returning customers","description":"Returns customer segmentation showing new vs returning customer ratio. Essential for understanding growth vs retention balance and marketing effectiveness."}},"/bff/dashboard/revenue-retention":{"get":{"parameters":[{"description":"Granularity: yearly (3 pairs) or quarterly YoY (12 pairs). Defaults to year.","schema":{"default":"year","anyOf":[{"const":"year","type":"string"},{"const":"quarter","type":"string"}]},"in":"query","name":"period","required":false}],"responses":{"200":{"description":"Year-over-year revenue retention analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"period":{"description":"Granularity actually used.","anyOf":[{"const":"year","type":"string"},{"const":"quarter","type":"string"}]},"currency":{"description":"Currency code for all revenue values (org default).","type":"string"},"warning":{"description":"Warning summary.","type":"object","required":["level","firstOrderDate","organisationAgeDays"],"properties":{"level":{"description":"Health classification of the latest (floating) retention.","anyOf":[{"const":"insufficient_data","type":"string"},{"const":"healthy","type":"string"},{"const":"low_retention","type":"string"}]},"note":{"description":"Extra advisory when retention is below 50%.","const":"marketing_dependency","type":"string"},"firstOrderDate":{"description":"Date of the first paid order in the organisation (YYYY-MM-DD), null if none.","anyOf":[{"type":"string"},{"type":"null"}]},"organisationAgeDays":{"description":"Days since the first paid order — used for the \"younger than 2 years\" gate.","type":"number"}}},"periods":{"description":"Periods ordered newest first (idx 0 = floating current).","type":"array","items":{"description":"Single retention pair.","type":"object","required":["periodIdx","label","baselineStart","baselineEnd","currentStart","currentEnd","isFloating","baselineCustomers","retainedCustomers","lostCustomers","customerRetentionRate","baselineRevenue","currentRevenueFromBaselineCustomers","grossRetentionRate","netRetentionRate","avgRevenuePerCustomerBaseline","avgRevenuePerCustomerCurrent","avgRevenuePerCustomerChange","bands"],"properties":{"periodIdx":{"description":"0 = most recent (floating), N = N periods back.","type":"number"},"label":{"description":"Human label, e.g. \"2024 → 2025\" or \"Q2 2024 → Q2 2025\".","type":"string"},"baselineStart":{"description":"Baseline window start (YYYY-MM-DD).","type":"string"},"baselineEnd":{"description":"Baseline window end (YYYY-MM-DD).","type":"string"},"currentStart":{"description":"Current window start (YYYY-MM-DD).","type":"string"},"currentEnd":{"description":"Current window end (YYYY-MM-DD).","type":"string"},"isFloating":{"description":"True if the current window is in-progress (truncated to today).","type":"boolean"},"baselineCustomers":{"description":"Distinct customers paying in baseline.","type":"number"},"retainedCustomers":{"description":"Of those, how many also paid in current.","type":"number"},"lostCustomers":{"description":"Baseline minus retained.","type":"number"},"customerRetentionRate":{"description":"retainedCustomers / baselineCustomers, in %.","type":"number"},"baselineRevenue":{"description":"Revenue in baseline from baseline customers.","type":"number"},"currentRevenueFromBaselineCustomers":{"description":"Revenue in current from those same baseline customers.","type":"number"},"grossRetentionRate":{"description":"GRR: SUM(MIN(current, baseline)) / SUM(baseline) — capped, no upsell.","type":"number"},"netRetentionRate":{"description":"NRR: SUM(current) / SUM(baseline) — can exceed 100% with upsell.","type":"number"},"avgRevenuePerCustomerBaseline":{"description":"Avg baseline revenue, averaged over retained customers (like-for-like).","type":"number"},"avgRevenuePerCustomerCurrent":{"description":"Avg current revenue, averaged over retained customers.","type":"number"},"avgRevenuePerCustomerChange":{"description":"Percentage change in avg spend from the same customers.","type":"number"},"bands":{"description":"Per-customer retention bands (6 fixed buckets).","type":"array","items":{"type":"object","required":["band","customerCount","customerPercentage","baselineRevenue","currentRevenue"],"properties":{"band":{"anyOf":[{"const":"growing","type":"string"},{"const":"holding","type":"string"},{"const":"declining","type":"string"},{"const":"at_risk","type":"string"},{"const":"critical","type":"string"},{"const":"lost","type":"string"}]},"customerCount":{"description":"Customers in this band.","type":"number"},"customerPercentage":{"description":"Share of baseline customers (0-100).","type":"number"},"baselineRevenue":{"description":"Baseline revenue from this band.","type":"number"},"currentRevenue":{"description":"Current revenue from this band.","type":"number"}}}}}}},"stability":{"description":"Null when warning.level is insufficient_data.","anyOf":[{"type":"object","required":["weightedRetention","weightedGrossRetention","volatility","score","rating","projectedAnnualRevenue"],"properties":{"weightedRetention":{"description":"Baseline-weighted NRR across all periods (%).","type":"number"},"weightedGrossRetention":{"description":"Baseline-weighted GRR across all periods (%).","type":"number"},"volatility":{"description":"Standard deviation of NRR across periods (pp).","type":"number"},"score":{"description":"Stability score 0-100.","type":"number"},"rating":{"anyOf":[{"const":"excellent","type":"string"},{"const":"good","type":"string"},{"const":"moderate","type":"string"},{"const":"concerning","type":"string"},{"const":"critical","type":"string"}]},"projectedAnnualRevenue":{"description":"Estimated revenue we can count on next period from existing customers.","type":"number"}}},{"type":"null"}]},"currencyMix":{"description":"Currency situation — retention is computed only in the org default.","type":"object","required":["primaryCurrencyId","primaryCurrencyCode","otherCurrenciesPresent","otherCurrenciesRevenue"],"properties":{"primaryCurrencyId":{"description":"Org default currency ID.","type":"number"},"primaryCurrencyCode":{"description":"Org default currency code.","type":"string"},"otherCurrenciesPresent":{"description":"True if orders in other currencies exist in the windows.","type":"boolean"},"otherCurrenciesRevenue":{"description":"Total revenue ignored due to non-default currency.","type":"number"}}}},"required":["period","currency","warning","periods","stability","currencyMix"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"period":{"description":"Granularity actually used.","anyOf":[{"const":"year","type":"string"},{"const":"quarter","type":"string"}]},"currency":{"description":"Currency code for all revenue values (org default).","type":"string"},"warning":{"description":"Warning summary.","type":"object","required":["level","firstOrderDate","organisationAgeDays"],"properties":{"level":{"description":"Health classification of the latest (floating) retention.","anyOf":[{"const":"insufficient_data","type":"string"},{"const":"healthy","type":"string"},{"const":"low_retention","type":"string"}]},"note":{"description":"Extra advisory when retention is below 50%.","const":"marketing_dependency","type":"string"},"firstOrderDate":{"description":"Date of the first paid order in the organisation (YYYY-MM-DD), null if none.","anyOf":[{"type":"string"},{"type":"null"}]},"organisationAgeDays":{"description":"Days since the first paid order — used for the \"younger than 2 years\" gate.","type":"number"}}},"periods":{"description":"Periods ordered newest first (idx 0 = floating current).","type":"array","items":{"description":"Single retention pair.","type":"object","required":["periodIdx","label","baselineStart","baselineEnd","currentStart","currentEnd","isFloating","baselineCustomers","retainedCustomers","lostCustomers","customerRetentionRate","baselineRevenue","currentRevenueFromBaselineCustomers","grossRetentionRate","netRetentionRate","avgRevenuePerCustomerBaseline","avgRevenuePerCustomerCurrent","avgRevenuePerCustomerChange","bands"],"properties":{"periodIdx":{"description":"0 = most recent (floating), N = N periods back.","type":"number"},"label":{"description":"Human label, e.g. \"2024 → 2025\" or \"Q2 2024 → Q2 2025\".","type":"string"},"baselineStart":{"description":"Baseline window start (YYYY-MM-DD).","type":"string"},"baselineEnd":{"description":"Baseline window end (YYYY-MM-DD).","type":"string"},"currentStart":{"description":"Current window start (YYYY-MM-DD).","type":"string"},"currentEnd":{"description":"Current window end (YYYY-MM-DD).","type":"string"},"isFloating":{"description":"True if the current window is in-progress (truncated to today).","type":"boolean"},"baselineCustomers":{"description":"Distinct customers paying in baseline.","type":"number"},"retainedCustomers":{"description":"Of those, how many also paid in current.","type":"number"},"lostCustomers":{"description":"Baseline minus retained.","type":"number"},"customerRetentionRate":{"description":"retainedCustomers / baselineCustomers, in %.","type":"number"},"baselineRevenue":{"description":"Revenue in baseline from baseline customers.","type":"number"},"currentRevenueFromBaselineCustomers":{"description":"Revenue in current from those same baseline customers.","type":"number"},"grossRetentionRate":{"description":"GRR: SUM(MIN(current, baseline)) / SUM(baseline) — capped, no upsell.","type":"number"},"netRetentionRate":{"description":"NRR: SUM(current) / SUM(baseline) — can exceed 100% with upsell.","type":"number"},"avgRevenuePerCustomerBaseline":{"description":"Avg baseline revenue, averaged over retained customers (like-for-like).","type":"number"},"avgRevenuePerCustomerCurrent":{"description":"Avg current revenue, averaged over retained customers.","type":"number"},"avgRevenuePerCustomerChange":{"description":"Percentage change in avg spend from the same customers.","type":"number"},"bands":{"description":"Per-customer retention bands (6 fixed buckets).","type":"array","items":{"type":"object","required":["band","customerCount","customerPercentage","baselineRevenue","currentRevenue"],"properties":{"band":{"anyOf":[{"const":"growing","type":"string"},{"const":"holding","type":"string"},{"const":"declining","type":"string"},{"const":"at_risk","type":"string"},{"const":"critical","type":"string"},{"const":"lost","type":"string"}]},"customerCount":{"description":"Customers in this band.","type":"number"},"customerPercentage":{"description":"Share of baseline customers (0-100).","type":"number"},"baselineRevenue":{"description":"Baseline revenue from this band.","type":"number"},"currentRevenue":{"description":"Current revenue from this band.","type":"number"}}}}}}},"stability":{"description":"Null when warning.level is insufficient_data.","anyOf":[{"type":"object","required":["weightedRetention","weightedGrossRetention","volatility","score","rating","projectedAnnualRevenue"],"properties":{"weightedRetention":{"description":"Baseline-weighted NRR across all periods (%).","type":"number"},"weightedGrossRetention":{"description":"Baseline-weighted GRR across all periods (%).","type":"number"},"volatility":{"description":"Standard deviation of NRR across periods (pp).","type":"number"},"score":{"description":"Stability score 0-100.","type":"number"},"rating":{"anyOf":[{"const":"excellent","type":"string"},{"const":"good","type":"string"},{"const":"moderate","type":"string"},{"const":"concerning","type":"string"},{"const":"critical","type":"string"}]},"projectedAnnualRevenue":{"description":"Estimated revenue we can count on next period from existing customers.","type":"number"}}},{"type":"null"}]},"currencyMix":{"description":"Currency situation — retention is computed only in the org default.","type":"object","required":["primaryCurrencyId","primaryCurrencyCode","otherCurrenciesPresent","otherCurrenciesRevenue"],"properties":{"primaryCurrencyId":{"description":"Org default currency ID.","type":"number"},"primaryCurrencyCode":{"description":"Org default currency code.","type":"string"},"otherCurrenciesPresent":{"description":"True if orders in other currencies exist in the windows.","type":"boolean"},"otherCurrenciesRevenue":{"description":"Total revenue ignored due to non-default currency.","type":"number"}}}},"required":["period","currency","warning","periods","stability","currencyMix"]}},"text/plain":{"schema":{"type":"object","properties":{"period":{"description":"Granularity actually used.","anyOf":[{"const":"year","type":"string"},{"const":"quarter","type":"string"}]},"currency":{"description":"Currency code for all revenue values (org default).","type":"string"},"warning":{"description":"Warning summary.","type":"object","required":["level","firstOrderDate","organisationAgeDays"],"properties":{"level":{"description":"Health classification of the latest (floating) retention.","anyOf":[{"const":"insufficient_data","type":"string"},{"const":"healthy","type":"string"},{"const":"low_retention","type":"string"}]},"note":{"description":"Extra advisory when retention is below 50%.","const":"marketing_dependency","type":"string"},"firstOrderDate":{"description":"Date of the first paid order in the organisation (YYYY-MM-DD), null if none.","anyOf":[{"type":"string"},{"type":"null"}]},"organisationAgeDays":{"description":"Days since the first paid order — used for the \"younger than 2 years\" gate.","type":"number"}}},"periods":{"description":"Periods ordered newest first (idx 0 = floating current).","type":"array","items":{"description":"Single retention pair.","type":"object","required":["periodIdx","label","baselineStart","baselineEnd","currentStart","currentEnd","isFloating","baselineCustomers","retainedCustomers","lostCustomers","customerRetentionRate","baselineRevenue","currentRevenueFromBaselineCustomers","grossRetentionRate","netRetentionRate","avgRevenuePerCustomerBaseline","avgRevenuePerCustomerCurrent","avgRevenuePerCustomerChange","bands"],"properties":{"periodIdx":{"description":"0 = most recent (floating), N = N periods back.","type":"number"},"label":{"description":"Human label, e.g. \"2024 → 2025\" or \"Q2 2024 → Q2 2025\".","type":"string"},"baselineStart":{"description":"Baseline window start (YYYY-MM-DD).","type":"string"},"baselineEnd":{"description":"Baseline window end (YYYY-MM-DD).","type":"string"},"currentStart":{"description":"Current window start (YYYY-MM-DD).","type":"string"},"currentEnd":{"description":"Current window end (YYYY-MM-DD).","type":"string"},"isFloating":{"description":"True if the current window is in-progress (truncated to today).","type":"boolean"},"baselineCustomers":{"description":"Distinct customers paying in baseline.","type":"number"},"retainedCustomers":{"description":"Of those, how many also paid in current.","type":"number"},"lostCustomers":{"description":"Baseline minus retained.","type":"number"},"customerRetentionRate":{"description":"retainedCustomers / baselineCustomers, in %.","type":"number"},"baselineRevenue":{"description":"Revenue in baseline from baseline customers.","type":"number"},"currentRevenueFromBaselineCustomers":{"description":"Revenue in current from those same baseline customers.","type":"number"},"grossRetentionRate":{"description":"GRR: SUM(MIN(current, baseline)) / SUM(baseline) — capped, no upsell.","type":"number"},"netRetentionRate":{"description":"NRR: SUM(current) / SUM(baseline) — can exceed 100% with upsell.","type":"number"},"avgRevenuePerCustomerBaseline":{"description":"Avg baseline revenue, averaged over retained customers (like-for-like).","type":"number"},"avgRevenuePerCustomerCurrent":{"description":"Avg current revenue, averaged over retained customers.","type":"number"},"avgRevenuePerCustomerChange":{"description":"Percentage change in avg spend from the same customers.","type":"number"},"bands":{"description":"Per-customer retention bands (6 fixed buckets).","type":"array","items":{"type":"object","required":["band","customerCount","customerPercentage","baselineRevenue","currentRevenue"],"properties":{"band":{"anyOf":[{"const":"growing","type":"string"},{"const":"holding","type":"string"},{"const":"declining","type":"string"},{"const":"at_risk","type":"string"},{"const":"critical","type":"string"},{"const":"lost","type":"string"}]},"customerCount":{"description":"Customers in this band.","type":"number"},"customerPercentage":{"description":"Share of baseline customers (0-100).","type":"number"},"baselineRevenue":{"description":"Baseline revenue from this band.","type":"number"},"currentRevenue":{"description":"Current revenue from this band.","type":"number"}}}}}}},"stability":{"description":"Null when warning.level is insufficient_data.","anyOf":[{"type":"object","required":["weightedRetention","weightedGrossRetention","volatility","score","rating","projectedAnnualRevenue"],"properties":{"weightedRetention":{"description":"Baseline-weighted NRR across all periods (%).","type":"number"},"weightedGrossRetention":{"description":"Baseline-weighted GRR across all periods (%).","type":"number"},"volatility":{"description":"Standard deviation of NRR across periods (pp).","type":"number"},"score":{"description":"Stability score 0-100.","type":"number"},"rating":{"anyOf":[{"const":"excellent","type":"string"},{"const":"good","type":"string"},{"const":"moderate","type":"string"},{"const":"concerning","type":"string"},{"const":"critical","type":"string"}]},"projectedAnnualRevenue":{"description":"Estimated revenue we can count on next period from existing customers.","type":"number"}}},{"type":"null"}]},"currencyMix":{"description":"Currency situation — retention is computed only in the org default.","type":"object","required":["primaryCurrencyId","primaryCurrencyCode","otherCurrenciesPresent","otherCurrenciesRevenue"],"properties":{"primaryCurrencyId":{"description":"Org default currency ID.","type":"number"},"primaryCurrencyCode":{"description":"Org default currency code.","type":"string"},"otherCurrenciesPresent":{"description":"True if orders in other currencies exist in the windows.","type":"boolean"},"otherCurrenciesRevenue":{"description":"Total revenue ignored due to non-default currency.","type":"number"}}}},"required":["period","currency","warning","periods","stability","currencyMix"]}}}}},"operationId":"getBffDashboardRevenue-retention","tags":["Dashboard"],"summary":"Year-over-year revenue retention","description":"Cohort-based revenue retention: for customers who paid in a previous period, how much do they still pay this period? Returns per-period stats, per-customer retention bands, a stability score and a warning level. The most recent period is \"floating\" (truncated to today) and compared to the same offset in the prior period for a fair in-progress comparison. Returns insufficient_data if the organisation's first paid order is younger than 2 years."}},"/bff/dashboard/mrr":{"get":{"parameters":[{"description":"Number of months to analyze. Defaults to 12.","schema":{"type":"number","default":12},"in":"query","name":"months","required":false}],"responses":{"200":{"description":"MRR and subscription metrics.","content":{"application/json":{"schema":{"type":"object","properties":{"currentMrr":{"description":"Current Monthly Recurring Revenue.","type":"number"},"previousMrr":{"description":"Previous month MRR.","type":"number"},"mrrChange":{"description":"Percentage change in MRR vs previous month.","type":"number"},"activeSubscriptions":{"description":"Number of currently active subscriptions.","type":"number"},"churnedSubscriptions":{"description":"Subscriptions cancelled/expired this month.","type":"number"},"newSubscriptions":{"description":"New subscriptions created this month.","type":"number"},"churnRate":{"description":"Monthly churn rate (0-100%).","type":"number"},"monthlyTrend":{"description":"Monthly MRR trend, oldest first.","type":"array","items":{"description":"Monthly MRR data point.","type":"object","required":["month","mrr","activeSubscriptions","newSubscriptions","churnedSubscriptions"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"mrr":{"description":"MRR for the month.","type":"number"},"activeSubscriptions":{"description":"Active subscriptions at end of month.","type":"number"},"newSubscriptions":{"description":"New subscriptions in the month.","type":"number"},"churnedSubscriptions":{"description":"Churned subscriptions in the month.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["currentMrr","previousMrr","mrrChange","activeSubscriptions","churnedSubscriptions","newSubscriptions","churnRate","monthlyTrend","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"currentMrr":{"description":"Current Monthly Recurring Revenue.","type":"number"},"previousMrr":{"description":"Previous month MRR.","type":"number"},"mrrChange":{"description":"Percentage change in MRR vs previous month.","type":"number"},"activeSubscriptions":{"description":"Number of currently active subscriptions.","type":"number"},"churnedSubscriptions":{"description":"Subscriptions cancelled/expired this month.","type":"number"},"newSubscriptions":{"description":"New subscriptions created this month.","type":"number"},"churnRate":{"description":"Monthly churn rate (0-100%).","type":"number"},"monthlyTrend":{"description":"Monthly MRR trend, oldest first.","type":"array","items":{"description":"Monthly MRR data point.","type":"object","required":["month","mrr","activeSubscriptions","newSubscriptions","churnedSubscriptions"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"mrr":{"description":"MRR for the month.","type":"number"},"activeSubscriptions":{"description":"Active subscriptions at end of month.","type":"number"},"newSubscriptions":{"description":"New subscriptions in the month.","type":"number"},"churnedSubscriptions":{"description":"Churned subscriptions in the month.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["currentMrr","previousMrr","mrrChange","activeSubscriptions","churnedSubscriptions","newSubscriptions","churnRate","monthlyTrend","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"currentMrr":{"description":"Current Monthly Recurring Revenue.","type":"number"},"previousMrr":{"description":"Previous month MRR.","type":"number"},"mrrChange":{"description":"Percentage change in MRR vs previous month.","type":"number"},"activeSubscriptions":{"description":"Number of currently active subscriptions.","type":"number"},"churnedSubscriptions":{"description":"Subscriptions cancelled/expired this month.","type":"number"},"newSubscriptions":{"description":"New subscriptions created this month.","type":"number"},"churnRate":{"description":"Monthly churn rate (0-100%).","type":"number"},"monthlyTrend":{"description":"Monthly MRR trend, oldest first.","type":"array","items":{"description":"Monthly MRR data point.","type":"object","required":["month","mrr","activeSubscriptions","newSubscriptions","churnedSubscriptions"],"properties":{"month":{"description":"Month in YYYY-MM format.","type":"string"},"mrr":{"description":"MRR for the month.","type":"number"},"activeSubscriptions":{"description":"Active subscriptions at end of month.","type":"number"},"newSubscriptions":{"description":"New subscriptions in the month.","type":"number"},"churnedSubscriptions":{"description":"Churned subscriptions in the month.","type":"number"}}}},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["currentMrr","previousMrr","mrrChange","activeSubscriptions","churnedSubscriptions","newSubscriptions","churnRate","monthlyTrend","currency"]}}}}},"operationId":"getBffDashboardMrr","tags":["Dashboard"],"summary":"Monthly Recurring Revenue (MRR)","description":"Returns MRR metrics for subscription-based revenue. The \"north star\" metric for businesses with recurring revenue models."}},"/bff/dashboard/top-products":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false},{"description":"Number of products to return. Defaults to 10.","schema":{"type":"number","default":10},"in":"query","name":"limit","required":false}],"responses":{"200":{"description":"Top products analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"products":{"description":"Top products sorted by revenue (highest first).","type":"array","items":{"description":"Top product item.","type":"object","required":["rank","productName","quantitySold","revenue","orderCount","averagePrice","revenuePercentage"],"properties":{"rank":{"description":"Rank by revenue (1 = highest revenue).","type":"number"},"productId":{"description":"Internal product ID. Undefined for ad-hoc items.","type":"number"},"productCode":{"description":"Product code. Undefined for ad-hoc items.","type":"string"},"productName":{"description":"Product name or order item label.","type":"string"},"quantitySold":{"description":"Total quantity sold.","type":"number"},"revenue":{"description":"Total revenue generated.","type":"number"},"orderCount":{"description":"Number of orders containing this product.","type":"number"},"averagePrice":{"description":"Average selling price per unit.","type":"number"},"revenuePercentage":{"description":"Percentage of total revenue (0-100).","type":"number"}}}},"totalRevenue":{"description":"Total revenue for the period (for percentage calculation).","type":"number"},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["products","totalRevenue","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"products":{"description":"Top products sorted by revenue (highest first).","type":"array","items":{"description":"Top product item.","type":"object","required":["rank","productName","quantitySold","revenue","orderCount","averagePrice","revenuePercentage"],"properties":{"rank":{"description":"Rank by revenue (1 = highest revenue).","type":"number"},"productId":{"description":"Internal product ID. Undefined for ad-hoc items.","type":"number"},"productCode":{"description":"Product code. Undefined for ad-hoc items.","type":"string"},"productName":{"description":"Product name or order item label.","type":"string"},"quantitySold":{"description":"Total quantity sold.","type":"number"},"revenue":{"description":"Total revenue generated.","type":"number"},"orderCount":{"description":"Number of orders containing this product.","type":"number"},"averagePrice":{"description":"Average selling price per unit.","type":"number"},"revenuePercentage":{"description":"Percentage of total revenue (0-100).","type":"number"}}}},"totalRevenue":{"description":"Total revenue for the period (for percentage calculation).","type":"number"},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["products","totalRevenue","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"products":{"description":"Top products sorted by revenue (highest first).","type":"array","items":{"description":"Top product item.","type":"object","required":["rank","productName","quantitySold","revenue","orderCount","averagePrice","revenuePercentage"],"properties":{"rank":{"description":"Rank by revenue (1 = highest revenue).","type":"number"},"productId":{"description":"Internal product ID. Undefined for ad-hoc items.","type":"number"},"productCode":{"description":"Product code. Undefined for ad-hoc items.","type":"string"},"productName":{"description":"Product name or order item label.","type":"string"},"quantitySold":{"description":"Total quantity sold.","type":"number"},"revenue":{"description":"Total revenue generated.","type":"number"},"orderCount":{"description":"Number of orders containing this product.","type":"number"},"averagePrice":{"description":"Average selling price per unit.","type":"number"},"revenuePercentage":{"description":"Percentage of total revenue (0-100).","type":"number"}}}},"totalRevenue":{"description":"Total revenue for the period (for percentage calculation).","type":"number"},"currency":{"description":"Currency code for all amounts (e.g., \"CZK\").","type":"string"}},"required":["products","totalRevenue","currency"]}}}}},"operationId":"getBffDashboardTop-products","tags":["Dashboard"],"summary":"Top selling products","description":"Returns best-selling products by revenue and quantity. Identifies what generates revenue vs marketing noise."}},"/bff/dashboard/calendar-utilization":{"get":{"parameters":[{"description":"Number of days ahead to analyze. Defaults to 14.","schema":{"type":"number","default":14},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Calendar utilization metrics.","content":{"application/json":{"schema":{"type":"object","properties":{"overallUtilization":{"description":"Overall utilization rate (0-100%).","type":"number"},"totalSlots":{"description":"Total number of events/slots in the period.","type":"number"},"bookedSlots":{"description":"Number of active (non-cancelled) bookings.","type":"number"},"cancelledEvents":{"description":"Number of cancelled events in the period.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"},"byCalendar":{"description":"Utilization breakdown by calendar.","type":"array","items":{"description":"Calendar utilization item.","type":"object","required":["calendarId","calendarName","utilization","bookedHours","availableHours"],"properties":{"calendarId":{"description":"Calendar ID.","type":"number"},"calendarName":{"description":"Calendar name.","type":"string"},"utilization":{"description":"Utilization rate for this calendar (0-100%).","type":"number"},"bookedHours":{"description":"Total booked hours.","type":"number"},"availableHours":{"description":"Total available hours (estimated).","type":"number"}}}},"dailyUtilization":{"description":"Daily utilization trend for charting.","type":"array","items":{"description":"Daily utilization data point.","type":"object","required":["date","utilization","bookedEvents"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"utilization":{"description":"Utilization for this day (0-100%).","type":"number"},"bookedEvents":{"description":"Number of booked events on this day.","type":"number"}}}}},"required":["overallUtilization","totalSlots","bookedSlots","cancelledEvents","cancellationRate","byCalendar","dailyUtilization"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"overallUtilization":{"description":"Overall utilization rate (0-100%).","type":"number"},"totalSlots":{"description":"Total number of events/slots in the period.","type":"number"},"bookedSlots":{"description":"Number of active (non-cancelled) bookings.","type":"number"},"cancelledEvents":{"description":"Number of cancelled events in the period.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"},"byCalendar":{"description":"Utilization breakdown by calendar.","type":"array","items":{"description":"Calendar utilization item.","type":"object","required":["calendarId","calendarName","utilization","bookedHours","availableHours"],"properties":{"calendarId":{"description":"Calendar ID.","type":"number"},"calendarName":{"description":"Calendar name.","type":"string"},"utilization":{"description":"Utilization rate for this calendar (0-100%).","type":"number"},"bookedHours":{"description":"Total booked hours.","type":"number"},"availableHours":{"description":"Total available hours (estimated).","type":"number"}}}},"dailyUtilization":{"description":"Daily utilization trend for charting.","type":"array","items":{"description":"Daily utilization data point.","type":"object","required":["date","utilization","bookedEvents"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"utilization":{"description":"Utilization for this day (0-100%).","type":"number"},"bookedEvents":{"description":"Number of booked events on this day.","type":"number"}}}}},"required":["overallUtilization","totalSlots","bookedSlots","cancelledEvents","cancellationRate","byCalendar","dailyUtilization"]}},"text/plain":{"schema":{"type":"object","properties":{"overallUtilization":{"description":"Overall utilization rate (0-100%).","type":"number"},"totalSlots":{"description":"Total number of events/slots in the period.","type":"number"},"bookedSlots":{"description":"Number of active (non-cancelled) bookings.","type":"number"},"cancelledEvents":{"description":"Number of cancelled events in the period.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"},"byCalendar":{"description":"Utilization breakdown by calendar.","type":"array","items":{"description":"Calendar utilization item.","type":"object","required":["calendarId","calendarName","utilization","bookedHours","availableHours"],"properties":{"calendarId":{"description":"Calendar ID.","type":"number"},"calendarName":{"description":"Calendar name.","type":"string"},"utilization":{"description":"Utilization rate for this calendar (0-100%).","type":"number"},"bookedHours":{"description":"Total booked hours.","type":"number"},"availableHours":{"description":"Total available hours (estimated).","type":"number"}}}},"dailyUtilization":{"description":"Daily utilization trend for charting.","type":"array","items":{"description":"Daily utilization data point.","type":"object","required":["date","utilization","bookedEvents"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"utilization":{"description":"Utilization for this day (0-100%).","type":"number"},"bookedEvents":{"description":"Number of booked events on this day.","type":"number"}}}}},"required":["overallUtilization","totalSlots","bookedSlots","cancelledEvents","cancellationRate","byCalendar","dailyUtilization"]}}}}},"operationId":"getBffDashboardCalendar-utilization","tags":["Dashboard"],"summary":"Calendar utilization","description":"Returns calendar slot utilization metrics. Critical for service businesses, consultants, rentals, and booking-based models."}},"/bff/dashboard/unmatched-payments":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Unmatched payments analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Total value of unmatched transactions.","type":"number"},"transactionCount":{"description":"Number of unmatched transactions.","type":"number"},"agingBuckets":{"description":"Transactions grouped by age.","type":"object","required":["today","thisWeek","thisMonth","older"],"properties":{"today":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received today.","type":"number"},"count":{"description":"Count of transactions today.","type":"number"}}},"thisWeek":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received this week.","type":"number"},"count":{"description":"Count of transactions this week.","type":"number"}}},"thisMonth":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received this month.","type":"number"},"count":{"description":"Count of transactions this month.","type":"number"}}},"older":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount from older transactions.","type":"number"},"count":{"description":"Count of older transactions.","type":"number"}}}}},"recentTransactions":{"description":"Recent unmatched transactions (max 20).","type":"array","items":{"type":"object","required":["id","bankTransactionId","date","amount"],"properties":{"id":{"description":"Transaction ID.","type":"number"},"bankTransactionId":{"description":"Bank transaction reference.","type":"string"},"date":{"description":"Transaction date (YYYY-MM-DD).","type":"string"},"amount":{"description":"Transaction amount.","type":"number"},"variableSymbol":{"description":"Variable symbol if present.","type":"string"},"accountName":{"description":"Sender account name.","type":"string"},"message":{"description":"Transaction message.","type":"string"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalAmount","transactionCount","agingBuckets","recentTransactions","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Total value of unmatched transactions.","type":"number"},"transactionCount":{"description":"Number of unmatched transactions.","type":"number"},"agingBuckets":{"description":"Transactions grouped by age.","type":"object","required":["today","thisWeek","thisMonth","older"],"properties":{"today":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received today.","type":"number"},"count":{"description":"Count of transactions today.","type":"number"}}},"thisWeek":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received this week.","type":"number"},"count":{"description":"Count of transactions this week.","type":"number"}}},"thisMonth":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received this month.","type":"number"},"count":{"description":"Count of transactions this month.","type":"number"}}},"older":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount from older transactions.","type":"number"},"count":{"description":"Count of older transactions.","type":"number"}}}}},"recentTransactions":{"description":"Recent unmatched transactions (max 20).","type":"array","items":{"type":"object","required":["id","bankTransactionId","date","amount"],"properties":{"id":{"description":"Transaction ID.","type":"number"},"bankTransactionId":{"description":"Bank transaction reference.","type":"string"},"date":{"description":"Transaction date (YYYY-MM-DD).","type":"string"},"amount":{"description":"Transaction amount.","type":"number"},"variableSymbol":{"description":"Variable symbol if present.","type":"string"},"accountName":{"description":"Sender account name.","type":"string"},"message":{"description":"Transaction message.","type":"string"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalAmount","transactionCount","agingBuckets","recentTransactions","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"totalAmount":{"description":"Total value of unmatched transactions.","type":"number"},"transactionCount":{"description":"Number of unmatched transactions.","type":"number"},"agingBuckets":{"description":"Transactions grouped by age.","type":"object","required":["today","thisWeek","thisMonth","older"],"properties":{"today":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received today.","type":"number"},"count":{"description":"Count of transactions today.","type":"number"}}},"thisWeek":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received this week.","type":"number"},"count":{"description":"Count of transactions this week.","type":"number"}}},"thisMonth":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount received this month.","type":"number"},"count":{"description":"Count of transactions this month.","type":"number"}}},"older":{"type":"object","required":["amount","count"],"properties":{"amount":{"description":"Amount from older transactions.","type":"number"},"count":{"description":"Count of older transactions.","type":"number"}}}}},"recentTransactions":{"description":"Recent unmatched transactions (max 20).","type":"array","items":{"type":"object","required":["id","bankTransactionId","date","amount"],"properties":{"id":{"description":"Transaction ID.","type":"number"},"bankTransactionId":{"description":"Bank transaction reference.","type":"string"},"date":{"description":"Transaction date (YYYY-MM-DD).","type":"string"},"amount":{"description":"Transaction amount.","type":"number"},"variableSymbol":{"description":"Variable symbol if present.","type":"string"},"accountName":{"description":"Sender account name.","type":"string"},"message":{"description":"Transaction message.","type":"string"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalAmount","transactionCount","agingBuckets","recentTransactions","currency"]}}}}},"operationId":"getBffDashboardUnmatched-payments","tags":["Dashboard"],"summary":"Unmatched bank payments","description":"Returns bank transactions not matched to any order. Critical for cash recovery - identifies failed variable symbols, gateway issues, and import errors."}},"/bff/dashboard/cash-flow":{"get":{"parameters":[{"description":"Number of months to analyze. Defaults to 6.","schema":{"type":"number","default":6},"in":"query","name":"months","required":false}],"responses":{"200":{"description":"Cash flow analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"currentMonth":{"type":"object","required":["invoiced","received","gap","collectionRate"],"properties":{"invoiced":{"description":"Total invoiced this month.","type":"number"},"received":{"description":"Total cash received this month.","type":"number"},"gap":{"description":"Difference between invoiced and received.","type":"number"},"collectionRate":{"description":"Collection rate (0-100%).","type":"number"}}},"pendingInvoices":{"description":"Total value of unpaid invoices.","type":"number"},"pendingOrders":{"description":"Total value of unpaid orders.","type":"number"},"monthlyTrend":{"description":"Monthly cash flow trend.","type":"array","items":{"type":"object","required":["month","invoiced","received","gap"],"properties":{"month":{"description":"Month (YYYY-MM).","type":"string"},"invoiced":{"description":"Amount invoiced.","type":"number"},"received":{"description":"Amount received.","type":"number"},"gap":{"description":"Cash flow gap.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["currentMonth","pendingInvoices","pendingOrders","monthlyTrend","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"currentMonth":{"type":"object","required":["invoiced","received","gap","collectionRate"],"properties":{"invoiced":{"description":"Total invoiced this month.","type":"number"},"received":{"description":"Total cash received this month.","type":"number"},"gap":{"description":"Difference between invoiced and received.","type":"number"},"collectionRate":{"description":"Collection rate (0-100%).","type":"number"}}},"pendingInvoices":{"description":"Total value of unpaid invoices.","type":"number"},"pendingOrders":{"description":"Total value of unpaid orders.","type":"number"},"monthlyTrend":{"description":"Monthly cash flow trend.","type":"array","items":{"type":"object","required":["month","invoiced","received","gap"],"properties":{"month":{"description":"Month (YYYY-MM).","type":"string"},"invoiced":{"description":"Amount invoiced.","type":"number"},"received":{"description":"Amount received.","type":"number"},"gap":{"description":"Cash flow gap.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["currentMonth","pendingInvoices","pendingOrders","monthlyTrend","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"currentMonth":{"type":"object","required":["invoiced","received","gap","collectionRate"],"properties":{"invoiced":{"description":"Total invoiced this month.","type":"number"},"received":{"description":"Total cash received this month.","type":"number"},"gap":{"description":"Difference between invoiced and received.","type":"number"},"collectionRate":{"description":"Collection rate (0-100%).","type":"number"}}},"pendingInvoices":{"description":"Total value of unpaid invoices.","type":"number"},"pendingOrders":{"description":"Total value of unpaid orders.","type":"number"},"monthlyTrend":{"description":"Monthly cash flow trend.","type":"array","items":{"type":"object","required":["month","invoiced","received","gap"],"properties":{"month":{"description":"Month (YYYY-MM).","type":"string"},"invoiced":{"description":"Amount invoiced.","type":"number"},"received":{"description":"Amount received.","type":"number"},"gap":{"description":"Cash flow gap.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["currentMonth","pendingInvoices","pendingOrders","monthlyTrend","currency"]}}}}},"operationId":"getBffDashboardCash-flow","tags":["Dashboard"],"summary":"Cash flow overview","description":"Compares invoiced amounts vs actual cash received. Essential for financial planning - invoices ≠ cash in hand."}},"/bff/dashboard/payment-methods":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Payment methods analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"totalOrders":{"description":"Total paid orders.","type":"number"},"totalRevenue":{"description":"Total revenue.","type":"number"},"methods":{"description":"Payment methods breakdown.","type":"array","items":{"type":"object","required":["methodId","methodCode","methodName","orderCount","revenue","avgOrderValue","orderPercentage","revenuePercentage"],"properties":{"methodId":{"description":"Payment method ID.","type":"number"},"methodCode":{"description":"Payment method code.","type":"string"},"methodName":{"description":"Payment method name.","type":"string"},"orderCount":{"description":"Orders using this method.","type":"number"},"revenue":{"description":"Revenue from this method.","type":"number"},"avgOrderValue":{"description":"Average order value.","type":"number"},"orderPercentage":{"description":"Percentage of orders (0-100).","type":"number"},"revenuePercentage":{"description":"Percentage of revenue (0-100).","type":"number"}}}},"gateways":{"description":"Online gateway performance.","type":"array","items":{"type":"object","required":["gatewayCode","gatewayName","paymentCount","successCount","successRate"],"properties":{"gatewayCode":{"description":"Gateway code.","type":"string"},"gatewayName":{"description":"Gateway name.","type":"string"},"paymentCount":{"description":"Total payment attempts.","type":"number"},"successCount":{"description":"Successful payments.","type":"number"},"successRate":{"description":"Success rate (0-100%).","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalOrders","totalRevenue","methods","gateways","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalOrders":{"description":"Total paid orders.","type":"number"},"totalRevenue":{"description":"Total revenue.","type":"number"},"methods":{"description":"Payment methods breakdown.","type":"array","items":{"type":"object","required":["methodId","methodCode","methodName","orderCount","revenue","avgOrderValue","orderPercentage","revenuePercentage"],"properties":{"methodId":{"description":"Payment method ID.","type":"number"},"methodCode":{"description":"Payment method code.","type":"string"},"methodName":{"description":"Payment method name.","type":"string"},"orderCount":{"description":"Orders using this method.","type":"number"},"revenue":{"description":"Revenue from this method.","type":"number"},"avgOrderValue":{"description":"Average order value.","type":"number"},"orderPercentage":{"description":"Percentage of orders (0-100).","type":"number"},"revenuePercentage":{"description":"Percentage of revenue (0-100).","type":"number"}}}},"gateways":{"description":"Online gateway performance.","type":"array","items":{"type":"object","required":["gatewayCode","gatewayName","paymentCount","successCount","successRate"],"properties":{"gatewayCode":{"description":"Gateway code.","type":"string"},"gatewayName":{"description":"Gateway name.","type":"string"},"paymentCount":{"description":"Total payment attempts.","type":"number"},"successCount":{"description":"Successful payments.","type":"number"},"successRate":{"description":"Success rate (0-100%).","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalOrders","totalRevenue","methods","gateways","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"totalOrders":{"description":"Total paid orders.","type":"number"},"totalRevenue":{"description":"Total revenue.","type":"number"},"methods":{"description":"Payment methods breakdown.","type":"array","items":{"type":"object","required":["methodId","methodCode","methodName","orderCount","revenue","avgOrderValue","orderPercentage","revenuePercentage"],"properties":{"methodId":{"description":"Payment method ID.","type":"number"},"methodCode":{"description":"Payment method code.","type":"string"},"methodName":{"description":"Payment method name.","type":"string"},"orderCount":{"description":"Orders using this method.","type":"number"},"revenue":{"description":"Revenue from this method.","type":"number"},"avgOrderValue":{"description":"Average order value.","type":"number"},"orderPercentage":{"description":"Percentage of orders (0-100).","type":"number"},"revenuePercentage":{"description":"Percentage of revenue (0-100).","type":"number"}}}},"gateways":{"description":"Online gateway performance.","type":"array","items":{"type":"object","required":["gatewayCode","gatewayName","paymentCount","successCount","successRate"],"properties":{"gatewayCode":{"description":"Gateway code.","type":"string"},"gatewayName":{"description":"Gateway name.","type":"string"},"paymentCount":{"description":"Total payment attempts.","type":"number"},"successCount":{"description":"Successful payments.","type":"number"},"successRate":{"description":"Success rate (0-100%).","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalOrders","totalRevenue","methods","gateways","currency"]}}}}},"operationId":"getBffDashboardPayment-methods","tags":["Dashboard"],"summary":"Payment methods popularity","description":"Shows which payment methods customers prefer. Helps optimize conversion and reduce gateway fees by focusing on efficient methods."}},"/bff/dashboard/order-funnel":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Order funnel analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"stages":{"type":"object","required":["cartsCreated","cartsWithItems","ordersCreated","ordersPaid","ordersCompleted","ordersCancelled"],"properties":{"cartsCreated":{"description":"Total carts created.","type":"number"},"cartsWithItems":{"description":"Carts with at least one item.","type":"number"},"ordersCreated":{"description":"Orders created from carts.","type":"number"},"ordersPaid":{"description":"Orders successfully paid.","type":"number"},"ordersCompleted":{"description":"Orders marked as completed.","type":"number"},"ordersCancelled":{"description":"Orders cancelled/storno.","type":"number"}}},"conversionRates":{"type":"object","required":["cartToOrder","orderToPaid","paidToCompleted","overallConversion","cancellationRate"],"properties":{"cartToOrder":{"description":"Cart to order conversion (0-100%).","type":"number"},"orderToPaid":{"description":"Order to paid conversion (0-100%).","type":"number"},"paidToCompleted":{"description":"Paid to completed rate (0-100%).","type":"number"},"overallConversion":{"description":"Cart to paid overall (0-100%).","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}},"abandonedByStatus":{"description":"Abandoned orders by status.","type":"array","items":{"type":"object","required":["statusCode","statusLabel","count"],"properties":{"statusCode":{"description":"Order status code.","type":"string"},"statusLabel":{"description":"Status label.","type":"string"},"count":{"description":"Number of abandoned orders.","type":"number"}}}},"dailyTrend":{"description":"Daily conversion trend.","type":"array","items":{"type":"object","required":["date","ordersCreated","ordersPaid","conversionRate"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"ordersCreated":{"description":"Orders created.","type":"number"},"ordersPaid":{"description":"Orders paid.","type":"number"},"conversionRate":{"description":"Daily conversion rate (0-100%).","type":"number"}}}}},"required":["stages","conversionRates","abandonedByStatus","dailyTrend"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"stages":{"type":"object","required":["cartsCreated","cartsWithItems","ordersCreated","ordersPaid","ordersCompleted","ordersCancelled"],"properties":{"cartsCreated":{"description":"Total carts created.","type":"number"},"cartsWithItems":{"description":"Carts with at least one item.","type":"number"},"ordersCreated":{"description":"Orders created from carts.","type":"number"},"ordersPaid":{"description":"Orders successfully paid.","type":"number"},"ordersCompleted":{"description":"Orders marked as completed.","type":"number"},"ordersCancelled":{"description":"Orders cancelled/storno.","type":"number"}}},"conversionRates":{"type":"object","required":["cartToOrder","orderToPaid","paidToCompleted","overallConversion","cancellationRate"],"properties":{"cartToOrder":{"description":"Cart to order conversion (0-100%).","type":"number"},"orderToPaid":{"description":"Order to paid conversion (0-100%).","type":"number"},"paidToCompleted":{"description":"Paid to completed rate (0-100%).","type":"number"},"overallConversion":{"description":"Cart to paid overall (0-100%).","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}},"abandonedByStatus":{"description":"Abandoned orders by status.","type":"array","items":{"type":"object","required":["statusCode","statusLabel","count"],"properties":{"statusCode":{"description":"Order status code.","type":"string"},"statusLabel":{"description":"Status label.","type":"string"},"count":{"description":"Number of abandoned orders.","type":"number"}}}},"dailyTrend":{"description":"Daily conversion trend.","type":"array","items":{"type":"object","required":["date","ordersCreated","ordersPaid","conversionRate"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"ordersCreated":{"description":"Orders created.","type":"number"},"ordersPaid":{"description":"Orders paid.","type":"number"},"conversionRate":{"description":"Daily conversion rate (0-100%).","type":"number"}}}}},"required":["stages","conversionRates","abandonedByStatus","dailyTrend"]}},"text/plain":{"schema":{"type":"object","properties":{"stages":{"type":"object","required":["cartsCreated","cartsWithItems","ordersCreated","ordersPaid","ordersCompleted","ordersCancelled"],"properties":{"cartsCreated":{"description":"Total carts created.","type":"number"},"cartsWithItems":{"description":"Carts with at least one item.","type":"number"},"ordersCreated":{"description":"Orders created from carts.","type":"number"},"ordersPaid":{"description":"Orders successfully paid.","type":"number"},"ordersCompleted":{"description":"Orders marked as completed.","type":"number"},"ordersCancelled":{"description":"Orders cancelled/storno.","type":"number"}}},"conversionRates":{"type":"object","required":["cartToOrder","orderToPaid","paidToCompleted","overallConversion","cancellationRate"],"properties":{"cartToOrder":{"description":"Cart to order conversion (0-100%).","type":"number"},"orderToPaid":{"description":"Order to paid conversion (0-100%).","type":"number"},"paidToCompleted":{"description":"Paid to completed rate (0-100%).","type":"number"},"overallConversion":{"description":"Cart to paid overall (0-100%).","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}},"abandonedByStatus":{"description":"Abandoned orders by status.","type":"array","items":{"type":"object","required":["statusCode","statusLabel","count"],"properties":{"statusCode":{"description":"Order status code.","type":"string"},"statusLabel":{"description":"Status label.","type":"string"},"count":{"description":"Number of abandoned orders.","type":"number"}}}},"dailyTrend":{"description":"Daily conversion trend.","type":"array","items":{"type":"object","required":["date","ordersCreated","ordersPaid","conversionRate"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"ordersCreated":{"description":"Orders created.","type":"number"},"ordersPaid":{"description":"Orders paid.","type":"number"},"conversionRate":{"description":"Daily conversion rate (0-100%).","type":"number"}}}}},"required":["stages","conversionRates","abandonedByStatus","dailyTrend"]}}}}},"operationId":"getBffDashboardOrder-funnel","tags":["Dashboard"],"summary":"Order conversion funnel","description":"Shows conversion rates at each stage: cart → order → paid → completed. Identifies where UX or system issues lose money."}},"/bff/dashboard/voucher-performance":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Voucher performance analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["ordersWithVoucher","ordersTotal","voucherUsageRate","revenueWithVoucher","revenueTotal","totalDiscount","avgDiscountPerOrder"],"properties":{"ordersWithVoucher":{"description":"Orders using a voucher.","type":"number"},"ordersTotal":{"description":"Total paid orders.","type":"number"},"voucherUsageRate":{"description":"Voucher usage rate (0-100%).","type":"number"},"revenueWithVoucher":{"description":"Revenue from voucher orders.","type":"number"},"revenueTotal":{"description":"Total revenue.","type":"number"},"totalDiscount":{"description":"Total discount amount given.","type":"number"},"avgDiscountPerOrder":{"description":"Average discount per order.","type":"number"}}},"topVouchers":{"description":"Top 10 vouchers by usage.","type":"array","items":{"type":"object","required":["voucherId","voucherCode","voucherType","voucherValue","usageCount","revenue"],"properties":{"voucherId":{"description":"Voucher ID.","type":"number"},"voucherCode":{"description":"Voucher code.","type":"string"},"voucherType":{"description":"Voucher type name.","type":"string"},"voucherValue":{"description":"Voucher value.","type":"string"},"usageCount":{"description":"Times used.","type":"number"},"revenue":{"description":"Revenue from orders with this voucher.","type":"number"}}}},"byType":{"description":"Vouchers grouped by type.","type":"array","items":{"type":"object","required":["typeId","typeName","usageCount","revenue"],"properties":{"typeId":{"description":"Voucher type ID.","type":"number"},"typeName":{"description":"Voucher type name.","type":"string"},"usageCount":{"description":"Usage count.","type":"number"},"revenue":{"description":"Revenue generated.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","topVouchers","byType","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["ordersWithVoucher","ordersTotal","voucherUsageRate","revenueWithVoucher","revenueTotal","totalDiscount","avgDiscountPerOrder"],"properties":{"ordersWithVoucher":{"description":"Orders using a voucher.","type":"number"},"ordersTotal":{"description":"Total paid orders.","type":"number"},"voucherUsageRate":{"description":"Voucher usage rate (0-100%).","type":"number"},"revenueWithVoucher":{"description":"Revenue from voucher orders.","type":"number"},"revenueTotal":{"description":"Total revenue.","type":"number"},"totalDiscount":{"description":"Total discount amount given.","type":"number"},"avgDiscountPerOrder":{"description":"Average discount per order.","type":"number"}}},"topVouchers":{"description":"Top 10 vouchers by usage.","type":"array","items":{"type":"object","required":["voucherId","voucherCode","voucherType","voucherValue","usageCount","revenue"],"properties":{"voucherId":{"description":"Voucher ID.","type":"number"},"voucherCode":{"description":"Voucher code.","type":"string"},"voucherType":{"description":"Voucher type name.","type":"string"},"voucherValue":{"description":"Voucher value.","type":"string"},"usageCount":{"description":"Times used.","type":"number"},"revenue":{"description":"Revenue from orders with this voucher.","type":"number"}}}},"byType":{"description":"Vouchers grouped by type.","type":"array","items":{"type":"object","required":["typeId","typeName","usageCount","revenue"],"properties":{"typeId":{"description":"Voucher type ID.","type":"number"},"typeName":{"description":"Voucher type name.","type":"string"},"usageCount":{"description":"Usage count.","type":"number"},"revenue":{"description":"Revenue generated.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","topVouchers","byType","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["ordersWithVoucher","ordersTotal","voucherUsageRate","revenueWithVoucher","revenueTotal","totalDiscount","avgDiscountPerOrder"],"properties":{"ordersWithVoucher":{"description":"Orders using a voucher.","type":"number"},"ordersTotal":{"description":"Total paid orders.","type":"number"},"voucherUsageRate":{"description":"Voucher usage rate (0-100%).","type":"number"},"revenueWithVoucher":{"description":"Revenue from voucher orders.","type":"number"},"revenueTotal":{"description":"Total revenue.","type":"number"},"totalDiscount":{"description":"Total discount amount given.","type":"number"},"avgDiscountPerOrder":{"description":"Average discount per order.","type":"number"}}},"topVouchers":{"description":"Top 10 vouchers by usage.","type":"array","items":{"type":"object","required":["voucherId","voucherCode","voucherType","voucherValue","usageCount","revenue"],"properties":{"voucherId":{"description":"Voucher ID.","type":"number"},"voucherCode":{"description":"Voucher code.","type":"string"},"voucherType":{"description":"Voucher type name.","type":"string"},"voucherValue":{"description":"Voucher value.","type":"string"},"usageCount":{"description":"Times used.","type":"number"},"revenue":{"description":"Revenue from orders with this voucher.","type":"number"}}}},"byType":{"description":"Vouchers grouped by type.","type":"array","items":{"type":"object","required":["typeId","typeName","usageCount","revenue"],"properties":{"typeId":{"description":"Voucher type ID.","type":"number"},"typeName":{"description":"Voucher type name.","type":"string"},"usageCount":{"description":"Usage count.","type":"number"},"revenue":{"description":"Revenue generated.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","topVouchers","byType","currency"]}}}}},"operationId":"getBffDashboardVoucher-performance","tags":["Dashboard"],"summary":"Voucher/discount code performance","description":"Analyzes effectiveness of discount codes. Shows whether vouchers drive revenue or just burn margin."}},"/bff/dashboard/inactive-customers":{"get":{"parameters":[{"description":"Days without order to be considered inactive. Defaults to 90.","schema":{"type":"number","default":90},"in":"query","name":"inactiveDays","required":false}],"responses":{"200":{"description":"Inactive customers analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalCustomers","activeCustomers","inactiveCustomers","inactivityRate","inactiveRevenuePotential"],"properties":{"totalCustomers":{"description":"Total customers.","type":"number"},"activeCustomers":{"description":"Customers who ordered recently.","type":"number"},"inactiveCustomers":{"description":"Customers inactive for the threshold period.","type":"number"},"inactivityRate":{"description":"Inactivity rate (0-100%).","type":"number"},"inactiveRevenuePotential":{"description":"Estimated revenue potential from reactivation.","type":"number"}}},"bySegment":{"description":"Inactive customers by segment.","type":"array","items":{"type":"object","required":["segment","segmentLabel","customerCount","avgLifetimeValue","avgOrders"],"properties":{"segment":{"description":"Segment code.","type":"string"},"segmentLabel":{"description":"Segment label.","type":"string"},"customerCount":{"description":"Customers in segment.","type":"number"},"avgLifetimeValue":{"description":"Average lifetime value.","type":"number"},"avgOrders":{"description":"Average order count.","type":"number"}}}},"topInactiveCustomers":{"description":"Top 20 inactive customers by value.","type":"array","items":{"type":"object","required":["customerId","externalId","customerName","email","orderCount","totalSpent"],"properties":{"customerId":{"description":"Customer ID.","type":"number"},"externalId":{"description":"External customer ID.","type":"string"},"customerName":{"description":"Customer name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts — UI should fall back to `customerName` or `externalId`.","type":"string"},{"type":"null"}]},"lastOrderDate":{"description":"Last order date.","type":"string"},"orderCount":{"description":"Total orders.","type":"number"},"totalSpent":{"description":"Total amount spent.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","bySegment","topInactiveCustomers","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalCustomers","activeCustomers","inactiveCustomers","inactivityRate","inactiveRevenuePotential"],"properties":{"totalCustomers":{"description":"Total customers.","type":"number"},"activeCustomers":{"description":"Customers who ordered recently.","type":"number"},"inactiveCustomers":{"description":"Customers inactive for the threshold period.","type":"number"},"inactivityRate":{"description":"Inactivity rate (0-100%).","type":"number"},"inactiveRevenuePotential":{"description":"Estimated revenue potential from reactivation.","type":"number"}}},"bySegment":{"description":"Inactive customers by segment.","type":"array","items":{"type":"object","required":["segment","segmentLabel","customerCount","avgLifetimeValue","avgOrders"],"properties":{"segment":{"description":"Segment code.","type":"string"},"segmentLabel":{"description":"Segment label.","type":"string"},"customerCount":{"description":"Customers in segment.","type":"number"},"avgLifetimeValue":{"description":"Average lifetime value.","type":"number"},"avgOrders":{"description":"Average order count.","type":"number"}}}},"topInactiveCustomers":{"description":"Top 20 inactive customers by value.","type":"array","items":{"type":"object","required":["customerId","externalId","customerName","email","orderCount","totalSpent"],"properties":{"customerId":{"description":"Customer ID.","type":"number"},"externalId":{"description":"External customer ID.","type":"string"},"customerName":{"description":"Customer name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts — UI should fall back to `customerName` or `externalId`.","type":"string"},{"type":"null"}]},"lastOrderDate":{"description":"Last order date.","type":"string"},"orderCount":{"description":"Total orders.","type":"number"},"totalSpent":{"description":"Total amount spent.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","bySegment","topInactiveCustomers","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalCustomers","activeCustomers","inactiveCustomers","inactivityRate","inactiveRevenuePotential"],"properties":{"totalCustomers":{"description":"Total customers.","type":"number"},"activeCustomers":{"description":"Customers who ordered recently.","type":"number"},"inactiveCustomers":{"description":"Customers inactive for the threshold period.","type":"number"},"inactivityRate":{"description":"Inactivity rate (0-100%).","type":"number"},"inactiveRevenuePotential":{"description":"Estimated revenue potential from reactivation.","type":"number"}}},"bySegment":{"description":"Inactive customers by segment.","type":"array","items":{"type":"object","required":["segment","segmentLabel","customerCount","avgLifetimeValue","avgOrders"],"properties":{"segment":{"description":"Segment code.","type":"string"},"segmentLabel":{"description":"Segment label.","type":"string"},"customerCount":{"description":"Customers in segment.","type":"number"},"avgLifetimeValue":{"description":"Average lifetime value.","type":"number"},"avgOrders":{"description":"Average order count.","type":"number"}}}},"topInactiveCustomers":{"description":"Top 20 inactive customers by value.","type":"array","items":{"type":"object","required":["customerId","externalId","customerName","email","orderCount","totalSpent"],"properties":{"customerId":{"description":"Customer ID.","type":"number"},"externalId":{"description":"External customer ID.","type":"string"},"customerName":{"description":"Customer name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts — UI should fall back to `customerName` or `externalId`.","type":"string"},{"type":"null"}]},"lastOrderDate":{"description":"Last order date.","type":"string"},"orderCount":{"description":"Total orders.","type":"number"},"totalSpent":{"description":"Total amount spent.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","bySegment","topInactiveCustomers","currency"]}}}}},"operationId":"getBffDashboardInactive-customers","tags":["Dashboard"],"summary":"Inactive customers","description":"Identifies customers who have not ordered recently. Perfect input for reactivation campaigns and retention efforts."}},"/bff/dashboard/brand-performance":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Brand performance analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"totalRevenue":{"description":"Total revenue.","type":"number"},"totalQuantity":{"description":"Total quantity sold.","type":"number"},"brands":{"description":"Top 20 brands by revenue.","type":"array","items":{"type":"object","required":["brandCode","brandName","revenue","quantity","orderCount","productCount","revenuePercentage","revenueChange"],"properties":{"brandId":{"description":"Brand ID. Null for unbranded.","type":"number"},"brandCode":{"description":"Brand code.","type":"string"},"brandName":{"description":"Brand name.","type":"string"},"revenue":{"description":"Revenue from this brand.","type":"number"},"quantity":{"description":"Quantity sold.","type":"number"},"orderCount":{"description":"Number of orders.","type":"number"},"productCount":{"description":"Number of products sold.","type":"number"},"revenuePercentage":{"description":"Revenue share (0-100%).","type":"number"},"revenueChange":{"description":"Revenue change vs previous period (%).","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalRevenue","totalQuantity","brands","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"totalRevenue":{"description":"Total revenue.","type":"number"},"totalQuantity":{"description":"Total quantity sold.","type":"number"},"brands":{"description":"Top 20 brands by revenue.","type":"array","items":{"type":"object","required":["brandCode","brandName","revenue","quantity","orderCount","productCount","revenuePercentage","revenueChange"],"properties":{"brandId":{"description":"Brand ID. Null for unbranded.","type":"number"},"brandCode":{"description":"Brand code.","type":"string"},"brandName":{"description":"Brand name.","type":"string"},"revenue":{"description":"Revenue from this brand.","type":"number"},"quantity":{"description":"Quantity sold.","type":"number"},"orderCount":{"description":"Number of orders.","type":"number"},"productCount":{"description":"Number of products sold.","type":"number"},"revenuePercentage":{"description":"Revenue share (0-100%).","type":"number"},"revenueChange":{"description":"Revenue change vs previous period (%).","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalRevenue","totalQuantity","brands","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"totalRevenue":{"description":"Total revenue.","type":"number"},"totalQuantity":{"description":"Total quantity sold.","type":"number"},"brands":{"description":"Top 20 brands by revenue.","type":"array","items":{"type":"object","required":["brandCode","brandName","revenue","quantity","orderCount","productCount","revenuePercentage","revenueChange"],"properties":{"brandId":{"description":"Brand ID. Null for unbranded.","type":"number"},"brandCode":{"description":"Brand code.","type":"string"},"brandName":{"description":"Brand name.","type":"string"},"revenue":{"description":"Revenue from this brand.","type":"number"},"quantity":{"description":"Quantity sold.","type":"number"},"orderCount":{"description":"Number of orders.","type":"number"},"productCount":{"description":"Number of products sold.","type":"number"},"revenuePercentage":{"description":"Revenue share (0-100%).","type":"number"},"revenueChange":{"description":"Revenue change vs previous period (%).","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["totalRevenue","totalQuantity","brands","currency"]}}}}},"operationId":"getBffDashboardBrand-performance","tags":["Dashboard"],"summary":"Brand performance","description":"Shows which brands generate revenue vs catalog noise. Critical for e-commerce product strategy and supplier negotiations."}},"/bff/dashboard/upcoming-renewals":{"get":{"parameters":[{"description":"Days ahead to check. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Upcoming renewals analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalRenewals","totalMrrAtRisk","autoRenewCount","manualRenewCount"],"properties":{"totalRenewals":{"description":"Total renewals in period.","type":"number"},"totalMrrAtRisk":{"description":"MRR value at risk.","type":"number"},"autoRenewCount":{"description":"Auto-renew subscriptions.","type":"number"},"manualRenewCount":{"description":"Manual renewal required.","type":"number"}}},"byTimeBucket":{"type":"object","required":["thisWeek","nextWeek","thisMonth","later"],"properties":{"thisWeek":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals this week.","type":"number"},"mrr":{"description":"MRR this week.","type":"number"}}},"nextWeek":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals next week.","type":"number"},"mrr":{"description":"MRR next week.","type":"number"}}},"thisMonth":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals this month.","type":"number"},"mrr":{"description":"MRR this month.","type":"number"}}},"later":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals later.","type":"number"},"mrr":{"description":"MRR later.","type":"number"}}}}},"renewals":{"description":"Upcoming renewals list (max 50).","type":"array","items":{"type":"object","required":["subscriptionId","externalId","customerName","customerEmail","productName","renewalDate","price","autoRenew","daysUntilRenewal"],"properties":{"subscriptionId":{"description":"Subscription ID.","type":"number"},"externalId":{"description":"External subscription ID.","type":"string"},"customerName":{"description":"Customer name.","type":"string"},"customerEmail":{"description":"Customer email.","type":"string"},"productName":{"description":"Subscription product.","type":"string"},"renewalDate":{"description":"Renewal date (YYYY-MM-DD).","type":"string"},"price":{"description":"Subscription price.","type":"number"},"autoRenew":{"description":"Auto-renew enabled.","type":"boolean"},"daysUntilRenewal":{"description":"Days until renewal.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","byTimeBucket","renewals","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalRenewals","totalMrrAtRisk","autoRenewCount","manualRenewCount"],"properties":{"totalRenewals":{"description":"Total renewals in period.","type":"number"},"totalMrrAtRisk":{"description":"MRR value at risk.","type":"number"},"autoRenewCount":{"description":"Auto-renew subscriptions.","type":"number"},"manualRenewCount":{"description":"Manual renewal required.","type":"number"}}},"byTimeBucket":{"type":"object","required":["thisWeek","nextWeek","thisMonth","later"],"properties":{"thisWeek":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals this week.","type":"number"},"mrr":{"description":"MRR this week.","type":"number"}}},"nextWeek":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals next week.","type":"number"},"mrr":{"description":"MRR next week.","type":"number"}}},"thisMonth":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals this month.","type":"number"},"mrr":{"description":"MRR this month.","type":"number"}}},"later":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals later.","type":"number"},"mrr":{"description":"MRR later.","type":"number"}}}}},"renewals":{"description":"Upcoming renewals list (max 50).","type":"array","items":{"type":"object","required":["subscriptionId","externalId","customerName","customerEmail","productName","renewalDate","price","autoRenew","daysUntilRenewal"],"properties":{"subscriptionId":{"description":"Subscription ID.","type":"number"},"externalId":{"description":"External subscription ID.","type":"string"},"customerName":{"description":"Customer name.","type":"string"},"customerEmail":{"description":"Customer email.","type":"string"},"productName":{"description":"Subscription product.","type":"string"},"renewalDate":{"description":"Renewal date (YYYY-MM-DD).","type":"string"},"price":{"description":"Subscription price.","type":"number"},"autoRenew":{"description":"Auto-renew enabled.","type":"boolean"},"daysUntilRenewal":{"description":"Days until renewal.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","byTimeBucket","renewals","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalRenewals","totalMrrAtRisk","autoRenewCount","manualRenewCount"],"properties":{"totalRenewals":{"description":"Total renewals in period.","type":"number"},"totalMrrAtRisk":{"description":"MRR value at risk.","type":"number"},"autoRenewCount":{"description":"Auto-renew subscriptions.","type":"number"},"manualRenewCount":{"description":"Manual renewal required.","type":"number"}}},"byTimeBucket":{"type":"object","required":["thisWeek","nextWeek","thisMonth","later"],"properties":{"thisWeek":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals this week.","type":"number"},"mrr":{"description":"MRR this week.","type":"number"}}},"nextWeek":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals next week.","type":"number"},"mrr":{"description":"MRR next week.","type":"number"}}},"thisMonth":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals this month.","type":"number"},"mrr":{"description":"MRR this month.","type":"number"}}},"later":{"type":"object","required":["count","mrr"],"properties":{"count":{"description":"Renewals later.","type":"number"},"mrr":{"description":"MRR later.","type":"number"}}}}},"renewals":{"description":"Upcoming renewals list (max 50).","type":"array","items":{"type":"object","required":["subscriptionId","externalId","customerName","customerEmail","productName","renewalDate","price","autoRenew","daysUntilRenewal"],"properties":{"subscriptionId":{"description":"Subscription ID.","type":"number"},"externalId":{"description":"External subscription ID.","type":"string"},"customerName":{"description":"Customer name.","type":"string"},"customerEmail":{"description":"Customer email.","type":"string"},"productName":{"description":"Subscription product.","type":"string"},"renewalDate":{"description":"Renewal date (YYYY-MM-DD).","type":"string"},"price":{"description":"Subscription price.","type":"number"},"autoRenew":{"description":"Auto-renew enabled.","type":"boolean"},"daysUntilRenewal":{"description":"Days until renewal.","type":"number"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","byTimeBucket","renewals","currency"]}}}}},"operationId":"getBffDashboardUpcoming-renewals","tags":["Dashboard"],"summary":"Upcoming subscription renewals","description":"Lists subscriptions due for renewal soon. Enables proactive churn prevention - better than reacting after the fact."}},"/bff/dashboard/cancelled-events":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Cancelled events analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalEvents","cancelledEvents","cancellationRate","lostRevenue"],"properties":{"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"},"lostRevenue":{"description":"Estimated lost revenue.","type":"number"}}},"byCalendar":{"description":"Cancellations by calendar.","type":"array","items":{"type":"object","required":["calendarId","calendarName","totalEvents","cancelledEvents","cancellationRate"],"properties":{"calendarId":{"description":"Calendar ID.","type":"number"},"calendarName":{"description":"Calendar name.","type":"string"},"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}}},"byDayOfWeek":{"description":"Cancellations by day of week.","type":"array","items":{"type":"object","required":["dayOfWeek","dayName","totalEvents","cancelledEvents","cancellationRate"],"properties":{"dayOfWeek":{"description":"Day of week (0=Sunday).","type":"number"},"dayName":{"description":"Day name.","type":"string"},"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}}},"recentCancellations":{"description":"Recent cancellations (max 20).","type":"array","items":{"type":"object","required":["eventId","eventTitle","calendarName","startTime"],"properties":{"eventId":{"description":"Event ID.","type":"number"},"eventTitle":{"description":"Event title.","type":"string"},"calendarName":{"description":"Calendar name.","type":"string"},"startTime":{"description":"Event start time (ISO).","type":"string"},"customerName":{"description":"Customer name.","type":"string"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","byCalendar","byDayOfWeek","recentCancellations","currency"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalEvents","cancelledEvents","cancellationRate","lostRevenue"],"properties":{"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"},"lostRevenue":{"description":"Estimated lost revenue.","type":"number"}}},"byCalendar":{"description":"Cancellations by calendar.","type":"array","items":{"type":"object","required":["calendarId","calendarName","totalEvents","cancelledEvents","cancellationRate"],"properties":{"calendarId":{"description":"Calendar ID.","type":"number"},"calendarName":{"description":"Calendar name.","type":"string"},"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}}},"byDayOfWeek":{"description":"Cancellations by day of week.","type":"array","items":{"type":"object","required":["dayOfWeek","dayName","totalEvents","cancelledEvents","cancellationRate"],"properties":{"dayOfWeek":{"description":"Day of week (0=Sunday).","type":"number"},"dayName":{"description":"Day name.","type":"string"},"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}}},"recentCancellations":{"description":"Recent cancellations (max 20).","type":"array","items":{"type":"object","required":["eventId","eventTitle","calendarName","startTime"],"properties":{"eventId":{"description":"Event ID.","type":"number"},"eventTitle":{"description":"Event title.","type":"string"},"calendarName":{"description":"Calendar name.","type":"string"},"startTime":{"description":"Event start time (ISO).","type":"string"},"customerName":{"description":"Customer name.","type":"string"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","byCalendar","byDayOfWeek","recentCancellations","currency"]}},"text/plain":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalEvents","cancelledEvents","cancellationRate","lostRevenue"],"properties":{"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"},"lostRevenue":{"description":"Estimated lost revenue.","type":"number"}}},"byCalendar":{"description":"Cancellations by calendar.","type":"array","items":{"type":"object","required":["calendarId","calendarName","totalEvents","cancelledEvents","cancellationRate"],"properties":{"calendarId":{"description":"Calendar ID.","type":"number"},"calendarName":{"description":"Calendar name.","type":"string"},"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}}},"byDayOfWeek":{"description":"Cancellations by day of week.","type":"array","items":{"type":"object","required":["dayOfWeek","dayName","totalEvents","cancelledEvents","cancellationRate"],"properties":{"dayOfWeek":{"description":"Day of week (0=Sunday).","type":"number"},"dayName":{"description":"Day name.","type":"string"},"totalEvents":{"description":"Total events.","type":"number"},"cancelledEvents":{"description":"Cancelled events.","type":"number"},"cancellationRate":{"description":"Cancellation rate (0-100%).","type":"number"}}}},"recentCancellations":{"description":"Recent cancellations (max 20).","type":"array","items":{"type":"object","required":["eventId","eventTitle","calendarName","startTime"],"properties":{"eventId":{"description":"Event ID.","type":"number"},"eventTitle":{"description":"Event title.","type":"string"},"calendarName":{"description":"Calendar name.","type":"string"},"startTime":{"description":"Event start time (ISO).","type":"string"},"customerName":{"description":"Customer name.","type":"string"}}}},"currency":{"description":"Currency code.","type":"string"}},"required":["summary","byCalendar","byDayOfWeek","recentCancellations","currency"]}}}}},"operationId":"getBffDashboardCancelled-events","tags":["Dashboard"],"summary":"Cancelled calendar events","description":"Analyzes event cancellations by calendar and day of week. For service businesses, reveals issues with pricing, capacity, or communication."}},"/bff/dashboard/email-stats":{"get":{"parameters":[{"description":"Number of days to analyze. Defaults to 30.","schema":{"type":"number","default":30},"in":"query","name":"days","required":false}],"responses":{"200":{"description":"Email statistics analysis.","content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalEmails","sentEmails","failedEmails","pendingEmails","openedEmails","deliveryRate","openRate"],"properties":{"totalEmails":{"description":"Total emails.","type":"number"},"sentEmails":{"description":"Successfully sent.","type":"number"},"failedEmails":{"description":"Failed to send.","type":"number"},"pendingEmails":{"description":"Pending/queued.","type":"number"},"openedEmails":{"description":"Opened emails.","type":"number"},"deliveryRate":{"description":"Delivery rate (0-100%).","type":"number"},"openRate":{"description":"Open rate (0-100%).","type":"number"}}},"byTag":{"description":"Stats by email type.","type":"array","items":{"type":"object","required":["tag","tagLabel","total","sent","failed","opened","deliveryRate","openRate"],"properties":{"tag":{"description":"Email tag/type.","type":"string"},"tagLabel":{"description":"Tag label.","type":"string"},"total":{"description":"Total emails.","type":"number"},"sent":{"description":"Sent emails.","type":"number"},"failed":{"description":"Failed emails.","type":"number"},"opened":{"description":"Opened emails.","type":"number"},"deliveryRate":{"description":"Delivery rate (0-100%).","type":"number"},"openRate":{"description":"Open rate (0-100%).","type":"number"}}}},"dailyTrend":{"description":"Daily email trend.","type":"array","items":{"type":"object","required":["date","sent","failed","opened"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"sent":{"description":"Sent count.","type":"number"},"failed":{"description":"Failed count.","type":"number"},"opened":{"description":"Opened count.","type":"number"}}}},"recentFailures":{"description":"Recent failed emails (max 20).","type":"array","items":{"type":"object","required":["emailId","externalId","subject","insertedDate","failedAttempts"],"properties":{"emailId":{"description":"Email ID.","type":"number"},"externalId":{"description":"External email ID.","type":"string"},"subject":{"description":"Email subject.","type":"string"},"insertedDate":{"description":"Creation date (ISO).","type":"string"},"failedAttempts":{"description":"Failed attempt count.","type":"number"}}}}},"required":["summary","byTag","dailyTrend","recentFailures"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalEmails","sentEmails","failedEmails","pendingEmails","openedEmails","deliveryRate","openRate"],"properties":{"totalEmails":{"description":"Total emails.","type":"number"},"sentEmails":{"description":"Successfully sent.","type":"number"},"failedEmails":{"description":"Failed to send.","type":"number"},"pendingEmails":{"description":"Pending/queued.","type":"number"},"openedEmails":{"description":"Opened emails.","type":"number"},"deliveryRate":{"description":"Delivery rate (0-100%).","type":"number"},"openRate":{"description":"Open rate (0-100%).","type":"number"}}},"byTag":{"description":"Stats by email type.","type":"array","items":{"type":"object","required":["tag","tagLabel","total","sent","failed","opened","deliveryRate","openRate"],"properties":{"tag":{"description":"Email tag/type.","type":"string"},"tagLabel":{"description":"Tag label.","type":"string"},"total":{"description":"Total emails.","type":"number"},"sent":{"description":"Sent emails.","type":"number"},"failed":{"description":"Failed emails.","type":"number"},"opened":{"description":"Opened emails.","type":"number"},"deliveryRate":{"description":"Delivery rate (0-100%).","type":"number"},"openRate":{"description":"Open rate (0-100%).","type":"number"}}}},"dailyTrend":{"description":"Daily email trend.","type":"array","items":{"type":"object","required":["date","sent","failed","opened"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"sent":{"description":"Sent count.","type":"number"},"failed":{"description":"Failed count.","type":"number"},"opened":{"description":"Opened count.","type":"number"}}}},"recentFailures":{"description":"Recent failed emails (max 20).","type":"array","items":{"type":"object","required":["emailId","externalId","subject","insertedDate","failedAttempts"],"properties":{"emailId":{"description":"Email ID.","type":"number"},"externalId":{"description":"External email ID.","type":"string"},"subject":{"description":"Email subject.","type":"string"},"insertedDate":{"description":"Creation date (ISO).","type":"string"},"failedAttempts":{"description":"Failed attempt count.","type":"number"}}}}},"required":["summary","byTag","dailyTrend","recentFailures"]}},"text/plain":{"schema":{"type":"object","properties":{"summary":{"type":"object","required":["totalEmails","sentEmails","failedEmails","pendingEmails","openedEmails","deliveryRate","openRate"],"properties":{"totalEmails":{"description":"Total emails.","type":"number"},"sentEmails":{"description":"Successfully sent.","type":"number"},"failedEmails":{"description":"Failed to send.","type":"number"},"pendingEmails":{"description":"Pending/queued.","type":"number"},"openedEmails":{"description":"Opened emails.","type":"number"},"deliveryRate":{"description":"Delivery rate (0-100%).","type":"number"},"openRate":{"description":"Open rate (0-100%).","type":"number"}}},"byTag":{"description":"Stats by email type.","type":"array","items":{"type":"object","required":["tag","tagLabel","total","sent","failed","opened","deliveryRate","openRate"],"properties":{"tag":{"description":"Email tag/type.","type":"string"},"tagLabel":{"description":"Tag label.","type":"string"},"total":{"description":"Total emails.","type":"number"},"sent":{"description":"Sent emails.","type":"number"},"failed":{"description":"Failed emails.","type":"number"},"opened":{"description":"Opened emails.","type":"number"},"deliveryRate":{"description":"Delivery rate (0-100%).","type":"number"},"openRate":{"description":"Open rate (0-100%).","type":"number"}}}},"dailyTrend":{"description":"Daily email trend.","type":"array","items":{"type":"object","required":["date","sent","failed","opened"],"properties":{"date":{"description":"Date (YYYY-MM-DD).","type":"string"},"sent":{"description":"Sent count.","type":"number"},"failed":{"description":"Failed count.","type":"number"},"opened":{"description":"Opened count.","type":"number"}}}},"recentFailures":{"description":"Recent failed emails (max 20).","type":"array","items":{"type":"object","required":["emailId","externalId","subject","insertedDate","failedAttempts"],"properties":{"emailId":{"description":"Email ID.","type":"number"},"externalId":{"description":"External email ID.","type":"string"},"subject":{"description":"Email subject.","type":"string"},"insertedDate":{"description":"Creation date (ISO).","type":"string"},"failedAttempts":{"description":"Failed attempt count.","type":"number"}}}}},"required":["summary","byTag","dailyTrend","recentFailures"]}}}}},"operationId":"getBffDashboardEmail-stats","tags":["Dashboard"],"summary":"System email statistics","description":"Shows health of transactional emails (invoices, notifications, password resets). Not marketing - critical system health indicator."}},"/bff/dev/translate-dictionaries":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"response":{"description":"Translation process result."}},"required":["success","response"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"response":{"description":"Translation process result."}},"required":["success","response"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"response":{"description":"Translation process result."}},"required":["success","response"]}}}}},"operationId":"getBffDevTranslate-dictionaries","tags":["Dev"],"summary":"Translate dictionaries","description":"Triggers dictionary translation process. Development-only endpoint."}},"/bff/doc/page":{"get":{"parameters":[{"description":"Documentation page slug.","examples":["getting-started"],"schema":{"type":"string"},"in":"query","name":"slug","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"operationId":"getBffDocPage","tags":["Documentation"],"summary":"Get documentation page","description":"Returns a documentation page by slug with locale fallback. If the requested locale translation does not exist, falls back to the first available translation. Content is rendered from Markdown to HTML with anchor list extraction. Returns { found: false } if the page does not exist, or { found: true, slug, locale, title, content, perex, anchorList, routes } on success.","responses":{"200":{}}}},"/bff/doc/list":{"get":{"parameters":[{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"description":"Categories sorted by position.","type":"array","items":{"type":"object","required":["id","name","articles"],"properties":{"id":{"description":"Category external ID for filtering/linking.","type":"string"},"name":{"description":"Localized category name.","type":"string"},"articles":{"description":"Articles in this category, sorted by position.","type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}}}},"uncategorized":{"description":"Articles without a category.","type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}},"required":["categories","uncategorized"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"categories":{"description":"Categories sorted by position.","type":"array","items":{"type":"object","required":["id","name","articles"],"properties":{"id":{"description":"Category external ID for filtering/linking.","type":"string"},"name":{"description":"Localized category name.","type":"string"},"articles":{"description":"Articles in this category, sorted by position.","type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}}}},"uncategorized":{"description":"Articles without a category.","type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}},"required":["categories","uncategorized"]}},"text/plain":{"schema":{"type":"object","properties":{"categories":{"description":"Categories sorted by position.","type":"array","items":{"type":"object","required":["id","name","articles"],"properties":{"id":{"description":"Category external ID for filtering/linking.","type":"string"},"name":{"description":"Localized category name.","type":"string"},"articles":{"description":"Articles in this category, sorted by position.","type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}}}},"uncategorized":{"description":"Articles without a category.","type":"array","items":{"type":"object","required":["slug","title","perex"],"properties":{"slug":{"description":"Article slug for navigation.","type":"string"},"title":{"description":"Article title.","type":"string"},"perex":{"description":"Short summary/teaser.","type":"string"}}}}},"required":["categories","uncategorized"]}}}}},"operationId":"getBffDocList","tags":["Documentation"],"summary":"List documentation pages grouped by category","description":"Returns all published documentation pages grouped by category for help-center navigation. Categories are sorted by position, articles within each category by position then publish date. Articles without a category are returned in a separate \"uncategorized\" array."}},"/bff/domain/list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of domains.","type":"number"},"items":{"description":"List of domain items.","type":"array","items":{"type":"object","required":["id","domainVerified"],"properties":{"id":{"description":"Domain identifier (domain name or fallback ID).","examples":["example.com"],"type":"string"},"domainVerified":{"description":"Whether domain ownership has been verified.","type":"boolean"},"environment":{"description":"Environment label (e.g. production, staging).","examples":["production"],"type":"string"},"label":{"description":"Custom label for the domain.","type":"string"},"description":{"description":"Custom description.","type":"string"},"domain":{"description":"Fully qualified domain name.","examples":["example.com"],"type":"string"},"insertedDate":{"description":"When the domain was first added.","anyOf":[{"description":"When the domain was first added.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastCheckDate":{"description":"Last health check timestamp.","anyOf":[{"description":"Last health check timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"httpCode":{"description":"Last HTTP status code.","examples":[200],"type":"number"},"httpsSupport":{"description":"Whether the domain supports HTTPS.","type":"boolean"},"title":{"description":"Page title from last crawl.","type":"string"},"responseTime":{"description":"Response time in milliseconds.","type":"number"},"uptimeOk":{"description":"Whether the domain is considered up.","type":"boolean"}}}}},"required":["itemCount","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of domains.","type":"number"},"items":{"description":"List of domain items.","type":"array","items":{"type":"object","required":["id","domainVerified"],"properties":{"id":{"description":"Domain identifier (domain name or fallback ID).","examples":["example.com"],"type":"string"},"domainVerified":{"description":"Whether domain ownership has been verified.","type":"boolean"},"environment":{"description":"Environment label (e.g. production, staging).","examples":["production"],"type":"string"},"label":{"description":"Custom label for the domain.","type":"string"},"description":{"description":"Custom description.","type":"string"},"domain":{"description":"Fully qualified domain name.","examples":["example.com"],"type":"string"},"insertedDate":{"description":"When the domain was first added.","anyOf":[{"description":"When the domain was first added.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastCheckDate":{"description":"Last health check timestamp.","anyOf":[{"description":"Last health check timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"httpCode":{"description":"Last HTTP status code.","examples":[200],"type":"number"},"httpsSupport":{"description":"Whether the domain supports HTTPS.","type":"boolean"},"title":{"description":"Page title from last crawl.","type":"string"},"responseTime":{"description":"Response time in milliseconds.","type":"number"},"uptimeOk":{"description":"Whether the domain is considered up.","type":"boolean"}}}}},"required":["itemCount","items"]}},"text/plain":{"schema":{"type":"object","properties":{"itemCount":{"description":"Total number of domains.","type":"number"},"items":{"description":"List of domain items.","type":"array","items":{"type":"object","required":["id","domainVerified"],"properties":{"id":{"description":"Domain identifier (domain name or fallback ID).","examples":["example.com"],"type":"string"},"domainVerified":{"description":"Whether domain ownership has been verified.","type":"boolean"},"environment":{"description":"Environment label (e.g. production, staging).","examples":["production"],"type":"string"},"label":{"description":"Custom label for the domain.","type":"string"},"description":{"description":"Custom description.","type":"string"},"domain":{"description":"Fully qualified domain name.","examples":["example.com"],"type":"string"},"insertedDate":{"description":"When the domain was first added.","anyOf":[{"description":"When the domain was first added.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastCheckDate":{"description":"Last health check timestamp.","anyOf":[{"description":"Last health check timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"httpCode":{"description":"Last HTTP status code.","examples":[200],"type":"number"},"httpsSupport":{"description":"Whether the domain supports HTTPS.","type":"boolean"},"title":{"description":"Page title from last crawl.","type":"string"},"responseTime":{"description":"Response time in milliseconds.","type":"number"},"uptimeOk":{"description":"Whether the domain is considered up.","type":"boolean"}}}}},"required":["itemCount","items"]}}}}},"operationId":"getBffDomainList","tags":["Domain"],"summary":"List organisation domains","description":"Returns all domains linked to the current organisation with their verification status, HTTP health and DNS information."}},"/bff/domain/show-verify-token":{"get":{"parameters":[{"description":"Domain name to get verification token for.","examples":["example.com"],"schema":{"type":"string"},"in":"query","name":"domain","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"verifyToken":{"description":"Raw verification token.","examples":["abc123def456"],"type":"string"},"dnsHeader":{"description":"Full DNS TXT record value to set.","examples":["brj-verify=abc123def456"],"type":"string"}},"required":["verifyToken","dnsHeader"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"verifyToken":{"description":"Raw verification token.","examples":["abc123def456"],"type":"string"},"dnsHeader":{"description":"Full DNS TXT record value to set.","examples":["brj-verify=abc123def456"],"type":"string"}},"required":["verifyToken","dnsHeader"]}},"text/plain":{"schema":{"type":"object","properties":{"verifyToken":{"description":"Raw verification token.","examples":["abc123def456"],"type":"string"},"dnsHeader":{"description":"Full DNS TXT record value to set.","examples":["brj-verify=abc123def456"],"type":"string"}},"required":["verifyToken","dnsHeader"]}}}}},"operationId":"getBffDomainShow-verify-token","tags":["Domain"],"summary":"Show domain verification token","description":"Returns the verification token and DNS TXT record value needed to prove domain ownership."}},"/bff/domain/check-verify-token":{"get":{"parameters":[{"description":"Domain name to verify.","examples":["example.com"],"schema":{"type":"string"},"in":"query","name":"domain","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"True if the domain verification token was found in DNS.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"True if the domain verification token was found in DNS.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"True if the domain verification token was found in DNS.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffDomainCheck-verify-token","tags":["Domain"],"summary":"Check domain verification","description":"Checks whether the DNS TXT verification record is properly set for the given domain."}},"/bff/domain/add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"True if the domain was successfully added.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"True if the domain was successfully added.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"True if the domain was successfully added.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffDomainAdd","tags":["Domain"],"summary":"Add domain to organisation","description":"Registers a new domain for the current organisation. The domain must be verified separately via the verification flow.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"description":"Domain name to add to the organisation.","examples":["example.com"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"description":"Domain name to add to the organisation.","examples":["example.com"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"description":"Domain name to add to the organisation.","examples":["example.com"],"type":"string"}}}}}}}},"/bff/drive/list":{"get":{"parameters":[{"description":"Directory path to list. Defaults to root \"/\".","examples":["/","documents/invoices"],"schema":{"type":"string"},"in":"query","name":"path","required":false}],"responses":{"200":{"description":"Directory listing with folders, files, and recursive statistics.","content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"Current directory path.","type":"string"},"folderList":{"description":"List of subfolders in the current directory.","type":"array","items":{"type":"object","required":["name","itemsCount"],"properties":{"name":{"description":"Folder name.","type":"string"},"itemsCount":{"description":"Number of items in the folder.","type":"number"}}}},"fileList":{"description":"List of files in the current directory.","type":"array","items":{"type":"object","required":["id","filename","size","insertedDate"],"properties":{"id":{"description":"Unique file token.","type":"string"},"filename":{"description":"File name.","type":"string"},"size":{"description":"File size in bytes.","type":"number"},"insertedDate":{"description":"Date when the file was uploaded (ISO format).","type":"string"}}}},"totalFileCount":{"description":"Total number of files in directory (recursive).","type":"number"},"totalSize":{"description":"Total size of all files in bytes (recursive).","type":"number"},"totalSizeFormatted":{"description":"Human-readable total size (e.g., \"1.5 MB\").","type":"string"},"canDownload":{"description":"Whether the directory can be downloaded as ZIP (false if empty or too many files).","type":"boolean"}},"required":["path","folderList","fileList","totalFileCount","totalSize","totalSizeFormatted","canDownload"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"path":{"description":"Current directory path.","type":"string"},"folderList":{"description":"List of subfolders in the current directory.","type":"array","items":{"type":"object","required":["name","itemsCount"],"properties":{"name":{"description":"Folder name.","type":"string"},"itemsCount":{"description":"Number of items in the folder.","type":"number"}}}},"fileList":{"description":"List of files in the current directory.","type":"array","items":{"type":"object","required":["id","filename","size","insertedDate"],"properties":{"id":{"description":"Unique file token.","type":"string"},"filename":{"description":"File name.","type":"string"},"size":{"description":"File size in bytes.","type":"number"},"insertedDate":{"description":"Date when the file was uploaded (ISO format).","type":"string"}}}},"totalFileCount":{"description":"Total number of files in directory (recursive).","type":"number"},"totalSize":{"description":"Total size of all files in bytes (recursive).","type":"number"},"totalSizeFormatted":{"description":"Human-readable total size (e.g., \"1.5 MB\").","type":"string"},"canDownload":{"description":"Whether the directory can be downloaded as ZIP (false if empty or too many files).","type":"boolean"}},"required":["path","folderList","fileList","totalFileCount","totalSize","totalSizeFormatted","canDownload"]}},"text/plain":{"schema":{"type":"object","properties":{"path":{"description":"Current directory path.","type":"string"},"folderList":{"description":"List of subfolders in the current directory.","type":"array","items":{"type":"object","required":["name","itemsCount"],"properties":{"name":{"description":"Folder name.","type":"string"},"itemsCount":{"description":"Number of items in the folder.","type":"number"}}}},"fileList":{"description":"List of files in the current directory.","type":"array","items":{"type":"object","required":["id","filename","size","insertedDate"],"properties":{"id":{"description":"Unique file token.","type":"string"},"filename":{"description":"File name.","type":"string"},"size":{"description":"File size in bytes.","type":"number"},"insertedDate":{"description":"Date when the file was uploaded (ISO format).","type":"string"}}}},"totalFileCount":{"description":"Total number of files in directory (recursive).","type":"number"},"totalSize":{"description":"Total size of all files in bytes (recursive).","type":"number"},"totalSizeFormatted":{"description":"Human-readable total size (e.g., \"1.5 MB\").","type":"string"},"canDownload":{"description":"Whether the directory can be downloaded as ZIP (false if empty or too many files).","type":"boolean"}},"required":["path","folderList","fileList","totalFileCount","totalSize","totalSizeFormatted","canDownload"]}}}}},"operationId":"getBffDriveList","tags":["Drive"],"summary":"List directory contents","description":"Returns a list of files and subfolders in the specified directory path, together with recursive directory statistics (total file count, size). Use this endpoint to browse the file storage structure and to show download preview."}},"/bff/drive/download-directory":{"get":{"parameters":[{"description":"Directory path to download. Defaults to root \"/\" which downloads all files.","examples":["/","documents"],"schema":{"type":"string"},"in":"query","name":"path","required":false}],"operationId":"getBffDriveDownload-directory","tags":["Drive"],"summary":"Download directory as ZIP","description":"Downloads all files from the specified directory (including subdirectories) as a ZIP archive. The ZIP includes a manifest file (_manifest.txt) with details about the export. Response headers include X-File-Count and X-Total-Size for progress indication.","responses":{"200":{}}}},"/bff/drive/detail":{"get":{"parameters":[{"description":"Unique file token.","examples":["aB3xKm9pQ2wLn4Yz"],"schema":{"type":"string"},"in":"query","name":"token","required":true}],"responses":{"200":{"description":"Complete file information.","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"description":"Unique file token.","type":"string"},"filename":{"description":"File name.","type":"string"},"extension":{"description":"File extension (e.g., \"pdf\", \"jpg\").","type":"string"},"size":{"description":"File size in bytes.","type":"number"},"sizeFormatted":{"description":"Human-readable file size (e.g., \"1.5 MB\").","type":"string"},"contentType":{"description":"MIME type (e.g., \"application/pdf\", \"image/jpeg\").","type":"string"},"tag":{"description":"File tag/category if assigned.","type":"string"},"insertedDate":{"description":"Date when the file was uploaded (ISO format).","type":"string"},"folderId":{"description":"Parent folder ID if file is in a folder.","type":"number"},"folderPath":{"description":"Full folder path (e.g., \"documents/invoices\").","type":"string"},"blobPath":{"description":"Internal storage path.","type":"string"},"downloadUrl":{"description":"Direct URL to download the file.","type":"string"},"viewUrl":{"description":"URL to view/stream the file content via the viewer endpoint.","type":"string"}},"required":["token","filename","size","sizeFormatted","contentType","insertedDate","blobPath","viewUrl"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"token":{"description":"Unique file token.","type":"string"},"filename":{"description":"File name.","type":"string"},"extension":{"description":"File extension (e.g., \"pdf\", \"jpg\").","type":"string"},"size":{"description":"File size in bytes.","type":"number"},"sizeFormatted":{"description":"Human-readable file size (e.g., \"1.5 MB\").","type":"string"},"contentType":{"description":"MIME type (e.g., \"application/pdf\", \"image/jpeg\").","type":"string"},"tag":{"description":"File tag/category if assigned.","type":"string"},"insertedDate":{"description":"Date when the file was uploaded (ISO format).","type":"string"},"folderId":{"description":"Parent folder ID if file is in a folder.","type":"number"},"folderPath":{"description":"Full folder path (e.g., \"documents/invoices\").","type":"string"},"blobPath":{"description":"Internal storage path.","type":"string"},"downloadUrl":{"description":"Direct URL to download the file.","type":"string"},"viewUrl":{"description":"URL to view/stream the file content via the viewer endpoint.","type":"string"}},"required":["token","filename","size","sizeFormatted","contentType","insertedDate","blobPath","viewUrl"]}},"text/plain":{"schema":{"type":"object","properties":{"token":{"description":"Unique file token.","type":"string"},"filename":{"description":"File name.","type":"string"},"extension":{"description":"File extension (e.g., \"pdf\", \"jpg\").","type":"string"},"size":{"description":"File size in bytes.","type":"number"},"sizeFormatted":{"description":"Human-readable file size (e.g., \"1.5 MB\").","type":"string"},"contentType":{"description":"MIME type (e.g., \"application/pdf\", \"image/jpeg\").","type":"string"},"tag":{"description":"File tag/category if assigned.","type":"string"},"insertedDate":{"description":"Date when the file was uploaded (ISO format).","type":"string"},"folderId":{"description":"Parent folder ID if file is in a folder.","type":"number"},"folderPath":{"description":"Full folder path (e.g., \"documents/invoices\").","type":"string"},"blobPath":{"description":"Internal storage path.","type":"string"},"downloadUrl":{"description":"Direct URL to download the file.","type":"string"},"viewUrl":{"description":"URL to view/stream the file content via the viewer endpoint.","type":"string"}},"required":["token","filename","size","sizeFormatted","contentType","insertedDate","blobPath","viewUrl"]}}}}},"operationId":"getBffDriveDetail","tags":["Drive"],"summary":"Get file detail","description":"Returns complete information about a file including metadata, URLs for download and viewing. Use this endpoint to get all data needed to display file details in the UI."}},"/bff/drive/viewer":{"get":{"parameters":[{"description":"Unique file token.","examples":["aB3xKm9pQ2wLn4Yz"],"schema":{"type":"string"},"in":"query","name":"token","required":true}],"operationId":"getBffDriveViewer","tags":["Drive"],"summary":"View/stream file content","description":"Proxies and streams the file content. Use this endpoint in iframes, img tags, or for direct file viewing. Returns the raw file bytes with appropriate Content-Type header.","responses":{"200":{}}}},"/bff/drive/rename":{"post":{"parameters":[],"responses":{"200":{"description":"Result of the rename operation.","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"description":"File token (unchanged).","type":"string"},"filename":{"description":"New sanitized filename (including extension).","type":"string"},"changed":{"description":"Whether the filename actually changed (false if same as before).","type":"boolean"}},"required":["token","filename","changed"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"token":{"description":"File token (unchanged).","type":"string"},"filename":{"description":"New sanitized filename (including extension).","type":"string"},"changed":{"description":"Whether the filename actually changed (false if same as before).","type":"boolean"}},"required":["token","filename","changed"]}},"text/plain":{"schema":{"type":"object","properties":{"token":{"description":"File token (unchanged).","type":"string"},"filename":{"description":"New sanitized filename (including extension).","type":"string"},"changed":{"description":"Whether the filename actually changed (false if same as before).","type":"boolean"}},"required":["token","filename","changed"]}}}}},"operationId":"postBffDriveRename","tags":["Drive"],"summary":"Rename a file","description":"Renames a file in the database only (the physical blob storage path is not changed). The file extension cannot be changed — it is validated against the original. The new name is sanitized to ASCII and must be unique within the same folder. The file is not moved to a different directory.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","filename"],"properties":{"token":{"description":"Unique file token identifying the file to rename.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"filename":{"minLength":1,"description":"New file name. Can be provided with or without extension. The original extension is always preserved — if a different extension is provided, the request is rejected. The name is automatically sanitized: converted to ASCII, lowercased, spaces replaced with hyphens, and invalid characters removed.","examples":["monthly-report","invoice-2026-03.pdf"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["token","filename"],"properties":{"token":{"description":"Unique file token identifying the file to rename.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"filename":{"minLength":1,"description":"New file name. Can be provided with or without extension. The original extension is always preserved — if a different extension is provided, the request is rejected. The name is automatically sanitized: converted to ASCII, lowercased, spaces replaced with hyphens, and invalid characters removed.","examples":["monthly-report","invoice-2026-03.pdf"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["token","filename"],"properties":{"token":{"description":"Unique file token identifying the file to rename.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"filename":{"minLength":1,"description":"New file name. Can be provided with or without extension. The original extension is always preserved — if a different extension is provided, the request is rejected. The name is automatically sanitized: converted to ASCII, lowercased, spaces replaced with hyphens, and invalid characters removed.","examples":["monthly-report","invoice-2026-03.pdf"],"type":"string"}}}}}}}},"/bff/drive/create-directory":{"post":{"parameters":[],"responses":{"200":{"description":"Created (or existing) directory information.","content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"description":"Unique external identifier of the created directory.","type":"string"},"name":{"description":"Name of the leaf directory.","type":"string"},"path":{"description":"Full normalized path of the created directory.","type":"string"}},"required":["externalId","name","path"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"externalId":{"description":"Unique external identifier of the created directory.","type":"string"},"name":{"description":"Name of the leaf directory.","type":"string"},"path":{"description":"Full normalized path of the created directory.","type":"string"}},"required":["externalId","name","path"]}},"text/plain":{"schema":{"type":"object","properties":{"externalId":{"description":"Unique external identifier of the created directory.","type":"string"},"name":{"description":"Name of the leaf directory.","type":"string"},"path":{"description":"Full normalized path of the created directory.","type":"string"}},"required":["externalId","name","path"]}}}}},"operationId":"postBffDriveCreate-directory","tags":["Drive"],"summary":"Create a new directory","description":"Creates a new directory (and any missing parent directories) at the specified path. If the directory already exists, returns the existing directory info without error. Directory names must be unique within their parent folder.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["path"],"properties":{"path":{"examples":["documents/invoices"],"description":"Full directory path to create. Segments separated by \"/\" will create nested directories. Each segment name must be unique within its parent directory.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["path"],"properties":{"path":{"examples":["documents/invoices"],"description":"Full directory path to create. Segments separated by \"/\" will create nested directories. Each segment name must be unique within its parent directory.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["path"],"properties":{"path":{"examples":["documents/invoices"],"description":"Full directory path to create. Segments separated by \"/\" will create nested directories. Each segment name must be unique within its parent directory.","type":"string"}}}}}}}},"/bff/ecommerce/company/detail":{"get":{"parameters":[{"description":"Company registration number (IČO) to look up.","examples":["05103118"],"schema":{"type":"string"},"in":"query","name":"ico","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"ico":{"description":"The IČO that was queried (lowercase).","examples":["05103118"],"type":"string"},"ares":{"description":"Structured company and address data from ARES."}},"required":["ico","ares"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"ico":{"description":"The IČO that was queried (lowercase).","examples":["05103118"],"type":"string"},"ares":{"description":"Structured company and address data from ARES."}},"required":["ico","ares"]}},"text/plain":{"schema":{"type":"object","properties":{"ico":{"description":"The IČO that was queried (lowercase).","examples":["05103118"],"type":"string"},"ares":{"description":"Structured company and address data from ARES."}},"required":["ico","ares"]}}}}},"operationId":"getBffEcommerceCompanyDetail","tags":["Ecommerce"],"summary":"Look up company by registration number","description":"Fetches company details from ARES (Czech business register) by IČO and returns structured address and company data."}},"/bff/ecommerce/vies/detail":{"get":{"parameters":[{"description":"EU VAT identifier including country prefix (e.g., \"SK2020317068\").","examples":["SK2020317068"],"schema":{"type":"string"},"in":"query","name":"vatId","required":true},{"description":"Set to \"true\" to bypass the 4-week cache and re-query VIES.","schema":{"type":"string"},"in":"query","name":"force","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"vatId":{"description":"The VAT ID that was queried.","type":"string"},"isValid":{"description":"True if VIES confirmed the VAT identifier.","type":"boolean"},"countryCode":{"description":"ISO 3166-1 alpha-2 country code (or \"EL\" for Greece in VIES).","type":"string"},"vatNumber":{"description":"VAT identifier without the country prefix.","type":"string"},"name":{"description":"Registered name as held by the member state.","type":"string"},"address":{"description":"Registered address (may contain newlines).","type":"string"},"requestDate":{"description":"ISO date when VIES queried the national registry.","type":"string"},"suggestReverseCharge":{"description":"UI hint: true when the contact qualifies for EU intra-community supply (valid non-CZ EU VAT ID).","type":"boolean"}},"required":["vatId","isValid","countryCode","vatNumber","suggestReverseCharge"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"vatId":{"description":"The VAT ID that was queried.","type":"string"},"isValid":{"description":"True if VIES confirmed the VAT identifier.","type":"boolean"},"countryCode":{"description":"ISO 3166-1 alpha-2 country code (or \"EL\" for Greece in VIES).","type":"string"},"vatNumber":{"description":"VAT identifier without the country prefix.","type":"string"},"name":{"description":"Registered name as held by the member state.","type":"string"},"address":{"description":"Registered address (may contain newlines).","type":"string"},"requestDate":{"description":"ISO date when VIES queried the national registry.","type":"string"},"suggestReverseCharge":{"description":"UI hint: true when the contact qualifies for EU intra-community supply (valid non-CZ EU VAT ID).","type":"boolean"}},"required":["vatId","isValid","countryCode","vatNumber","suggestReverseCharge"]}},"text/plain":{"schema":{"type":"object","properties":{"vatId":{"description":"The VAT ID that was queried.","type":"string"},"isValid":{"description":"True if VIES confirmed the VAT identifier.","type":"boolean"},"countryCode":{"description":"ISO 3166-1 alpha-2 country code (or \"EL\" for Greece in VIES).","type":"string"},"vatNumber":{"description":"VAT identifier without the country prefix.","type":"string"},"name":{"description":"Registered name as held by the member state.","type":"string"},"address":{"description":"Registered address (may contain newlines).","type":"string"},"requestDate":{"description":"ISO date when VIES queried the national registry.","type":"string"},"suggestReverseCharge":{"description":"UI hint: true when the contact qualifies for EU intra-community supply (valid non-CZ EU VAT ID).","type":"boolean"}},"required":["vatId","isValid","countryCode","vatNumber","suggestReverseCharge"]}}}}},"operationId":"getBffEcommerceViesDetail","tags":["Ecommerce"],"summary":"Look up EU VAT identifier via VIES","description":"Validates an EU VAT identifier through the VIES REST API and caches the result for 4 weeks. Returns the validity flag, registered name, address, the VIES request date, and a UI hint (`suggestReverseCharge`) that is true for valid non-CZ EU VAT IDs — the typical case where the admin should set the contact's `reverseCharge` flag."}},"/bff/emailer/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Filter by message status code.","schema":{"type":"string"},"in":"query","name":"status","required":false},{"description":"Filter by message tag.","schema":{"type":"string"},"in":"query","name":"tag","required":false},{"description":"Filter by recipient contact external ID.","schema":{"type":"string"},"in":"query","name":"emailToContactId","required":false}],"operationId":"getBffEmailerList","tags":["Emailer"],"summary":"List email messages","description":"Returns a paginated list of email messages for the current organisation with optional filters.","responses":{"200":{}}}},"/bff/emailer/received-list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffEmailerReceived-list","tags":["Emailer"],"summary":"List received e-mails","description":"Returns a paginated list of inbound e-mails pulled from Resend into the organisation mailbox.","responses":{"200":{}}}},"/bff/emailer/received-detail":{"get":{"parameters":[{"description":"Internal numeric ID of the received e-mail row.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffEmailerReceived-detail","tags":["Emailer"],"summary":"Get received e-mail detail","description":"Returns full detail of a single inbound e-mail including the HTML body fetched from blob storage and raw headers.","responses":{"200":{}}}},"/bff/emailer/detail":{"get":{"parameters":[{"description":"Email message ID.","examples":["abc123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffEmailerDetail","tags":["Emailer"],"summary":"Get email detail","description":"Returns full detail of a single email message including content and metadata.","responses":{"200":{}}}},"/bff/emailer/send":{"post":{"operationId":"postBffEmailerSend","tags":["Emailer"],"summary":"Send email","description":"Queues a new email for sending. The email payload is passed as raw JSON body.","responses":{"200":{}}}},"/bff/emailer/detail-log-explain":{"get":{"parameters":[{"description":"Email message ID to explain.","examples":["abc123"],"schema":{"type":"string"},"in":"query","name":"emailId","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"operationId":"getBffEmailerDetail-log-explain","tags":["Emailer"],"summary":"AI-explain email log entry","description":"Uses AI to generate a human-readable explanation of the email delivery log.","responses":{"200":{}}}},"/bff/emailer/status":{"get":{"operationId":"getBffEmailerStatus","tags":["Emailer"],"summary":"Get emailer status","description":"Returns whether SMTP is configured for the current organisation.","responses":{"200":{}}}},"/bff/emailer/send-now":{"get":{"parameters":[{"description":"Email message ID to send immediately.","examples":["abc123"],"schema":{"type":"string"},"in":"query","name":"emailId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffEmailerSend-now","tags":["Emailer"],"summary":"Send email immediately","description":"Bypasses the queue and sends the specified email right away."}},"/bff/emailer/send-again":{"get":{"parameters":[{"description":"Email message ID to re-send.","examples":["abc123"],"schema":{"type":"string"},"in":"query","name":"emailId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffEmailerSend-again","tags":["Emailer"],"summary":"Re-send email","description":"Re-sends a previously sent or failed email message."}},"/bff/emailer/smtp-info":{"get":{"operationId":"getBffEmailerSmtp-info","tags":["Emailer"],"summary":"Get SMTP configuration","description":"Returns the current SMTP server settings for the organisation.","responses":{"200":{}}}},"/bff/emailer/setup-smtp":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffEmailerSetup-smtp","tags":["Emailer"],"summary":"Configure SMTP settings","description":"Saves SMTP server configuration and sends a test email to verify connectivity.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["testAddress","host","port","from","authUser","authPassword"],"properties":{"testAddress":{"description":"Email address to send a test message to.","examples":["test@example.com"],"type":"string"},"host":{"description":"SMTP server hostname.","examples":["smtp.example.com"],"type":"string"},"port":{"description":"SMTP server port.","examples":["587"],"type":"string"},"from":{"description":"Sender email address (From header).","examples":["noreply@example.com"],"type":"string"},"authUser":{"description":"SMTP authentication username.","type":"string"},"authPassword":{"description":"SMTP authentication password.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["testAddress","host","port","from","authUser","authPassword"],"properties":{"testAddress":{"description":"Email address to send a test message to.","examples":["test@example.com"],"type":"string"},"host":{"description":"SMTP server hostname.","examples":["smtp.example.com"],"type":"string"},"port":{"description":"SMTP server port.","examples":["587"],"type":"string"},"from":{"description":"Sender email address (From header).","examples":["noreply@example.com"],"type":"string"},"authUser":{"description":"SMTP authentication username.","type":"string"},"authPassword":{"description":"SMTP authentication password.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["testAddress","host","port","from","authUser","authPassword"],"properties":{"testAddress":{"description":"Email address to send a test message to.","examples":["test@example.com"],"type":"string"},"host":{"description":"SMTP server hostname.","examples":["smtp.example.com"],"type":"string"},"port":{"description":"SMTP server port.","examples":["587"],"type":"string"},"from":{"description":"Sender email address (From header).","examples":["noreply@example.com"],"type":"string"},"authUser":{"description":"SMTP authentication username.","type":"string"},"authPassword":{"description":"SMTP authentication password.","type":"string"}}}}}}}},"/bff/emailer/statistics":{"get":{"operationId":"getBffEmailerStatistics","tags":["Emailer"],"summary":"Get email statistics","description":"Returns sending statistics and currently running newsletter jobs for the organisation.","responses":{"200":{}}}},"/bff/emailer/compose":{"post":{"parameters":[],"operationId":"postBffEmailerCompose","tags":["Emailer"],"summary":"Compose and send email","description":"Composes a new email with the given subject, message, and optional attachments, then sends it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["variant","subject","message"],"properties":{"variant":{"description":"Sending variant (e.g. single, bulk).","examples":["single"],"type":"string"},"contactList":{"description":"Comma-separated list of contact IDs to send to.","type":"string"},"subject":{"description":"Email subject line.","type":"string"},"message":{"description":"Email body content (HTML or plain text).","type":"string"},"attachmentTokens":{"description":"Optional list of blob tokens to attach to the e-mail. Blobs must belong to the same organisation as the request.","type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["variant","subject","message"],"properties":{"variant":{"description":"Sending variant (e.g. single, bulk).","examples":["single"],"type":"string"},"contactList":{"description":"Comma-separated list of contact IDs to send to.","type":"string"},"subject":{"description":"Email subject line.","type":"string"},"message":{"description":"Email body content (HTML or plain text).","type":"string"},"attachmentTokens":{"description":"Optional list of blob tokens to attach to the e-mail. Blobs must belong to the same organisation as the request.","type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["variant","subject","message"],"properties":{"variant":{"description":"Sending variant (e.g. single, bulk).","examples":["single"],"type":"string"},"contactList":{"description":"Comma-separated list of contact IDs to send to.","type":"string"},"subject":{"description":"Email subject line.","type":"string"},"message":{"description":"Email body content (HTML or plain text).","type":"string"},"attachmentTokens":{"description":"Optional list of blob tokens to attach to the e-mail. Blobs must belong to the same organisation as the request.","type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{}}}},"/bff/emailer/layout":{"get":{"operationId":"getBffEmailerLayout","tags":["Emailer"],"summary":"Get email layout","description":"Returns the current email layout settings including logo URL, footer HTML, and template HTML.","responses":{"200":{}}}},"/bff/emailer/layout-edit":{"post":{"parameters":[],"operationId":"postBffEmailerLayout-edit","tags":["Emailer"],"summary":"Update email layout","description":"Saves updated footer and template HTML for the organisation email layout.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"footer":{"description":"Footer HTML content for emails.","type":"string"},"template":{"description":"Base HTML template wrapping all emails.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"footer":{"description":"Footer HTML content for emails.","type":"string"},"template":{"description":"Base HTML template wrapping all emails.","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"footer":{"description":"Footer HTML content for emails.","type":"string"},"template":{"description":"Base HTML template wrapping all emails.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/emailer/layout-link-logo-blob":{"get":{"parameters":[{"description":"Blob storage token of the image to use as logo.","examples":["tok_abc123"],"schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"operationId":"getBffEmailerLayout-link-logo-blob","tags":["Emailer"],"summary":"Set logo from blob","description":"Links an uploaded image blob as the organisation logo used in email layouts.","responses":{"200":{}}}},"/bff/emailer/message-log":{"get":{"parameters":[{"description":"Email message ID to fetch logs for.","examples":["abc123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffEmailerMessage-log","tags":["Emailer"],"summary":"Get message delivery log","description":"Returns the delivery log entries for a specific email message.","responses":{"200":{}}}},"/bff/emailer/template-add":{"post":{"parameters":[],"operationId":"postBffEmailerTemplate-add","tags":["Emailer"],"summary":"Create email template","description":"Creates a new email template and optionally assigns it to an order group and status.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["templateTypeCode","templateCode","name","subject","locale"],"properties":{"templateTypeCode":{"description":"Template type code (e.g. order-confirmation).","examples":["order-confirmation"],"type":"string"},"templateCode":{"description":"Unique code identifier for the template.","examples":["order-confirmed-v1"],"type":"string"},"templateCodeVariant":{"description":"Optional variant suffix for the template code.","type":"string"},"name":{"description":"Human-readable template name.","examples":["Order Confirmation"],"type":"string"},"subject":{"description":"Default email subject line.","examples":["Your order has been confirmed"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"groupCode":{"description":"Order group code to auto-assign the template to.","type":"string"},"statusCode":{"description":"Order status code to auto-assign the template to.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["templateTypeCode","templateCode","name","subject","locale"],"properties":{"templateTypeCode":{"description":"Template type code (e.g. order-confirmation).","examples":["order-confirmation"],"type":"string"},"templateCode":{"description":"Unique code identifier for the template.","examples":["order-confirmed-v1"],"type":"string"},"templateCodeVariant":{"description":"Optional variant suffix for the template code.","type":"string"},"name":{"description":"Human-readable template name.","examples":["Order Confirmation"],"type":"string"},"subject":{"description":"Default email subject line.","examples":["Your order has been confirmed"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"groupCode":{"description":"Order group code to auto-assign the template to.","type":"string"},"statusCode":{"description":"Order status code to auto-assign the template to.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["templateTypeCode","templateCode","name","subject","locale"],"properties":{"templateTypeCode":{"description":"Template type code (e.g. order-confirmation).","examples":["order-confirmation"],"type":"string"},"templateCode":{"description":"Unique code identifier for the template.","examples":["order-confirmed-v1"],"type":"string"},"templateCodeVariant":{"description":"Optional variant suffix for the template code.","type":"string"},"name":{"description":"Human-readable template name.","examples":["Order Confirmation"],"type":"string"},"subject":{"description":"Default email subject line.","examples":["Your order has been confirmed"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"groupCode":{"description":"Order group code to auto-assign the template to.","type":"string"},"statusCode":{"description":"Order status code to auto-assign the template to.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/emailer/template-detail":{"get":{"parameters":[{"description":"Template code identifier.","examples":["order-confirmed-v1"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"operationId":"getBffEmailerTemplate-detail","tags":["Emailer"],"summary":"Get template detail","description":"Returns full detail of an email template including its content and metadata.","responses":{"200":{}}}},"/bff/emailer/template-edit":{"post":{"parameters":[],"operationId":"postBffEmailerTemplate-edit","tags":["Emailer"],"summary":"Update email template","description":"Updates the subject, content, and locale of an existing email template.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["templateCode","subject","template","locale"],"properties":{"templateCode":{"description":"Template code identifier to update.","examples":["order-confirmed-v1"],"type":"string"},"subject":{"description":"Updated email subject line.","type":"string"},"template":{"description":"Updated HTML template content.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["templateCode","subject","template","locale"],"properties":{"templateCode":{"description":"Template code identifier to update.","examples":["order-confirmed-v1"],"type":"string"},"subject":{"description":"Updated email subject line.","type":"string"},"template":{"description":"Updated HTML template content.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["templateCode","subject","template","locale"],"properties":{"templateCode":{"description":"Template code identifier to update.","examples":["order-confirmed-v1"],"type":"string"},"subject":{"description":"Updated email subject line.","type":"string"},"template":{"description":"Updated HTML template content.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/emailer/template-list":{"get":{"operationId":"getBffEmailerTemplate-list","tags":["Emailer"],"summary":"List email templates","description":"Returns all email templates for the current organisation.","responses":{"200":{}}}},"/bff/emailer/template-send-debug-email":{"post":{"parameters":[],"operationId":"postBffEmailerTemplate-send-debug-email","tags":["Emailer"],"summary":"Send debug template email","description":"Sends a test email using the specified template to the current user for debugging.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["templateCode"],"properties":{"templateCode":{"description":"Template code to send a debug email for.","examples":["order-confirmed-v1"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["templateCode"],"properties":{"templateCode":{"description":"Template code to send a debug email for.","examples":["order-confirmed-v1"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["templateCode"],"properties":{"templateCode":{"description":"Template code to send a debug email for.","examples":["order-confirmed-v1"],"type":"string"}}}}}},"responses":{"200":{}}}},"/bff/emailer/template-type-list":{"get":{"parameters":[{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"responses":{"200":{"description":"Template types response.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"List of available template types.","type":"array","items":{"description":"Template type item.","type":"object","required":["code","name"],"properties":{"code":{"description":"Unique template type code.","type":"string"},"name":{"description":"Localized template type name.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"List of available template types.","type":"array","items":{"description":"Template type item.","type":"object","required":["code","name"],"properties":{"code":{"description":"Unique template type code.","type":"string"},"name":{"description":"Localized template type name.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"List of available template types.","type":"array","items":{"description":"Template type item.","type":"object","required":["code","name"],"properties":{"code":{"description":"Unique template type code.","type":"string"},"name":{"description":"Localized template type name.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffEmailerTemplate-type-list","tags":["Emailer"],"summary":"List email template types","description":"Returns all available email template types with localized names. Use this to populate template type selectors in the admin UI."}},"/bff/emailer/template-variables":{"get":{"parameters":[{"description":"Template type code to resolve variables for.","examples":["order-confirmation"],"schema":{"type":"string"},"in":"query","name":"templateCode","required":true}],"operationId":"getBffEmailerTemplate-variables","tags":["Emailer"],"summary":"List template variables","description":"Returns available placeholder variables for the given template type code.","responses":{"200":{}}}},"/bff/firewall/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 100).","examples":["100"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Filter by rejection type code (e.g. \"tor\").","examples":["tor"],"schema":{"type":"string"},"in":"query","name":"typeCode","required":false},{"description":"Filter by category (network|identity|rate|content|fraud).","examples":["network"],"schema":{"type":"string"},"in":"query","name":"category","required":false}],"operationId":"getBffFirewallList","tags":["Firewall"],"summary":"List firewall rejections","description":"Returns a paginated list of firewall rejection events for the current organisation.","responses":{"200":{}}}},"/bff/firewall/stats":{"get":{"operationId":"getBffFirewallStats","tags":["Firewall"],"summary":"Firewall rejection statistics","description":"Returns aggregated rejection statistics (24h / 7d / 30d) by rule type and top countries.","responses":{"200":{}}}},"/bff/firewall/detail":{"get":{"parameters":[{"description":"Rejection external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffFirewallDetail","tags":["Firewall"],"summary":"Get firewall rejection detail","description":"Returns a single firewall rejection event with full context.","responses":{"200":{}}}},"/bff/form/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","active","recordCount","insertedDate","updatedDate"],"properties":{"id":{"description":"Form code (unique identifier within the organisation).","type":"string"},"name":{"description":"Form display name.","type":"string"},"description":{"description":"Form description.","type":"string"},"active":{"description":"Whether the form is active and accepting submissions.","type":"boolean"},"recordCount":{"description":"Number of submitted records.","type":"number"},"insertedDate":{"description":"When the form was created.","anyOf":[{"description":"When the form was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of forms (for pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","active","recordCount","insertedDate","updatedDate"],"properties":{"id":{"description":"Form code (unique identifier within the organisation).","type":"string"},"name":{"description":"Form display name.","type":"string"},"description":{"description":"Form description.","type":"string"},"active":{"description":"Whether the form is active and accepting submissions.","type":"boolean"},"recordCount":{"description":"Number of submitted records.","type":"number"},"insertedDate":{"description":"When the form was created.","anyOf":[{"description":"When the form was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of forms (for pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name","active","recordCount","insertedDate","updatedDate"],"properties":{"id":{"description":"Form code (unique identifier within the organisation).","type":"string"},"name":{"description":"Form display name.","type":"string"},"description":{"description":"Form description.","type":"string"},"active":{"description":"Whether the form is active and accepting submissions.","type":"boolean"},"recordCount":{"description":"Number of submitted records.","type":"number"},"insertedDate":{"description":"When the form was created.","anyOf":[{"description":"When the form was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of forms (for pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffFormList","tags":["Form"],"summary":"List forms","description":"Returns a paginated list of forms for the organisation, ordered by last update. Each form includes its record count (number of submissions)."}},"/bff/form/table":{"get":{"parameters":[{"description":"Form code.","examples":["contact-form"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"Form name.","type":"string"},"description":{"description":"Form description.","type":"string"},"table":{"description":"Table data with columns and rows of submitted records."}},"required":["name","table"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"description":"Form name.","type":"string"},"description":{"description":"Form description.","type":"string"},"table":{"description":"Table data with columns and rows of submitted records."}},"required":["name","table"]}},"text/plain":{"schema":{"type":"object","properties":{"name":{"description":"Form name.","type":"string"},"description":{"description":"Form description.","type":"string"},"table":{"description":"Table data with columns and rows of submitted records."}},"required":["name","table"]}}}}},"operationId":"getBffFormTable","tags":["Form"],"summary":"Get form submissions table","description":"Returns all submitted records for a form in a table format. Includes form metadata (name, description) and the full table of submissions with field values."}},"/bff/form/structure":{"get":{"parameters":[{"description":"Form code.","examples":["contact-form"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"info":{"type":"object","required":["name","code","active"],"properties":{"name":{"description":"Form name.","type":"string"},"code":{"description":"Form code (URL-friendly slug).","type":"string"},"active":{"description":"Whether the form is active.","type":"boolean"},"description":{"description":"Form description.","type":"string"}}},"fields":{"type":"array","items":{"type":"object","required":["key","type","label","required","position","active","insertedDate","updatedDate"],"properties":{"key":{"description":"Unique field key within the form.","type":"string"},"parentKey":{"description":"Parent field key (for nested fields).","type":"string"},"type":{"description":"Field input type.","anyOf":[{"const":"header","type":"string"},{"const":"text","type":"string"},{"const":"textarea","type":"string"},{"const":"date","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"select","type":"string"}]},"label":{"description":"Field label displayed to the user.","type":"string"},"helperText":{"description":"Additional help text below the field.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"defaultValue":{"description":"Default value for the field.","type":"string"},"options":{"description":"Options for select/radio/checkbox fields (key-value pairs)."},"position":{"description":"Display order (1-based).","type":"number"},"active":{"description":"Whether the field is active.","type":"boolean"},"insertedDate":{"description":"When the field was created.","anyOf":[{"description":"When the field was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["info","fields"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"info":{"type":"object","required":["name","code","active"],"properties":{"name":{"description":"Form name.","type":"string"},"code":{"description":"Form code (URL-friendly slug).","type":"string"},"active":{"description":"Whether the form is active.","type":"boolean"},"description":{"description":"Form description.","type":"string"}}},"fields":{"type":"array","items":{"type":"object","required":["key","type","label","required","position","active","insertedDate","updatedDate"],"properties":{"key":{"description":"Unique field key within the form.","type":"string"},"parentKey":{"description":"Parent field key (for nested fields).","type":"string"},"type":{"description":"Field input type.","anyOf":[{"const":"header","type":"string"},{"const":"text","type":"string"},{"const":"textarea","type":"string"},{"const":"date","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"select","type":"string"}]},"label":{"description":"Field label displayed to the user.","type":"string"},"helperText":{"description":"Additional help text below the field.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"defaultValue":{"description":"Default value for the field.","type":"string"},"options":{"description":"Options for select/radio/checkbox fields (key-value pairs)."},"position":{"description":"Display order (1-based).","type":"number"},"active":{"description":"Whether the field is active.","type":"boolean"},"insertedDate":{"description":"When the field was created.","anyOf":[{"description":"When the field was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["info","fields"]}},"text/plain":{"schema":{"type":"object","properties":{"info":{"type":"object","required":["name","code","active"],"properties":{"name":{"description":"Form name.","type":"string"},"code":{"description":"Form code (URL-friendly slug).","type":"string"},"active":{"description":"Whether the form is active.","type":"boolean"},"description":{"description":"Form description.","type":"string"}}},"fields":{"type":"array","items":{"type":"object","required":["key","type","label","required","position","active","insertedDate","updatedDate"],"properties":{"key":{"description":"Unique field key within the form.","type":"string"},"parentKey":{"description":"Parent field key (for nested fields).","type":"string"},"type":{"description":"Field input type.","anyOf":[{"const":"header","type":"string"},{"const":"text","type":"string"},{"const":"textarea","type":"string"},{"const":"date","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"select","type":"string"}]},"label":{"description":"Field label displayed to the user.","type":"string"},"helperText":{"description":"Additional help text below the field.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"defaultValue":{"description":"Default value for the field.","type":"string"},"options":{"description":"Options for select/radio/checkbox fields (key-value pairs)."},"position":{"description":"Display order (1-based).","type":"number"},"active":{"description":"Whether the field is active.","type":"boolean"},"insertedDate":{"description":"When the field was created.","anyOf":[{"description":"When the field was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["info","fields"]}}}}},"operationId":"getBffFormStructure","tags":["Form"],"summary":"Get form structure","description":"Returns the full form definition including metadata and all field definitions. Used by the form builder to load and edit the form layout."}},"/bff/form/add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"description":"The assigned form code (may differ from input if a conflict was resolved).","type":"string"}},"required":["code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"code":{"description":"The assigned form code (may differ from input if a conflict was resolved).","type":"string"}},"required":["code"]}},"text/plain":{"schema":{"type":"object","properties":{"code":{"description":"The assigned form code (may differ from input if a conflict was resolved).","type":"string"}},"required":["code"]}}}}},"operationId":"postBffFormAdd","tags":["Form"],"summary":"Create form","description":"Creates a new empty form. The form starts as active with no fields. If the provided code conflicts with an existing form, a numeric suffix is appended automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Form display name.","examples":["Contact Form"],"type":"string"},"code":{"description":"Custom code/slug. If not provided or if it conflicts, one is generated from the name.","examples":["contact-form"],"type":"string"},"description":{"description":"Form description.","examples":["General inquiry form for the website"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Form display name.","examples":["Contact Form"],"type":"string"},"code":{"description":"Custom code/slug. If not provided or if it conflicts, one is generated from the name.","examples":["contact-form"],"type":"string"},"description":{"description":"Form description.","examples":["General inquiry form for the website"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Form display name.","examples":["Contact Form"],"type":"string"},"code":{"description":"Custom code/slug. If not provided or if it conflicts, one is generated from the name.","examples":["contact-form"],"type":"string"},"description":{"description":"Form description.","examples":["General inquiry form for the website"],"type":"string"}}}}}}}},"/bff/form/update-structure":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffFormUpdate-structure","tags":["Form"],"summary":"Update form structure","description":"Updates form metadata and all field definitions in a single request. Only fields with matching keys are updated — unknown keys are skipped. If the new code conflicts with another form, a numeric suffix is appended automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","info","fields"],"properties":{"code":{"description":"Current form code (used to find the form).","examples":["contact-form"],"type":"string"},"info":{"type":"object","required":["name","code","active"],"properties":{"name":{"minLength":1,"description":"New form name.","examples":["Contact Form"],"type":"string"},"code":{"description":"New form code. Auto-suffixed if it conflicts with another form.","examples":["contact-form"],"type":"string"},"active":{"description":"Whether the form is active.","examples":[true],"type":"boolean"},"description":{"description":"Form description.","examples":["General inquiry form"],"type":"string"}}},"fields":{"type":"array","items":{"type":"object","required":["key","type","label","required","options","active","position"],"properties":{"key":{"description":"Field key (must match an existing field).","examples":["email"],"type":"string"},"type":{"description":"Field input type (text, textarea, select, date, etc.).","examples":["text"],"type":"string"},"label":{"description":"Field label.","examples":["Email address"],"type":"string"},"helperText":{"description":"Helper text below the field.","examples":["Enter your work email"],"type":"string"},"required":{"description":"Whether the field is required.","examples":[true],"type":"boolean"},"defaultValue":{"description":"Default value.","examples":[""],"type":"string"},"options":{"description":"Options for select/radio fields (key → label).","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"active":{"description":"Whether the field is active.","type":"boolean"},"position":{"description":"Display order (0-based).","type":"number"}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","info","fields"],"properties":{"code":{"description":"Current form code (used to find the form).","examples":["contact-form"],"type":"string"},"info":{"type":"object","required":["name","code","active"],"properties":{"name":{"minLength":1,"description":"New form name.","examples":["Contact Form"],"type":"string"},"code":{"description":"New form code. Auto-suffixed if it conflicts with another form.","examples":["contact-form"],"type":"string"},"active":{"description":"Whether the form is active.","examples":[true],"type":"boolean"},"description":{"description":"Form description.","examples":["General inquiry form"],"type":"string"}}},"fields":{"type":"array","items":{"type":"object","required":["key","type","label","required","options","active","position"],"properties":{"key":{"description":"Field key (must match an existing field).","examples":["email"],"type":"string"},"type":{"description":"Field input type (text, textarea, select, date, etc.).","examples":["text"],"type":"string"},"label":{"description":"Field label.","examples":["Email address"],"type":"string"},"helperText":{"description":"Helper text below the field.","examples":["Enter your work email"],"type":"string"},"required":{"description":"Whether the field is required.","examples":[true],"type":"boolean"},"defaultValue":{"description":"Default value.","examples":[""],"type":"string"},"options":{"description":"Options for select/radio fields (key → label).","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"active":{"description":"Whether the field is active.","type":"boolean"},"position":{"description":"Display order (0-based).","type":"number"}}}}}}},"text/plain":{"schema":{"type":"object","required":["code","info","fields"],"properties":{"code":{"description":"Current form code (used to find the form).","examples":["contact-form"],"type":"string"},"info":{"type":"object","required":["name","code","active"],"properties":{"name":{"minLength":1,"description":"New form name.","examples":["Contact Form"],"type":"string"},"code":{"description":"New form code. Auto-suffixed if it conflicts with another form.","examples":["contact-form"],"type":"string"},"active":{"description":"Whether the form is active.","examples":[true],"type":"boolean"},"description":{"description":"Form description.","examples":["General inquiry form"],"type":"string"}}},"fields":{"type":"array","items":{"type":"object","required":["key","type","label","required","options","active","position"],"properties":{"key":{"description":"Field key (must match an existing field).","examples":["email"],"type":"string"},"type":{"description":"Field input type (text, textarea, select, date, etc.).","examples":["text"],"type":"string"},"label":{"description":"Field label.","examples":["Email address"],"type":"string"},"helperText":{"description":"Helper text below the field.","examples":["Enter your work email"],"type":"string"},"required":{"description":"Whether the field is required.","examples":[true],"type":"boolean"},"defaultValue":{"description":"Default value.","examples":[""],"type":"string"},"options":{"description":"Options for select/radio fields (key → label).","type":"object","patternProperties":{"^(.*)$":{"type":"string"}}},"active":{"description":"Whether the field is active.","type":"boolean"},"position":{"description":"Display order (0-based).","type":"number"}}}}}}}}}}},"/bff/form/add-field":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffFormAdd-field","tags":["Form"],"summary":"Add field","description":"Adds a new empty text field at the end of the form. The field key is auto-generated. Use update-structure or rename-field-key to customize it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Form code to add the field to.","examples":["contact-form"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Form code to add the field to.","examples":["contact-form"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Form code to add the field to.","examples":["contact-form"],"type":"string"}}}}}}}},"/bff/form/duplicate-field":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffFormDuplicate-field","tags":["Form"],"summary":"Duplicate field","description":"Creates a copy of an existing field with a new auto-generated key. The duplicate is placed right after the original field. All properties (type, label, options, etc.) are copied.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["formCode","fieldCode"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Key of the field to duplicate.","examples":["email"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["formCode","fieldCode"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Key of the field to duplicate.","examples":["email"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["formCode","fieldCode"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Key of the field to duplicate.","examples":["email"],"type":"string"}}}}}}}},"/bff/form/remove-field":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffFormRemove-field","tags":["Form"],"summary":"Remove field","description":"Permanently deletes a field from the form. Existing submitted records that contain this field are not affected (values are preserved in the record data).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["formCode","fieldCode"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Key of the field to remove.","examples":["email"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["formCode","fieldCode"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Key of the field to remove.","examples":["email"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["formCode","fieldCode"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Key of the field to remove.","examples":["email"],"type":"string"}}}}}}}},"/bff/form/rename-field-key":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffFormRename-field-key","tags":["Form"],"summary":"Rename field key","description":"Renames a field key (the programmatic identifier). If the new key conflicts with an existing field, a numeric suffix is appended. Does not affect existing submitted records.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["formCode","fieldCode","fieldCodeNew"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Current field key.","examples":["field_1"],"type":"string"},"fieldCodeNew":{"description":"New field key. Auto-suffixed if it conflicts with another field.","examples":["email"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["formCode","fieldCode","fieldCodeNew"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Current field key.","examples":["field_1"],"type":"string"},"fieldCodeNew":{"description":"New field key. Auto-suffixed if it conflicts with another field.","examples":["email"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["formCode","fieldCode","fieldCodeNew"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldCode":{"description":"Current field key.","examples":["field_1"],"type":"string"},"fieldCodeNew":{"description":"New field key. Auto-suffixed if it conflicts with another field.","examples":["email"],"type":"string"}}}}}}}},"/bff/form/copy-form":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"newCode":{"description":"Code of the newly created form.","type":"string"}},"required":["success","newCode"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"newCode":{"description":"Code of the newly created form.","type":"string"}},"required":["success","newCode"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"newCode":{"description":"Code of the newly created form.","type":"string"}},"required":["success","newCode"]}}}}},"operationId":"postBffFormCopy-form","tags":["Form"],"summary":"Copy form","description":"Creates a full copy of a form including all field definitions. The new form gets a unique code and starts with zero submissions. Useful for creating seasonal variants of registration forms.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Code of the form to copy.","examples":["contact-form"],"type":"string"},"name":{"description":"Name for the new form. If not provided, the original name with a suffix is used.","examples":["Contact Form (copy)"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Code of the form to copy.","examples":["contact-form"],"type":"string"},"name":{"description":"Name for the new form. If not provided, the original name with a suffix is used.","examples":["Contact Form (copy)"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Code of the form to copy.","examples":["contact-form"],"type":"string"},"name":{"description":"Name for the new form. If not provided, the original name with a suffix is used.","examples":["Contact Form (copy)"],"type":"string"}}}}}}}},"/bff/form/delete-form":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffFormDelete-form","tags":["Form"],"summary":"Delete form","description":"Permanently deletes a form and all its data: field definitions, submitted records, and record entries. This action is irreversible.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Code of the form to delete.","examples":["contact-form"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Code of the form to delete.","examples":["contact-form"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["formCode"],"properties":{"formCode":{"description":"Code of the form to delete.","examples":["contact-form"],"type":"string"}}}}}}}},"/bff/form/record-detail":{"get":{"parameters":[{"description":"Form code.","examples":["contact-form"],"schema":{"type":"string"},"in":"query","name":"formCode","required":true},{"description":"Record ID.","examples":["42"],"schema":{"type":"string"},"in":"query","name":"recordId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"recordId":{"description":"Record ID.","type":"number"},"insertedDate":{"description":"When the record was submitted.","anyOf":[{"description":"When the record was submitted.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"entries":{"type":"array","items":{"type":"object","required":["key","label","value","type"],"properties":{"key":{"description":"Field key.","type":"string"},"label":{"description":"Field label at the time of submission.","type":"string"},"value":{"description":"Submitted value.","type":"string"},"type":{"description":"Field type.","type":"string"},"helper_text":{"description":"Field helper text.","type":"string"},"options":{"description":"Field options (for select fields)."}}}}},"required":["recordId","insertedDate","entries"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"recordId":{"description":"Record ID.","type":"number"},"insertedDate":{"description":"When the record was submitted.","anyOf":[{"description":"When the record was submitted.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"entries":{"type":"array","items":{"type":"object","required":["key","label","value","type"],"properties":{"key":{"description":"Field key.","type":"string"},"label":{"description":"Field label at the time of submission.","type":"string"},"value":{"description":"Submitted value.","type":"string"},"type":{"description":"Field type.","type":"string"},"helper_text":{"description":"Field helper text.","type":"string"},"options":{"description":"Field options (for select fields)."}}}}},"required":["recordId","insertedDate","entries"]}},"text/plain":{"schema":{"type":"object","properties":{"recordId":{"description":"Record ID.","type":"number"},"insertedDate":{"description":"When the record was submitted.","anyOf":[{"description":"When the record was submitted.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"entries":{"type":"array","items":{"type":"object","required":["key","label","value","type"],"properties":{"key":{"description":"Field key.","type":"string"},"label":{"description":"Field label at the time of submission.","type":"string"},"value":{"description":"Submitted value.","type":"string"},"type":{"description":"Field type.","type":"string"},"helper_text":{"description":"Field helper text.","type":"string"},"options":{"description":"Field options (for select fields)."}}}}},"required":["recordId","insertedDate","entries"]}}}}},"operationId":"getBffFormRecord-detail","tags":["Form"],"summary":"Get record detail","description":"Returns the full detail of a single form submission including all field values. Each entry contains the field key, label, value, type, and options."}},"/bff/form/delete-record":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffFormDelete-record","tags":["Form"],"summary":"Delete record","description":"Permanently deletes a single form submission and all its entry values. This action is irreversible.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["formCode","recordId"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"recordId":{"description":"ID of the record to delete.","examples":[42],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["formCode","recordId"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"recordId":{"description":"ID of the record to delete.","examples":[42],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["formCode","recordId"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"recordId":{"description":"ID of the record to delete.","examples":[42],"type":"number"}}}}}}}},"/bff/form/reorder-fields":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffFormReorder-fields","tags":["Form"],"summary":"Reorder fields","description":"Sets the display order of all fields in a form. Pass all field keys in the desired order — the position of each field is set by its index in the array.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["formCode","fieldKeys"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldKeys":{"description":"Ordered array of field keys. Position is assigned by index (0-based).","examples":[["name","email","message"]],"type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["formCode","fieldKeys"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldKeys":{"description":"Ordered array of field keys. Position is assigned by index (0-based).","examples":[["name","email","message"]],"type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["formCode","fieldKeys"],"properties":{"formCode":{"description":"Form code.","examples":["contact-form"],"type":"string"},"fieldKeys":{"description":"Ordered array of field keys. Position is assigned by index (0-based).","examples":[["name","email","message"]],"type":"array","items":{"type":"string"}}}}}}}}},"/bff/import/analyze":{"post":{"parameters":[],"responses":{"200":{"description":"Analysis result with preview data and import job reference.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the analysis completed successfully.","type":"boolean"},"importId":{"description":"External ID of the created import job. Use this to start the import.","type":"string"},"totalRows":{"description":"Total number of data rows detected in the source file.","type":"number"},"columns":{"description":"List of detected column names (after provider mapping if applicable).","type":"array","items":{"type":"string"}},"preview":{"description":"Preview of the first 10 rows as objects keyed by column name.","type":"array","items":{}},"errors":{"description":"Parsing errors encountered during analysis. Empty if parsing succeeded.","type":"array","items":{"type":"string"}}},"required":["success","importId","totalRows","columns","preview","errors"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the analysis completed successfully.","type":"boolean"},"importId":{"description":"External ID of the created import job. Use this to start the import.","type":"string"},"totalRows":{"description":"Total number of data rows detected in the source file.","type":"number"},"columns":{"description":"List of detected column names (after provider mapping if applicable).","type":"array","items":{"type":"string"}},"preview":{"description":"Preview of the first 10 rows as objects keyed by column name.","type":"array","items":{}},"errors":{"description":"Parsing errors encountered during analysis. Empty if parsing succeeded.","type":"array","items":{"type":"string"}}},"required":["success","importId","totalRows","columns","preview","errors"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the analysis completed successfully.","type":"boolean"},"importId":{"description":"External ID of the created import job. Use this to start the import.","type":"string"},"totalRows":{"description":"Total number of data rows detected in the source file.","type":"number"},"columns":{"description":"List of detected column names (after provider mapping if applicable).","type":"array","items":{"type":"string"}},"preview":{"description":"Preview of the first 10 rows as objects keyed by column name.","type":"array","items":{}},"errors":{"description":"Parsing errors encountered during analysis. Empty if parsing succeeded.","type":"array","items":{"type":"string"}}},"required":["success","importId","totalRows","columns","preview","errors"]}}}}},"operationId":"postBffImportAnalyze","tags":["Import"],"summary":"Analyze import file","description":"Accepts a CSV/JSON file upload or a remote URL, parses the content, detects columns, and creates an import job in \"ready\" status. For the Shoptet provider, Czech column names are automatically mapped to English equivalents. Returns a preview of the first 10 rows.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"description":"Import provider (\"shoptet\" or \"manual\"). Default: \"manual\".","type":"string"},"dataType":{"description":"Type of entity being imported (e.g. \"product\", \"contact\").","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\"). Default: \"file\".","type":"string"},"file":{"default":"File","description":"CSV/JSON file upload (required when sourceType=\"file\").","type":"string","format":"binary"},"url":{"description":"Remote feed URL (required when sourceType=\"url\").","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"provider":{"description":"Import provider (\"shoptet\" or \"manual\"). Default: \"manual\".","type":"string"},"dataType":{"description":"Type of entity being imported (e.g. \"product\", \"contact\").","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\"). Default: \"file\".","type":"string"},"file":{"default":"File","description":"CSV/JSON file upload (required when sourceType=\"file\").","type":"string","format":"binary"},"url":{"description":"Remote feed URL (required when sourceType=\"url\").","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"provider":{"description":"Import provider (\"shoptet\" or \"manual\"). Default: \"manual\".","type":"string"},"dataType":{"description":"Type of entity being imported (e.g. \"product\", \"contact\").","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\"). Default: \"file\".","type":"string"},"file":{"default":"File","description":"CSV/JSON file upload (required when sourceType=\"file\").","type":"string","format":"binary"},"url":{"description":"Remote feed URL (required when sourceType=\"url\").","type":"string"}}}}}}}},"/bff/import/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1-500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Full-text search on source name.","examples":["products.csv"],"schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false}],"responses":{"200":{"description":"Paginated list of import jobs.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of import jobs matching the query criteria.","type":"array","items":{"description":"Single import job summary.","type":"object","required":["id","externalId","provider","dataType","sourceType","sourceName","status","totalRows","importedRows","failedRows","insertedDate","updatedDate"],"properties":{"id":{"description":"External ID of the import job.","type":"string"},"externalId":{"description":"Unique external identifier of the import job.","type":"string"},"provider":{"description":"Import provider (\"shoptet\" or \"manual\").","type":"string"},"dataType":{"description":"Type of entity being imported.","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\").","type":"string"},"sourceName":{"description":"Original filename or URL used as the import source.","type":"string"},"status":{"description":"Current status of the import job.","type":"string"},"totalRows":{"description":"Total number of rows in the source file.","type":"number"},"importedRows":{"description":"Number of rows successfully imported so far.","type":"number"},"failedRows":{"description":"Number of rows that failed to import.","type":"number"},"insertedDate":{"description":"ISO timestamp when the import was created.","type":"string"},"updatedDate":{"description":"ISO timestamp of the last status update.","type":"string"}}}},"itemCount":{"description":"Total number of import jobs matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of import jobs matching the query criteria.","type":"array","items":{"description":"Single import job summary.","type":"object","required":["id","externalId","provider","dataType","sourceType","sourceName","status","totalRows","importedRows","failedRows","insertedDate","updatedDate"],"properties":{"id":{"description":"External ID of the import job.","type":"string"},"externalId":{"description":"Unique external identifier of the import job.","type":"string"},"provider":{"description":"Import provider (\"shoptet\" or \"manual\").","type":"string"},"dataType":{"description":"Type of entity being imported.","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\").","type":"string"},"sourceName":{"description":"Original filename or URL used as the import source.","type":"string"},"status":{"description":"Current status of the import job.","type":"string"},"totalRows":{"description":"Total number of rows in the source file.","type":"number"},"importedRows":{"description":"Number of rows successfully imported so far.","type":"number"},"failedRows":{"description":"Number of rows that failed to import.","type":"number"},"insertedDate":{"description":"ISO timestamp when the import was created.","type":"string"},"updatedDate":{"description":"ISO timestamp of the last status update.","type":"string"}}}},"itemCount":{"description":"Total number of import jobs matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of import jobs matching the query criteria.","type":"array","items":{"description":"Single import job summary.","type":"object","required":["id","externalId","provider","dataType","sourceType","sourceName","status","totalRows","importedRows","failedRows","insertedDate","updatedDate"],"properties":{"id":{"description":"External ID of the import job.","type":"string"},"externalId":{"description":"Unique external identifier of the import job.","type":"string"},"provider":{"description":"Import provider (\"shoptet\" or \"manual\").","type":"string"},"dataType":{"description":"Type of entity being imported.","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\").","type":"string"},"sourceName":{"description":"Original filename or URL used as the import source.","type":"string"},"status":{"description":"Current status of the import job.","type":"string"},"totalRows":{"description":"Total number of rows in the source file.","type":"number"},"importedRows":{"description":"Number of rows successfully imported so far.","type":"number"},"failedRows":{"description":"Number of rows that failed to import.","type":"number"},"insertedDate":{"description":"ISO timestamp when the import was created.","type":"string"},"updatedDate":{"description":"ISO timestamp of the last status update.","type":"string"}}}},"itemCount":{"description":"Total number of import jobs matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffImportList","tags":["Import"],"summary":"List imports","description":"Returns a paginated list of import jobs for the authenticated organisation. Imports are sorted by creation date (newest first). Supports fulltext search on source name via the filterFulltextQuery query parameter."}},"/bff/import/detail":{"get":{"parameters":[{"description":"External ID of the import job.","examples":["aB3xKm9pQ2wLn4Yz"],"schema":{"type":"string"},"in":"query","name":"importId","required":true}],"responses":{"200":{"description":"Full import job detail with progress and metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Internal database ID.","type":"number"},"organisationId":{"description":"Organisation that owns this import.","type":"number"},"externalId":{"description":"Unique external identifier of the import job.","type":"string"},"provider":{"description":"Import provider (\"shoptet\" or \"manual\").","type":"string"},"dataType":{"description":"Type of entity being imported.","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\").","type":"string"},"sourceName":{"description":"Original filename or URL used as the import source.","type":"string"},"sourceUrl":{"nullable":true,"anyOf":[{"description":"Remote feed URL (only for URL source type).","type":"string"},{"type":"null"}]},"blobId":{"nullable":true,"anyOf":[{"description":"Internal blob ID of the uploaded file.","type":"number"},{"type":"null"}]},"status":{"description":"Current status of the import job.","type":"string"},"totalRows":{"description":"Total number of rows in the source file.","type":"number"},"importedRows":{"description":"Number of rows successfully imported so far.","type":"number"},"failedRows":{"description":"Number of rows that failed to import.","type":"number"},"columns":{"description":"Array of detected column names."},"errors":{"description":"Array of error messages if the import failed."},"insertedDate":{"description":"ISO timestamp when the import was created.","type":"string"},"updatedDate":{"description":"ISO timestamp of the last status update.","type":"string"}},"required":["id","organisationId","externalId","provider","dataType","sourceType","sourceName","sourceUrl","blobId","status","totalRows","importedRows","failedRows","columns","errors","insertedDate","updatedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Internal database ID.","type":"number"},"organisationId":{"description":"Organisation that owns this import.","type":"number"},"externalId":{"description":"Unique external identifier of the import job.","type":"string"},"provider":{"description":"Import provider (\"shoptet\" or \"manual\").","type":"string"},"dataType":{"description":"Type of entity being imported.","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\").","type":"string"},"sourceName":{"description":"Original filename or URL used as the import source.","type":"string"},"sourceUrl":{"nullable":true,"anyOf":[{"description":"Remote feed URL (only for URL source type).","type":"string"},{"type":"null"}]},"blobId":{"nullable":true,"anyOf":[{"description":"Internal blob ID of the uploaded file.","type":"number"},{"type":"null"}]},"status":{"description":"Current status of the import job.","type":"string"},"totalRows":{"description":"Total number of rows in the source file.","type":"number"},"importedRows":{"description":"Number of rows successfully imported so far.","type":"number"},"failedRows":{"description":"Number of rows that failed to import.","type":"number"},"columns":{"description":"Array of detected column names."},"errors":{"description":"Array of error messages if the import failed."},"insertedDate":{"description":"ISO timestamp when the import was created.","type":"string"},"updatedDate":{"description":"ISO timestamp of the last status update.","type":"string"}},"required":["id","organisationId","externalId","provider","dataType","sourceType","sourceName","sourceUrl","blobId","status","totalRows","importedRows","failedRows","columns","errors","insertedDate","updatedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Internal database ID.","type":"number"},"organisationId":{"description":"Organisation that owns this import.","type":"number"},"externalId":{"description":"Unique external identifier of the import job.","type":"string"},"provider":{"description":"Import provider (\"shoptet\" or \"manual\").","type":"string"},"dataType":{"description":"Type of entity being imported.","type":"string"},"sourceType":{"description":"Source type (\"file\" or \"url\").","type":"string"},"sourceName":{"description":"Original filename or URL used as the import source.","type":"string"},"sourceUrl":{"nullable":true,"anyOf":[{"description":"Remote feed URL (only for URL source type).","type":"string"},{"type":"null"}]},"blobId":{"nullable":true,"anyOf":[{"description":"Internal blob ID of the uploaded file.","type":"number"},{"type":"null"}]},"status":{"description":"Current status of the import job.","type":"string"},"totalRows":{"description":"Total number of rows in the source file.","type":"number"},"importedRows":{"description":"Number of rows successfully imported so far.","type":"number"},"failedRows":{"description":"Number of rows that failed to import.","type":"number"},"columns":{"description":"Array of detected column names."},"errors":{"description":"Array of error messages if the import failed."},"insertedDate":{"description":"ISO timestamp when the import was created.","type":"string"},"updatedDate":{"description":"ISO timestamp of the last status update.","type":"string"}},"required":["id","organisationId","externalId","provider","dataType","sourceType","sourceName","sourceUrl","blobId","status","totalRows","importedRows","failedRows","columns","errors","insertedDate","updatedDate"]}}}}},"operationId":"getBffImportDetail","tags":["Import"],"summary":"Get import detail","description":"Returns full details of a single import job including progress counters, detected columns, and any error messages. Use this endpoint to poll import progress (recommended interval: 10 seconds)."}},"/bff/invoice/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Invoice status.","schema":{"anyOf":[{"const":"open","type":"string"},{"const":"sent","type":"string"},{"const":"overdue","type":"string"},{"const":"paid","type":"string"},{"const":"cancelled","type":"string"},{"const":"uncollectible","type":"string"}]},"in":"query","name":"status","required":false},{"description":"Document type.","schema":{"anyOf":[{"const":"invoice","type":"string"},{"const":"receipt","type":"string"},{"const":"proforma","type":"string"},{"const":"partialProforma","type":"string"},{"const":"correction","type":"string"},{"const":"taxDocument","type":"string"},{"const":"finalInvoice","type":"string"},{"const":"creditNote","type":"string"}]},"in":"query","name":"type","required":false},{"description":"Filter by payment status: \"true\" or \"false\".","examples":["true"],"schema":{"type":"string"},"in":"query","name":"isPaid","required":false},{"description":"External customer ID for filtering.","examples":["xK9mP2wLn4YzaB3Q"],"schema":{"type":"string"},"in":"query","name":"customerId","required":false},{"description":"Issue date from (ISO format: YYYY-MM-DD).","examples":["2026-01-01"],"schema":{"type":"string"},"in":"query","name":"dateFrom","required":false},{"description":"Issue date to (ISO format: YYYY-MM-DD).","examples":["2026-03-31"],"schema":{"type":"string"},"in":"query","name":"dateTo","required":false},{"description":"Full-text search in invoice number, email, and customer name.","examples":["2024001"],"schema":{"type":"string"},"in":"query","name":"search","required":false}],"responses":{"200":{"description":"Paginated list of invoices.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"List of invoices.","type":"array","items":{"description":"Invoice item in the list.","type":"object","required":["id","sequence_number","type","status","total","currency","issuer_id","issue_date","due_date"],"properties":{"id":{"description":"Unique external invoice identifier (16 characters).","type":"string"},"sequence_number":{"description":"Invoice number (e.g., \"2024001\").","type":"string"},"order_hash":{"description":"Hash of the associated order.","type":"string"},"order_number":{"description":"Number of the associated order.","type":"string"},"type":{"description":"Document type (invoice, receipt, proforma, creditNote, ...).","type":"string"},"status":{"description":"Invoice status (open, sent, overdue, paid, cancelled, uncollectible).","type":"string"},"total":{"description":"Total invoice amount.","type":"string"},"currency":{"description":"Currency code (CZK, EUR, ...).","type":"string"},"issuer_id":{"description":"External ID of the issuer.","type":"string"},"issuer_name":{"description":"Name of the issuer.","type":"string"},"customer_id":{"description":"External ID of the customer.","type":"string"},"customer_name":{"description":"Name of the customer.","type":"string"},"recipient_id":{"description":"External ID of the recipient (if different from customer).","type":"string"},"recipient_name":{"description":"Name of the recipient.","type":"string"},"issue_date":{"description":"Invoice issue date.","anyOf":[{"description":"Invoice issue date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"due_date":{"description":"Payment due date.","anyOf":[{"description":"Payment due date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"invoice_pay_date":{"description":"Payment date. Null if unpaid.","anyOf":[{"description":"Payment date. Null if unpaid.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of invoices matching the filter.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"List of invoices.","type":"array","items":{"description":"Invoice item in the list.","type":"object","required":["id","sequence_number","type","status","total","currency","issuer_id","issue_date","due_date"],"properties":{"id":{"description":"Unique external invoice identifier (16 characters).","type":"string"},"sequence_number":{"description":"Invoice number (e.g., \"2024001\").","type":"string"},"order_hash":{"description":"Hash of the associated order.","type":"string"},"order_number":{"description":"Number of the associated order.","type":"string"},"type":{"description":"Document type (invoice, receipt, proforma, creditNote, ...).","type":"string"},"status":{"description":"Invoice status (open, sent, overdue, paid, cancelled, uncollectible).","type":"string"},"total":{"description":"Total invoice amount.","type":"string"},"currency":{"description":"Currency code (CZK, EUR, ...).","type":"string"},"issuer_id":{"description":"External ID of the issuer.","type":"string"},"issuer_name":{"description":"Name of the issuer.","type":"string"},"customer_id":{"description":"External ID of the customer.","type":"string"},"customer_name":{"description":"Name of the customer.","type":"string"},"recipient_id":{"description":"External ID of the recipient (if different from customer).","type":"string"},"recipient_name":{"description":"Name of the recipient.","type":"string"},"issue_date":{"description":"Invoice issue date.","anyOf":[{"description":"Invoice issue date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"due_date":{"description":"Payment due date.","anyOf":[{"description":"Payment due date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"invoice_pay_date":{"description":"Payment date. Null if unpaid.","anyOf":[{"description":"Payment date. Null if unpaid.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of invoices matching the filter.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"List of invoices.","type":"array","items":{"description":"Invoice item in the list.","type":"object","required":["id","sequence_number","type","status","total","currency","issuer_id","issue_date","due_date"],"properties":{"id":{"description":"Unique external invoice identifier (16 characters).","type":"string"},"sequence_number":{"description":"Invoice number (e.g., \"2024001\").","type":"string"},"order_hash":{"description":"Hash of the associated order.","type":"string"},"order_number":{"description":"Number of the associated order.","type":"string"},"type":{"description":"Document type (invoice, receipt, proforma, creditNote, ...).","type":"string"},"status":{"description":"Invoice status (open, sent, overdue, paid, cancelled, uncollectible).","type":"string"},"total":{"description":"Total invoice amount.","type":"string"},"currency":{"description":"Currency code (CZK, EUR, ...).","type":"string"},"issuer_id":{"description":"External ID of the issuer.","type":"string"},"issuer_name":{"description":"Name of the issuer.","type":"string"},"customer_id":{"description":"External ID of the customer.","type":"string"},"customer_name":{"description":"Name of the customer.","type":"string"},"recipient_id":{"description":"External ID of the recipient (if different from customer).","type":"string"},"recipient_name":{"description":"Name of the recipient.","type":"string"},"issue_date":{"description":"Invoice issue date.","anyOf":[{"description":"Invoice issue date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"due_date":{"description":"Payment due date.","anyOf":[{"description":"Payment due date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"invoice_pay_date":{"description":"Payment date. Null if unpaid.","anyOf":[{"description":"Payment date. Null if unpaid.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of invoices matching the filter.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffInvoiceList","tags":["Invoice"],"summary":"List invoices","description":"Returns a paginated list of invoices for the organisation. Invoices are sorted by issue date (newest first). Supports filtering by status, type, payment state, customer, date range, and full-text search."}},"/bff/invoice/detail":{"get":{"parameters":[{"description":"External invoice ID (16 characters).","examples":["aB3xKm9pQ2wLn4Yz"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"description":"Complete invoice detail.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"External invoice ID.","type":"string"},"sequenceNumber":{"description":"Invoice number.","type":"string"},"type":{"description":"Document type.","type":"string"},"title":{"description":"Invoice title (e.g., \"Invoice 2024001\").","type":"string"},"status":{"description":"Invoice status.","type":"string"},"hasPaid":{"description":"Whether the invoice is paid.","type":"boolean"},"total":{"description":"Total amount.","type":"number"},"currency":{"description":"Currency code.","type":"string"},"supplier":{"description":"Invoice participant (supplier or customer).","type":"object","required":["name","streetAddress","city","postalCode"],"properties":{"name":{"description":"Company name or person name.","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (VAT ID).","type":"string"},"accountNumber":{"description":"Bank account number.","type":"string"},"addressDescription":{"description":"Address description.","type":"string"}}},"customer":{"description":"Invoice participant (supplier or customer).","type":"object","required":["name","streetAddress","city","postalCode"],"properties":{"name":{"description":"Company name or person name.","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (VAT ID).","type":"string"},"accountNumber":{"description":"Bank account number.","type":"string"},"addressDescription":{"description":"Address description.","type":"string"}}},"variableSymbol":{"description":"Variable symbol (payment reference).","type":"string"},"constantSymbol":{"description":"Constant symbol.","type":"string"},"specificSymbol":{"description":"Specific symbol.","type":"string"},"bankName":{"description":"Bank name.","type":"string"},"iban":{"description":"IBAN.","type":"string"},"bic":{"description":"BIC/SWIFT code.","type":"string"},"dueDate":{"description":"Due date (ISO format).","type":"string"},"issueDate":{"description":"Issue date (ISO format).","type":"string"},"taxableSupplyDate":{"description":"Taxable supply date (ISO format).","type":"string"},"paymentMethod":{"description":"Payment method.","type":"string"},"publicNotice":{"description":"Public notice (displayed on invoice).","type":"string"},"internalNotice":{"description":"Internal notice (not displayed on invoice).","type":"string"},"items":{"description":"Invoice line items.","type":"array","items":{"description":"Invoice line item.","type":"object","required":["description","quantity","unitPrice","totalPrice","vatRate"],"properties":{"description":{"description":"Item description.","type":"string"},"quantity":{"description":"Quantity.","type":"number"},"unit":{"description":"Unit (pcs, hrs, ...).","type":"string"},"unitPrice":{"description":"Unit price excluding VAT.","type":"number"},"totalPrice":{"description":"Total item price.","type":"number"},"vatRate":{"description":"VAT rate in percent.","type":"number"}}}},"useVat":{"description":"Whether the organisation is VAT registered.","type":"boolean"},"logoUrl":{"description":"Organisation logo URL.","type":"string"},"snapshottedAt":{"description":"ISO timestamp when the invoice was locked into an immutable snapshot. Absent when the invoice still reflects live supplier/customer/bank data.","type":"string"},"lastReminderAt":{"description":"ISO timestamp of the most recent overdue reminder, if any.","type":"string"},"reminderCount":{"description":"Total reminders sent for this invoice.","type":"number"},"file":{"description":"Invoice PDF file information.","type":"object","required":["token","filename","downloadUrl","size"],"properties":{"token":{"description":"Unique file token.","type":"string"},"filename":{"description":"Original filename.","type":"string"},"downloadUrl":{"description":"Direct download URL for the PDF file.","type":"string"},"size":{"description":"File size in bytes.","type":"number"}}}},"required":["id","sequenceNumber","type","title","status","hasPaid","total","currency","supplier","dueDate","issueDate","items","useVat","reminderCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"External invoice ID.","type":"string"},"sequenceNumber":{"description":"Invoice number.","type":"string"},"type":{"description":"Document type.","type":"string"},"title":{"description":"Invoice title (e.g., \"Invoice 2024001\").","type":"string"},"status":{"description":"Invoice status.","type":"string"},"hasPaid":{"description":"Whether the invoice is paid.","type":"boolean"},"total":{"description":"Total amount.","type":"number"},"currency":{"description":"Currency code.","type":"string"},"supplier":{"description":"Invoice participant (supplier or customer).","type":"object","required":["name","streetAddress","city","postalCode"],"properties":{"name":{"description":"Company name or person name.","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (VAT ID).","type":"string"},"accountNumber":{"description":"Bank account number.","type":"string"},"addressDescription":{"description":"Address description.","type":"string"}}},"customer":{"description":"Invoice participant (supplier or customer).","type":"object","required":["name","streetAddress","city","postalCode"],"properties":{"name":{"description":"Company name or person name.","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (VAT ID).","type":"string"},"accountNumber":{"description":"Bank account number.","type":"string"},"addressDescription":{"description":"Address description.","type":"string"}}},"variableSymbol":{"description":"Variable symbol (payment reference).","type":"string"},"constantSymbol":{"description":"Constant symbol.","type":"string"},"specificSymbol":{"description":"Specific symbol.","type":"string"},"bankName":{"description":"Bank name.","type":"string"},"iban":{"description":"IBAN.","type":"string"},"bic":{"description":"BIC/SWIFT code.","type":"string"},"dueDate":{"description":"Due date (ISO format).","type":"string"},"issueDate":{"description":"Issue date (ISO format).","type":"string"},"taxableSupplyDate":{"description":"Taxable supply date (ISO format).","type":"string"},"paymentMethod":{"description":"Payment method.","type":"string"},"publicNotice":{"description":"Public notice (displayed on invoice).","type":"string"},"internalNotice":{"description":"Internal notice (not displayed on invoice).","type":"string"},"items":{"description":"Invoice line items.","type":"array","items":{"description":"Invoice line item.","type":"object","required":["description","quantity","unitPrice","totalPrice","vatRate"],"properties":{"description":{"description":"Item description.","type":"string"},"quantity":{"description":"Quantity.","type":"number"},"unit":{"description":"Unit (pcs, hrs, ...).","type":"string"},"unitPrice":{"description":"Unit price excluding VAT.","type":"number"},"totalPrice":{"description":"Total item price.","type":"number"},"vatRate":{"description":"VAT rate in percent.","type":"number"}}}},"useVat":{"description":"Whether the organisation is VAT registered.","type":"boolean"},"logoUrl":{"description":"Organisation logo URL.","type":"string"},"snapshottedAt":{"description":"ISO timestamp when the invoice was locked into an immutable snapshot. Absent when the invoice still reflects live supplier/customer/bank data.","type":"string"},"lastReminderAt":{"description":"ISO timestamp of the most recent overdue reminder, if any.","type":"string"},"reminderCount":{"description":"Total reminders sent for this invoice.","type":"number"},"file":{"description":"Invoice PDF file information.","type":"object","required":["token","filename","downloadUrl","size"],"properties":{"token":{"description":"Unique file token.","type":"string"},"filename":{"description":"Original filename.","type":"string"},"downloadUrl":{"description":"Direct download URL for the PDF file.","type":"string"},"size":{"description":"File size in bytes.","type":"number"}}}},"required":["id","sequenceNumber","type","title","status","hasPaid","total","currency","supplier","dueDate","issueDate","items","useVat","reminderCount"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"External invoice ID.","type":"string"},"sequenceNumber":{"description":"Invoice number.","type":"string"},"type":{"description":"Document type.","type":"string"},"title":{"description":"Invoice title (e.g., \"Invoice 2024001\").","type":"string"},"status":{"description":"Invoice status.","type":"string"},"hasPaid":{"description":"Whether the invoice is paid.","type":"boolean"},"total":{"description":"Total amount.","type":"number"},"currency":{"description":"Currency code.","type":"string"},"supplier":{"description":"Invoice participant (supplier or customer).","type":"object","required":["name","streetAddress","city","postalCode"],"properties":{"name":{"description":"Company name or person name.","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (VAT ID).","type":"string"},"accountNumber":{"description":"Bank account number.","type":"string"},"addressDescription":{"description":"Address description.","type":"string"}}},"customer":{"description":"Invoice participant (supplier or customer).","type":"object","required":["name","streetAddress","city","postalCode"],"properties":{"name":{"description":"Company name or person name.","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number.","type":"string"},"taxIdentificationNumber":{"description":"Tax identification number (VAT ID).","type":"string"},"accountNumber":{"description":"Bank account number.","type":"string"},"addressDescription":{"description":"Address description.","type":"string"}}},"variableSymbol":{"description":"Variable symbol (payment reference).","type":"string"},"constantSymbol":{"description":"Constant symbol.","type":"string"},"specificSymbol":{"description":"Specific symbol.","type":"string"},"bankName":{"description":"Bank name.","type":"string"},"iban":{"description":"IBAN.","type":"string"},"bic":{"description":"BIC/SWIFT code.","type":"string"},"dueDate":{"description":"Due date (ISO format).","type":"string"},"issueDate":{"description":"Issue date (ISO format).","type":"string"},"taxableSupplyDate":{"description":"Taxable supply date (ISO format).","type":"string"},"paymentMethod":{"description":"Payment method.","type":"string"},"publicNotice":{"description":"Public notice (displayed on invoice).","type":"string"},"internalNotice":{"description":"Internal notice (not displayed on invoice).","type":"string"},"items":{"description":"Invoice line items.","type":"array","items":{"description":"Invoice line item.","type":"object","required":["description","quantity","unitPrice","totalPrice","vatRate"],"properties":{"description":{"description":"Item description.","type":"string"},"quantity":{"description":"Quantity.","type":"number"},"unit":{"description":"Unit (pcs, hrs, ...).","type":"string"},"unitPrice":{"description":"Unit price excluding VAT.","type":"number"},"totalPrice":{"description":"Total item price.","type":"number"},"vatRate":{"description":"VAT rate in percent.","type":"number"}}}},"useVat":{"description":"Whether the organisation is VAT registered.","type":"boolean"},"logoUrl":{"description":"Organisation logo URL.","type":"string"},"snapshottedAt":{"description":"ISO timestamp when the invoice was locked into an immutable snapshot. Absent when the invoice still reflects live supplier/customer/bank data.","type":"string"},"lastReminderAt":{"description":"ISO timestamp of the most recent overdue reminder, if any.","type":"string"},"reminderCount":{"description":"Total reminders sent for this invoice.","type":"number"},"file":{"description":"Invoice PDF file information.","type":"object","required":["token","filename","downloadUrl","size"],"properties":{"token":{"description":"Unique file token.","type":"string"},"filename":{"description":"Original filename.","type":"string"},"downloadUrl":{"description":"Direct download URL for the PDF file.","type":"string"},"size":{"description":"File size in bytes.","type":"number"}}}},"required":["id","sequenceNumber","type","title","status","hasPaid","total","currency","supplier","dueDate","issueDate","items","useVat","reminderCount"]}}}}},"operationId":"getBffInvoiceDetail","tags":["Invoice"],"summary":"Invoice detail","description":"Returns complete invoice detail including line items, supplier, customer, and payment information. This data can be used for displaying the invoice or generating PDF."}},"/bff/invoice/stats":{"get":{"parameters":[{"description":"Date from (ISO format: YYYY-MM-DD).","examples":["2026-01-01"],"schema":{"type":"string"},"in":"query","name":"dateFrom","required":false},{"description":"Date to (ISO format: YYYY-MM-DD).","examples":["2026-03-31"],"schema":{"type":"string"},"in":"query","name":"dateTo","required":false}],"responses":{"200":{"description":"Invoice statistics.","content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"description":"Summary statistics.","type":"object","required":["totalCount","paidCount","unpaidCount","overdueCount","totalAmount","paidAmount","unpaidAmount","overdueAmount"],"properties":{"totalCount":{"description":"Total number of invoices.","type":"number"},"paidCount":{"description":"Number of paid invoices.","type":"number"},"unpaidCount":{"description":"Number of unpaid invoices.","type":"number"},"overdueCount":{"description":"Number of overdue invoices.","type":"number"},"totalAmount":{"description":"Total invoiced amount.","type":"number"},"paidAmount":{"description":"Paid amount.","type":"number"},"unpaidAmount":{"description":"Unpaid amount.","type":"number"},"overdueAmount":{"description":"Overdue amount.","type":"number"}}},"byType":{"description":"Statistics by document type.","type":"array","items":{"type":"object","required":["type","count","amount"],"properties":{"type":{"description":"Document type.","type":"string"},"count":{"description":"Count.","type":"number"},"amount":{"description":"Total amount.","type":"number"}}}},"byStatus":{"description":"Statistics by status.","type":"array","items":{"type":"object","required":["status","count","amount"],"properties":{"status":{"description":"Status.","type":"string"},"count":{"description":"Count.","type":"number"},"amount":{"description":"Total amount.","type":"number"}}}}},"required":["summary","byType","byStatus"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"summary":{"description":"Summary statistics.","type":"object","required":["totalCount","paidCount","unpaidCount","overdueCount","totalAmount","paidAmount","unpaidAmount","overdueAmount"],"properties":{"totalCount":{"description":"Total number of invoices.","type":"number"},"paidCount":{"description":"Number of paid invoices.","type":"number"},"unpaidCount":{"description":"Number of unpaid invoices.","type":"number"},"overdueCount":{"description":"Number of overdue invoices.","type":"number"},"totalAmount":{"description":"Total invoiced amount.","type":"number"},"paidAmount":{"description":"Paid amount.","type":"number"},"unpaidAmount":{"description":"Unpaid amount.","type":"number"},"overdueAmount":{"description":"Overdue amount.","type":"number"}}},"byType":{"description":"Statistics by document type.","type":"array","items":{"type":"object","required":["type","count","amount"],"properties":{"type":{"description":"Document type.","type":"string"},"count":{"description":"Count.","type":"number"},"amount":{"description":"Total amount.","type":"number"}}}},"byStatus":{"description":"Statistics by status.","type":"array","items":{"type":"object","required":["status","count","amount"],"properties":{"status":{"description":"Status.","type":"string"},"count":{"description":"Count.","type":"number"},"amount":{"description":"Total amount.","type":"number"}}}}},"required":["summary","byType","byStatus"]}},"text/plain":{"schema":{"type":"object","properties":{"summary":{"description":"Summary statistics.","type":"object","required":["totalCount","paidCount","unpaidCount","overdueCount","totalAmount","paidAmount","unpaidAmount","overdueAmount"],"properties":{"totalCount":{"description":"Total number of invoices.","type":"number"},"paidCount":{"description":"Number of paid invoices.","type":"number"},"unpaidCount":{"description":"Number of unpaid invoices.","type":"number"},"overdueCount":{"description":"Number of overdue invoices.","type":"number"},"totalAmount":{"description":"Total invoiced amount.","type":"number"},"paidAmount":{"description":"Paid amount.","type":"number"},"unpaidAmount":{"description":"Unpaid amount.","type":"number"},"overdueAmount":{"description":"Overdue amount.","type":"number"}}},"byType":{"description":"Statistics by document type.","type":"array","items":{"type":"object","required":["type","count","amount"],"properties":{"type":{"description":"Document type.","type":"string"},"count":{"description":"Count.","type":"number"},"amount":{"description":"Total amount.","type":"number"}}}},"byStatus":{"description":"Statistics by status.","type":"array","items":{"type":"object","required":["status","count","amount"],"properties":{"status":{"description":"Status.","type":"string"},"count":{"description":"Count.","type":"number"},"amount":{"description":"Total amount.","type":"number"}}}}},"required":["summary","byType","byStatus"]}}}}},"operationId":"getBffInvoiceStats","tags":["Invoice"],"summary":"Invoice statistics","description":"Returns aggregate invoice statistics - counts and amounts by payment status, document type, and status. Useful for dashboards and reports."}},"/bff/invoice/types":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","type","label"],"properties":{"id":{"description":"Type ID.","type":"number"},"type":{"description":"Type code.","type":"string"},"label":{"description":"Human-readable label.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","type","label"],"properties":{"id":{"description":"Type ID.","type":"number"},"type":{"description":"Type code.","type":"string"},"label":{"description":"Human-readable label.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","type","label"],"properties":{"id":{"description":"Type ID.","type":"number"},"type":{"description":"Type code.","type":"string"},"label":{"description":"Human-readable label.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffInvoiceTypes","tags":["Invoice"],"summary":"List invoice types","description":"Returns a list of all available invoice/document types."}},"/bff/invoice/mark-as-paid":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffInvoiceMark-as-paid","tags":["Invoice"],"summary":"Mark invoice as paid","description":"Marks the invoice as paid and changes its status to \"paid\".","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"payDate":{"description":"Payment date (ISO format). If not provided, current date is used.","examples":["2026-04-15"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"payDate":{"description":"Payment date (ISO format). If not provided, current date is used.","examples":["2026-04-15"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"payDate":{"description":"Payment date (ISO format). If not provided, current date is used.","examples":["2026-04-15"],"type":"string"}}}}}}}},"/bff/invoice/update-status":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffInvoiceUpdate-status","tags":["Invoice"],"summary":"Update invoice status","description":"Changes the invoice status to the specified value.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","status"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"status":{"description":"Invoice status.","anyOf":[{"const":"open","type":"string"},{"const":"sent","type":"string"},{"const":"overdue","type":"string"},{"const":"paid","type":"string"},{"const":"cancelled","type":"string"},{"const":"uncollectible","type":"string"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","status"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"status":{"description":"Invoice status.","anyOf":[{"const":"open","type":"string"},{"const":"sent","type":"string"},{"const":"overdue","type":"string"},{"const":"paid","type":"string"},{"const":"cancelled","type":"string"},{"const":"uncollectible","type":"string"}]}}}},"text/plain":{"schema":{"type":"object","required":["id","status"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"status":{"description":"Invoice status.","anyOf":[{"const":"open","type":"string"},{"const":"sent","type":"string"},{"const":"overdue","type":"string"},{"const":"paid","type":"string"},{"const":"cancelled","type":"string"},{"const":"uncollectible","type":"string"}]}}}}}}}},"/bff/invoice/update-notes":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffInvoiceUpdate-notes","tags":["Invoice"],"summary":"Update invoice notes","description":"Updates the public and/or internal notice of the invoice.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"publicNotice":{"description":"Public notice (displayed on invoice).","examples":["Thank you for your business"],"type":"string"},"internalNotice":{"description":"Internal notice.","examples":["Approved by manager"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"publicNotice":{"description":"Public notice (displayed on invoice).","examples":["Thank you for your business"],"type":"string"},"internalNotice":{"description":"Internal notice.","examples":["Approved by manager"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"publicNotice":{"description":"Public notice (displayed on invoice).","examples":["Thank you for your business"],"type":"string"},"internalNotice":{"description":"Internal notice.","examples":["Approved by manager"],"type":"string"}}}}}}}},"/bff/invoice/export":{"get":{"parameters":[{"description":"Start date (ISO format: YYYY-MM-DD).","examples":["2026-01-01"],"schema":{"type":"string"},"in":"query","name":"dateFrom","required":true},{"description":"End date (ISO format: YYYY-MM-DD).","examples":["2026-03-31"],"schema":{"type":"string"},"in":"query","name":"dateTo","required":true},{"description":"Export format: \"csv\" for spreadsheet data, \"zip\" for PDF files archive.","schema":{"anyOf":[{"const":"csv","type":"string"},{"const":"zip","type":"string"}]},"in":"query","name":"format","required":true}],"operationId":"getBffInvoiceExport","tags":["Invoice"],"summary":"Export invoices","description":"Exports invoices for the specified date range. CSV format includes invoice metadata (number, status, amounts, customer info). ZIP format includes actual PDF invoice files with a manifest.","responses":{"200":{}}}},"/bff/invoice/export-isdoc":{"get":{"parameters":[{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffInvoiceExport-isdoc","tags":["Invoice"],"summary":"Export invoice as ISDOC 6.0.2","description":"Generates the Czech B2B invoice exchange format (ISDOC 6.0.2) for a single invoice. The DocumentType element is derived from the invoice type (invoice → 1, proforma → 2, credit/correction → 5).","responses":{"200":{}}}},"/bff/invoice/export-pohoda":{"get":{"parameters":[{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Pohoda předkontace code (e.g., \"311000\").","schema":{"type":"string"},"in":"query","name":"accountCode","required":false},{"description":"Pohoda středisko code.","schema":{"type":"string"},"in":"query","name":"centreCode","required":false},{"description":"Pohoda činnost code.","schema":{"type":"string"},"in":"query","name":"activityCode","required":false},{"description":"Pohoda zakázka code.","schema":{"type":"string"},"in":"query","name":"contractCode","required":false},{"description":"Pohoda číselná řada prefix prepended to the sequence number.","schema":{"type":"string"},"in":"query","name":"numericalSeries","required":false},{"description":"Set to \"true\" for reverse-charge classification (priceNone instead of priceHigh).","schema":{"type":"string"},"in":"query","name":"reverseCharge","required":false}],"operationId":"getBffInvoiceExport-pohoda","tags":["Invoice"],"summary":"Export invoice as Pohoda XML (Stormware data package)","description":"Generates the Stormware Pohoda dataPack XML for direct import into the accounting software. Optional codes (account, centre, activity, contract) come from the per-organisation accounting configuration.","responses":{"200":{}}}},"/bff/invoice/clone":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"External ID of the new draft invoice.","type":"string"},"sequenceNumber":{"description":"Sequence number of the new draft invoice.","type":"string"}},"required":["id","sequenceNumber"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"External ID of the new draft invoice.","type":"string"},"sequenceNumber":{"description":"Sequence number of the new draft invoice.","type":"string"}},"required":["id","sequenceNumber"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"External ID of the new draft invoice.","type":"string"},"sequenceNumber":{"description":"Sequence number of the new draft invoice.","type":"string"}},"required":["id","sequenceNumber"]}}}}},"operationId":"postBffInvoiceClone","tags":["Invoice"],"summary":"Clone invoice as a new draft","description":"Duplicates an invoice as a fresh draft (status `open`, today's issue date, recomputed due date). When `incrementMonth` is true (default), any \"M/YYYY\" or \"MM/YYYY\" patterns in the line descriptions are advanced by one month, supporting recurring monthly billing.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID of the source invoice.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"incrementMonth":{"description":"Whether to auto-increment \"M/YYYY\" tokens in line descriptions. Defaults to true.","default":true,"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID of the source invoice.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"incrementMonth":{"description":"Whether to auto-increment \"M/YYYY\" tokens in line descriptions. Defaults to true.","default":true,"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID of the source invoice.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"incrementMonth":{"description":"Whether to auto-increment \"M/YYYY\" tokens in line descriptions. Defaults to true.","default":true,"type":"boolean"}}}}}}}},"/bff/invoice/lock-snapshot":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"alreadySnapshotted":{"description":"True when the invoice was already locked and `force` was not set — no change occurred.","type":"boolean"},"snapshottedAt":{"description":"ISO timestamp of the (existing or new) snapshot.","type":"string"}},"required":["alreadySnapshotted","snapshottedAt"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"alreadySnapshotted":{"description":"True when the invoice was already locked and `force` was not set — no change occurred.","type":"boolean"},"snapshottedAt":{"description":"ISO timestamp of the (existing or new) snapshot.","type":"string"}},"required":["alreadySnapshotted","snapshottedAt"]}},"text/plain":{"schema":{"type":"object","properties":{"alreadySnapshotted":{"description":"True when the invoice was already locked and `force` was not set — no change occurred.","type":"boolean"},"snapshottedAt":{"description":"ISO timestamp of the (existing or new) snapshot.","type":"string"}},"required":["alreadySnapshotted","snapshottedAt"]}}}}},"operationId":"postBffInvoiceLock-snapshot","tags":["Invoice"],"summary":"Lock invoice immutability snapshot","description":"Freezes the supplier, customer and bank account details into JSONB columns on the invoice. Once locked, downstream renderers (PDF, detail, exports) prefer the snapshot over live data, so the invoice stays unchanged even if the contact or bank account is later edited. Idempotent unless `force: true` is passed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"force":{"description":"Re-snapshot even if the invoice is already locked. Use only when an admin explicitly accepts overwriting historical data — guard the UI with a confirm dialog.","default":false,"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"force":{"description":"Re-snapshot even if the invoice is already locked. Use only when an admin explicitly accepts overwriting historical data — guard the UI with a confirm dialog.","default":false,"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"force":{"description":"Re-snapshot even if the invoice is already locked. Use only when an admin explicitly accepts overwriting historical data — guard the UI with a confirm dialog.","default":false,"type":"boolean"}}}}}}}},"/bff/invoice/send-reminder":{"post":{"parameters":[],"responses":{"200":{"anyOf":[{"type":"object","required":["sent","recipient","reminderCount","sentAt","emailExternalId"],"properties":{"sent":{"const":true,"type":"boolean"},"recipient":{"description":"Email address the reminder was sent to.","type":"string"},"reminderCount":{"description":"Total number of reminders sent for this invoice (after this one).","type":"number"},"sentAt":{"description":"ISO timestamp when the reminder was queued.","type":"string"},"emailExternalId":{"description":"External ID of the queued email message.","type":"string"}}},{"type":"object","required":["sent","skippedReason"],"properties":{"sent":{"const":false,"type":"boolean"},"skippedReason":{"description":"`paid`/`cancelled` — invoice no longer needs reminding. `cooldown` — last reminder was too recent. `no-recipient` — no email found on customer/recipient.","anyOf":[{"const":"paid","type":"string"},{"const":"cooldown","type":"string"},{"const":"no-recipient","type":"string"},{"const":"cancelled","type":"string"}]},"lastReminderAt":{"description":"ISO timestamp of the previous reminder (only when reason is `cooldown`).","type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["sent","recipient","reminderCount","sentAt","emailExternalId"],"properties":{"sent":{"const":true,"type":"boolean"},"recipient":{"description":"Email address the reminder was sent to.","type":"string"},"reminderCount":{"description":"Total number of reminders sent for this invoice (after this one).","type":"number"},"sentAt":{"description":"ISO timestamp when the reminder was queued.","type":"string"},"emailExternalId":{"description":"External ID of the queued email message.","type":"string"}}},{"type":"object","required":["sent","skippedReason"],"properties":{"sent":{"const":false,"type":"boolean"},"skippedReason":{"description":"`paid`/`cancelled` — invoice no longer needs reminding. `cooldown` — last reminder was too recent. `no-recipient` — no email found on customer/recipient.","anyOf":[{"const":"paid","type":"string"},{"const":"cooldown","type":"string"},{"const":"no-recipient","type":"string"},{"const":"cancelled","type":"string"}]},"lastReminderAt":{"description":"ISO timestamp of the previous reminder (only when reason is `cooldown`).","type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["sent","recipient","reminderCount","sentAt","emailExternalId"],"properties":{"sent":{"const":true,"type":"boolean"},"recipient":{"description":"Email address the reminder was sent to.","type":"string"},"reminderCount":{"description":"Total number of reminders sent for this invoice (after this one).","type":"number"},"sentAt":{"description":"ISO timestamp when the reminder was queued.","type":"string"},"emailExternalId":{"description":"External ID of the queued email message.","type":"string"}}},{"type":"object","required":["sent","skippedReason"],"properties":{"sent":{"const":false,"type":"boolean"},"skippedReason":{"description":"`paid`/`cancelled` — invoice no longer needs reminding. `cooldown` — last reminder was too recent. `no-recipient` — no email found on customer/recipient.","anyOf":[{"const":"paid","type":"string"},{"const":"cooldown","type":"string"},{"const":"no-recipient","type":"string"},{"const":"cancelled","type":"string"}]},"lastReminderAt":{"description":"ISO timestamp of the previous reminder (only when reason is `cooldown`).","type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["sent","recipient","reminderCount","sentAt","emailExternalId"],"properties":{"sent":{"const":true,"type":"boolean"},"recipient":{"description":"Email address the reminder was sent to.","type":"string"},"reminderCount":{"description":"Total number of reminders sent for this invoice (after this one).","type":"number"},"sentAt":{"description":"ISO timestamp when the reminder was queued.","type":"string"},"emailExternalId":{"description":"External ID of the queued email message.","type":"string"}}},{"type":"object","required":["sent","skippedReason"],"properties":{"sent":{"const":false,"type":"boolean"},"skippedReason":{"description":"`paid`/`cancelled` — invoice no longer needs reminding. `cooldown` — last reminder was too recent. `no-recipient` — no email found on customer/recipient.","anyOf":[{"const":"paid","type":"string"},{"const":"cooldown","type":"string"},{"const":"no-recipient","type":"string"},{"const":"cancelled","type":"string"}]},"lastReminderAt":{"description":"ISO timestamp of the previous reminder (only when reason is `cooldown`).","type":"string"}}}]}}}}},"operationId":"postBffInvoiceSend-reminder","tags":["Invoice"],"summary":"Send overdue payment reminder for one invoice","description":"Composes and queues a reminder email with the invoice PDF attached. Uses the organisation support email as From, the customer email as To, and respects a configurable cooldown window (default 72h) so admins don't accidentally spam the same client.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"recipientEmail":{"description":"Override the auto-resolved recipient (customer email). Useful when sending to an accountant or a billing contact instead of the primary email.","examples":["accountant@client.com"],"type":"string"},"ignoreCooldown":{"description":"Send even if a reminder was already sent recently. Default false — UI should warn the user when overriding cooldown.","default":false,"type":"boolean"},"cooldownHours":{"description":"Override the default cooldown window between reminders. Default 72 (3 days).","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"recipientEmail":{"description":"Override the auto-resolved recipient (customer email). Useful when sending to an accountant or a billing contact instead of the primary email.","examples":["accountant@client.com"],"type":"string"},"ignoreCooldown":{"description":"Send even if a reminder was already sent recently. Default false — UI should warn the user when overriding cooldown.","default":false,"type":"boolean"},"cooldownHours":{"description":"Override the default cooldown window between reminders. Default 72 (3 days).","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External invoice ID.","examples":["aB3xKm9pQ2wLn4Yz"],"type":"string"},"recipientEmail":{"description":"Override the auto-resolved recipient (customer email). Useful when sending to an accountant or a billing contact instead of the primary email.","examples":["accountant@client.com"],"type":"string"},"ignoreCooldown":{"description":"Send even if a reminder was already sent recently. Default false — UI should warn the user when overriding cooldown.","default":false,"type":"boolean"},"cooldownHours":{"description":"Override the default cooldown window between reminders. Default 72 (3 days).","type":"number"}}}}}}}},"/bff/invoice/send-reminders-bulk":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"sent":{"description":"Number of reminders actually queued.","type":"number"},"skipped":{"description":"Number of invoices skipped (paid, cancelled, cooldown, no recipient).","type":"number"},"errors":{"description":"Number of invoices that threw an error.","type":"number"},"rows":{"type":"array","items":{"type":"object","required":["id","outcome"],"properties":{"id":{"description":"External invoice ID.","type":"string"},"outcome":{"anyOf":[{"const":"sent","type":"string"},{"const":"skipped","type":"string"},{"const":"error","type":"string"}]},"reason":{"description":"Skip reason (when outcome is \"skipped\").","type":"string"},"recipient":{"description":"Email recipient (when outcome is \"sent\").","type":"string"},"error":{"description":"Error message (when outcome is \"error\").","type":"string"}}}}},"required":["sent","skipped","errors","rows"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"sent":{"description":"Number of reminders actually queued.","type":"number"},"skipped":{"description":"Number of invoices skipped (paid, cancelled, cooldown, no recipient).","type":"number"},"errors":{"description":"Number of invoices that threw an error.","type":"number"},"rows":{"type":"array","items":{"type":"object","required":["id","outcome"],"properties":{"id":{"description":"External invoice ID.","type":"string"},"outcome":{"anyOf":[{"const":"sent","type":"string"},{"const":"skipped","type":"string"},{"const":"error","type":"string"}]},"reason":{"description":"Skip reason (when outcome is \"skipped\").","type":"string"},"recipient":{"description":"Email recipient (when outcome is \"sent\").","type":"string"},"error":{"description":"Error message (when outcome is \"error\").","type":"string"}}}}},"required":["sent","skipped","errors","rows"]}},"text/plain":{"schema":{"type":"object","properties":{"sent":{"description":"Number of reminders actually queued.","type":"number"},"skipped":{"description":"Number of invoices skipped (paid, cancelled, cooldown, no recipient).","type":"number"},"errors":{"description":"Number of invoices that threw an error.","type":"number"},"rows":{"type":"array","items":{"type":"object","required":["id","outcome"],"properties":{"id":{"description":"External invoice ID.","type":"string"},"outcome":{"anyOf":[{"const":"sent","type":"string"},{"const":"skipped","type":"string"},{"const":"error","type":"string"}]},"reason":{"description":"Skip reason (when outcome is \"skipped\").","type":"string"},"recipient":{"description":"Email recipient (when outcome is \"sent\").","type":"string"},"error":{"description":"Error message (when outcome is \"error\").","type":"string"}}}}},"required":["sent","skipped","errors","rows"]}}}}},"operationId":"postBffInvoiceSend-reminders-bulk","tags":["Invoice"],"summary":"Send overdue payment reminders for multiple invoices","description":"Sequential per-invoice reminder dispatch. Returns a summary plus a per-invoice row so the UI can show which invoices were sent, which were skipped (and why), and which errored.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"description":"List of external invoice IDs.","minItems":1,"type":"array","items":{"description":"External invoice IDs to remind, in any order.","type":"string"}},"ignoreCooldown":{"description":"Ignore the per-invoice cooldown.","default":false,"type":"boolean"},"cooldownHours":{"description":"Override the default cooldown window (hours).","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"description":"List of external invoice IDs.","minItems":1,"type":"array","items":{"description":"External invoice IDs to remind, in any order.","type":"string"}},"ignoreCooldown":{"description":"Ignore the per-invoice cooldown.","default":false,"type":"boolean"},"cooldownHours":{"description":"Override the default cooldown window (hours).","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"description":"List of external invoice IDs.","minItems":1,"type":"array","items":{"description":"External invoice IDs to remind, in any order.","type":"string"}},"ignoreCooldown":{"description":"Ignore the per-invoice cooldown.","default":false,"type":"boolean"},"cooldownHours":{"description":"Override the default cooldown window (hours).","type":"number"}}}}}}}},"/bff/iot-lock/lock-list":{"get":{"responses":{"200":{"description":"Paginated list of locks with metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of locks matching the query criteria.","type":"array","items":{"description":"Single lock item in the list.","type":"object","required":["id","alias","active","isOnline","uptimePercent","insertedDate","updatedDate"],"properties":{"id":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"modelNum":{"description":"Lock hardware model number.","type":"string"},"mac":{"description":"Bluetooth MAC address of the lock.","type":"string"},"hasGateway":{"description":"Whether the lock is connected to a Wi-Fi gateway.","type":"boolean"},"featureValue":{"description":"TTLock feature bitmask value.","type":"string"},"firmwareVersion":{"description":"Current firmware revision.","type":"string"},"autoLockTime":{"description":"Auto-lock delay in seconds (0 = disabled).","type":"number"},"active":{"description":"Whether the lock is active in the system.","type":"boolean"},"isOnline":{"description":"Whether the lock gateway is currently online (no open outage incident).","type":"boolean"},"uptimePercent":{"description":"Gateway uptime percentage over the last 30 days (0–100).","type":"number"},"lastOnlineDate":{"description":"When the gateway was last seen online. Only present when currently offline.","anyOf":[{"description":"When the gateway was last seen online. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"currentOutageSince":{"description":"Start of the current outage. Only present when currently offline.","anyOf":[{"description":"Start of the current outage. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"administratorContactExternalId":{"description":"External ID of the assigned administrator contact.","type":"string"},"administratorName":{"description":"Full name of the assigned administrator (or email if name is not available).","type":"string"},"insertedDate":{"description":"Date when the lock was added to the system.","anyOf":[{"description":"Date when the lock was added to the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date of the last status update from TTLock API.","anyOf":[{"description":"Date of the last status update from TTLock API.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of non-deleted locks for pagination controls.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of locks matching the query criteria.","type":"array","items":{"description":"Single lock item in the list.","type":"object","required":["id","alias","active","isOnline","uptimePercent","insertedDate","updatedDate"],"properties":{"id":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"modelNum":{"description":"Lock hardware model number.","type":"string"},"mac":{"description":"Bluetooth MAC address of the lock.","type":"string"},"hasGateway":{"description":"Whether the lock is connected to a Wi-Fi gateway.","type":"boolean"},"featureValue":{"description":"TTLock feature bitmask value.","type":"string"},"firmwareVersion":{"description":"Current firmware revision.","type":"string"},"autoLockTime":{"description":"Auto-lock delay in seconds (0 = disabled).","type":"number"},"active":{"description":"Whether the lock is active in the system.","type":"boolean"},"isOnline":{"description":"Whether the lock gateway is currently online (no open outage incident).","type":"boolean"},"uptimePercent":{"description":"Gateway uptime percentage over the last 30 days (0–100).","type":"number"},"lastOnlineDate":{"description":"When the gateway was last seen online. Only present when currently offline.","anyOf":[{"description":"When the gateway was last seen online. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"currentOutageSince":{"description":"Start of the current outage. Only present when currently offline.","anyOf":[{"description":"Start of the current outage. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"administratorContactExternalId":{"description":"External ID of the assigned administrator contact.","type":"string"},"administratorName":{"description":"Full name of the assigned administrator (or email if name is not available).","type":"string"},"insertedDate":{"description":"Date when the lock was added to the system.","anyOf":[{"description":"Date when the lock was added to the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date of the last status update from TTLock API.","anyOf":[{"description":"Date of the last status update from TTLock API.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of non-deleted locks for pagination controls.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of locks matching the query criteria.","type":"array","items":{"description":"Single lock item in the list.","type":"object","required":["id","alias","active","isOnline","uptimePercent","insertedDate","updatedDate"],"properties":{"id":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"modelNum":{"description":"Lock hardware model number.","type":"string"},"mac":{"description":"Bluetooth MAC address of the lock.","type":"string"},"hasGateway":{"description":"Whether the lock is connected to a Wi-Fi gateway.","type":"boolean"},"featureValue":{"description":"TTLock feature bitmask value.","type":"string"},"firmwareVersion":{"description":"Current firmware revision.","type":"string"},"autoLockTime":{"description":"Auto-lock delay in seconds (0 = disabled).","type":"number"},"active":{"description":"Whether the lock is active in the system.","type":"boolean"},"isOnline":{"description":"Whether the lock gateway is currently online (no open outage incident).","type":"boolean"},"uptimePercent":{"description":"Gateway uptime percentage over the last 30 days (0–100).","type":"number"},"lastOnlineDate":{"description":"When the gateway was last seen online. Only present when currently offline.","anyOf":[{"description":"When the gateway was last seen online. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"currentOutageSince":{"description":"Start of the current outage. Only present when currently offline.","anyOf":[{"description":"Start of the current outage. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"administratorContactExternalId":{"description":"External ID of the assigned administrator contact.","type":"string"},"administratorName":{"description":"Full name of the assigned administrator (or email if name is not available).","type":"string"},"insertedDate":{"description":"Date when the lock was added to the system.","anyOf":[{"description":"Date when the lock was added to the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date of the last status update from TTLock API.","anyOf":[{"description":"Date of the last status update from TTLock API.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of non-deleted locks for pagination controls.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffIot-lockLock-list","tags":["IoT"],"summary":"List locks","description":"Returns a paginated list of TTLock smart locks for the authenticated organisation. Locks are ordered by active status, gateway connection, alias, and lock ID. Deleted locks are excluded. Each lock includes hardware metadata, battery level, and the assigned administrator contact (if any)."}},"/bff/iot-lock/lock-detail":{"get":{"parameters":[{"description":"TTLock lock ID (from TTLock API).","examples":["12345"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"backupPassword":{"description":"Current system-generated backup passcode for manual unlocking.","type":"string"},"backupPasswordInsertedDate":{"description":"Date when the backup password was generated.","anyOf":[{"description":"Date when the backup password was generated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the lock is active in the system.","type":"boolean"},"deleted":{"description":"Whether the lock has been soft-deleted.","type":"boolean"},"isOnline":{"description":"Whether the lock gateway is currently online (no open outage incident).","type":"boolean"},"uptimePercent":{"description":"Gateway uptime percentage over the last 30 days (0–100).","type":"number"},"lastOnlineDate":{"description":"When the gateway was last seen online. Only present when currently offline.","anyOf":[{"description":"When the gateway was last seen online. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"currentOutageSince":{"description":"Start of the current outage. Only present when currently offline.","anyOf":[{"description":"Start of the current outage. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"administratorContactExternalId":{"description":"External ID of the assigned administrator contact.","type":"string"},"administratorName":{"description":"Full name of the assigned administrator (or email if name is not available).","type":"string"},"insertedDate":{"description":"Date when the lock was added to the system.","anyOf":[{"description":"Date when the lock was added to the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date of the last status update from TTLock API.","anyOf":[{"description":"Date of the last status update from TTLock API.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","alias","active","deleted","isOnline","uptimePercent","insertedDate","updatedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"backupPassword":{"description":"Current system-generated backup passcode for manual unlocking.","type":"string"},"backupPasswordInsertedDate":{"description":"Date when the backup password was generated.","anyOf":[{"description":"Date when the backup password was generated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the lock is active in the system.","type":"boolean"},"deleted":{"description":"Whether the lock has been soft-deleted.","type":"boolean"},"isOnline":{"description":"Whether the lock gateway is currently online (no open outage incident).","type":"boolean"},"uptimePercent":{"description":"Gateway uptime percentage over the last 30 days (0–100).","type":"number"},"lastOnlineDate":{"description":"When the gateway was last seen online. Only present when currently offline.","anyOf":[{"description":"When the gateway was last seen online. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"currentOutageSince":{"description":"Start of the current outage. Only present when currently offline.","anyOf":[{"description":"Start of the current outage. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"administratorContactExternalId":{"description":"External ID of the assigned administrator contact.","type":"string"},"administratorName":{"description":"Full name of the assigned administrator (or email if name is not available).","type":"string"},"insertedDate":{"description":"Date when the lock was added to the system.","anyOf":[{"description":"Date when the lock was added to the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date of the last status update from TTLock API.","anyOf":[{"description":"Date of the last status update from TTLock API.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","alias","active","deleted","isOnline","uptimePercent","insertedDate","updatedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"alias":{"description":"Display name of the lock.","type":"string"},"electricQuantity":{"description":"Battery level percentage (0–100).","type":"number"},"backupPassword":{"description":"Current system-generated backup passcode for manual unlocking.","type":"string"},"backupPasswordInsertedDate":{"description":"Date when the backup password was generated.","anyOf":[{"description":"Date when the backup password was generated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the lock is active in the system.","type":"boolean"},"deleted":{"description":"Whether the lock has been soft-deleted.","type":"boolean"},"isOnline":{"description":"Whether the lock gateway is currently online (no open outage incident).","type":"boolean"},"uptimePercent":{"description":"Gateway uptime percentage over the last 30 days (0–100).","type":"number"},"lastOnlineDate":{"description":"When the gateway was last seen online. Only present when currently offline.","anyOf":[{"description":"When the gateway was last seen online. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"currentOutageSince":{"description":"Start of the current outage. Only present when currently offline.","anyOf":[{"description":"Start of the current outage. Only present when currently offline.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"administratorContactExternalId":{"description":"External ID of the assigned administrator contact.","type":"string"},"administratorName":{"description":"Full name of the assigned administrator (or email if name is not available).","type":"string"},"insertedDate":{"description":"Date when the lock was added to the system.","anyOf":[{"description":"Date when the lock was added to the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date of the last status update from TTLock API.","anyOf":[{"description":"Date of the last status update from TTLock API.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","alias","active","deleted","isOnline","uptimePercent","insertedDate","updatedDate"]}}}}},"operationId":"getBffIot-lockLock-detail","tags":["IoT"],"summary":"Get lock detail","description":"Returns full detail of a specific TTLock smart lock including battery level, backup password, active/deleted status, and the assigned administrator contact information."}},"/bff/iot-lock/lock-detail-refresh":{"get":{"parameters":[{"description":"TTLock lock ID (from TTLock API).","examples":["12345"],"schema":{"type":"string"},"in":"query","name":"lockId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful refresh.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful refresh.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful refresh.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffIot-lockLock-detail-refresh","tags":["IoT"],"summary":"Refresh lock status","description":"Fetches the latest lock status from the TTLock API and updates the local database. This includes battery level, gateway connection status, firmware version, and other hardware metadata. If the gateway connection changes, a system log entry is created and email notifications are sent. If battery drops below 25%, a critical notification is triggered. Also auto-generates a new backup password when gateway reconnects."}},"/bff/iot-lock/lock-electric-quantity-list":{"get":{"parameters":[{"description":"TTLock lock ID (from TTLock API).","examples":["12345"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of battery level readings ordered by date.","type":"array","items":{"description":"Single battery level measurement.","type":"object","required":["id","quantity","insertedDate"],"properties":{"id":{"description":"Record ID.","type":"number"},"quantity":{"description":"Battery level percentage (0–100) at the time of measurement.","type":"number"},"insertedDate":{"description":"Date when the measurement was recorded.","anyOf":[{"description":"Date when the measurement was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of battery level records.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of battery level readings ordered by date.","type":"array","items":{"description":"Single battery level measurement.","type":"object","required":["id","quantity","insertedDate"],"properties":{"id":{"description":"Record ID.","type":"number"},"quantity":{"description":"Battery level percentage (0–100) at the time of measurement.","type":"number"},"insertedDate":{"description":"Date when the measurement was recorded.","anyOf":[{"description":"Date when the measurement was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of battery level records.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of battery level readings ordered by date.","type":"array","items":{"description":"Single battery level measurement.","type":"object","required":["id","quantity","insertedDate"],"properties":{"id":{"description":"Record ID.","type":"number"},"quantity":{"description":"Battery level percentage (0–100) at the time of measurement.","type":"number"},"insertedDate":{"description":"Date when the measurement was recorded.","anyOf":[{"description":"Date when the measurement was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of battery level records.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffIot-lockLock-electric-quantity-list","tags":["IoT"],"summary":"List battery level history","description":"Returns the history of battery level (electric quantity) readings for a specific lock. Each entry records the battery percentage at a given point in time. Useful for monitoring battery health trends and predicting when replacement is needed."}},"/bff/iot-lock/unlock-now":{"get":{"parameters":[{"description":"TTLock lock ID (from TTLock API).","examples":["12345"],"schema":{"type":"string"},"in":"query","name":"lockId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"True if the unlock command was sent successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"True if the unlock command was sent successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"True if the unlock command was sent successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffIot-lockUnlock-now","tags":["IoT"],"summary":"Unlock lock remotely","description":"Sends an immediate remote unlock command to the lock via the TTLock API. Requires that the lock is connected to a Wi-Fi gateway. The lock must be active and not deleted."}},"/bff/iot-lock/unlock-record-list":{"get":{"parameters":[{"description":"TTLock lock ID (from TTLock API).","examples":["12345"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"description":"Paginated list of unlock/lock history records.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of unlock/lock records.","type":"array","items":{"description":"Single unlock/lock history record.","type":"object","required":["id","success","serverDate","recordType","recordTypeFromLock","insertedDate"],"properties":{"id":{"description":"TTLock record ID.","type":"number"},"success":{"description":"Whether the unlock/lock action was successful.","type":"boolean"},"lockDate":{"description":"Timestamp of the action from the lock device.","anyOf":[{"description":"Timestamp of the action from the lock device.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"serverDate":{"description":"Timestamp of the action from the TTLock server.","anyOf":[{"description":"Timestamp of the action from the TTLock server.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"recordType":{"description":"Translated record type label (e.g. \"Unlock via app\").","type":"string"},"recordTypeFromLock":{"description":"Translated record type from the lock hardware.","type":"string"},"keyboardPassword":{"description":"Keyboard password used for the action (if applicable).","type":"string"},"insertedDate":{"description":"Date when the record was stored locally.","anyOf":[{"description":"Date when the record was stored locally.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of records for pagination.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of unlock/lock records.","type":"array","items":{"description":"Single unlock/lock history record.","type":"object","required":["id","success","serverDate","recordType","recordTypeFromLock","insertedDate"],"properties":{"id":{"description":"TTLock record ID.","type":"number"},"success":{"description":"Whether the unlock/lock action was successful.","type":"boolean"},"lockDate":{"description":"Timestamp of the action from the lock device.","anyOf":[{"description":"Timestamp of the action from the lock device.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"serverDate":{"description":"Timestamp of the action from the TTLock server.","anyOf":[{"description":"Timestamp of the action from the TTLock server.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"recordType":{"description":"Translated record type label (e.g. \"Unlock via app\").","type":"string"},"recordTypeFromLock":{"description":"Translated record type from the lock hardware.","type":"string"},"keyboardPassword":{"description":"Keyboard password used for the action (if applicable).","type":"string"},"insertedDate":{"description":"Date when the record was stored locally.","anyOf":[{"description":"Date when the record was stored locally.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of records for pagination.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of unlock/lock records.","type":"array","items":{"description":"Single unlock/lock history record.","type":"object","required":["id","success","serverDate","recordType","recordTypeFromLock","insertedDate"],"properties":{"id":{"description":"TTLock record ID.","type":"number"},"success":{"description":"Whether the unlock/lock action was successful.","type":"boolean"},"lockDate":{"description":"Timestamp of the action from the lock device.","anyOf":[{"description":"Timestamp of the action from the lock device.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"serverDate":{"description":"Timestamp of the action from the TTLock server.","anyOf":[{"description":"Timestamp of the action from the TTLock server.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"recordType":{"description":"Translated record type label (e.g. \"Unlock via app\").","type":"string"},"recordTypeFromLock":{"description":"Translated record type from the lock hardware.","type":"string"},"keyboardPassword":{"description":"Keyboard password used for the action (if applicable).","type":"string"},"insertedDate":{"description":"Date when the record was stored locally.","anyOf":[{"description":"Date when the record was stored locally.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of records for pagination.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffIot-lockUnlock-record-list","tags":["IoT"],"summary":"List unlock records","description":"Returns a paginated list of unlock/lock history records for a specific lock. Each record includes the action type (unlock, lock, auto-lock, etc.), success status, timestamp, and the keyboard password used (if applicable). Record type labels are translated based on the provided locale."}},"/bff/iot-lock/lock-add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful registration.","type":"boolean"},"lockId":{"description":"The TTLock lock ID that was registered.","type":"number"}},"required":["success","lockId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful registration.","type":"boolean"},"lockId":{"description":"The TTLock lock ID that was registered.","type":"number"}},"required":["success","lockId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful registration.","type":"boolean"},"lockId":{"description":"The TTLock lock ID that was registered.","type":"number"}},"required":["success","lockId"]}}}}},"operationId":"postBffIot-lockLock-add","tags":["IoT"],"summary":"Add new lock","description":"Registers a new TTLock smart lock for the authenticated organisation. The lock ID must be obtained from the TTLock API or mobile app. After adding, the lock status is fetched from the TTLock API to populate initial metadata.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["lockId"],"properties":{"lockId":{"description":"TTLock lock ID to add (from the TTLock API/app).","examples":["12345"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["lockId"],"properties":{"lockId":{"description":"TTLock lock ID to add (from the TTLock API/app).","examples":["12345"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["lockId"],"properties":{"lockId":{"description":"TTLock lock ID to add (from the TTLock API/app).","examples":["12345"],"type":"string"}}}}}}}},"/bff/iot-lock/password-list":{"get":{"parameters":[{"description":"TTLock lock ID (from TTLock API).","examples":["12345"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"description":"Paginated list of keyboard passcodes.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of keyboard passcodes.","type":"array","items":{"description":"Single keyboard passcode item.","type":"object","required":["id","active","deleted","eventList","sendDate","insertedDate"],"properties":{"id":{"description":"TTLock keyboard password ID.","type":"number"},"active":{"description":"Whether the passcode is currently active (not deleted, within date range).","type":"boolean"},"deleted":{"description":"Whether the passcode has been soft-deleted.","type":"boolean"},"password":{"description":"The keyboard passcode digits.","type":"string"},"eventList":{"description":"Calendar events linked to this passcode.","type":"array","items":{"type":"object","required":["title","calendarCode","eventCode"],"properties":{"title":{"description":"Calendar event title.","type":"string"},"calendarCode":{"description":"Calendar external code.","type":"string"},"eventCode":{"description":"Calendar event external code.","type":"string"}}}},"startDate":{"description":"Date when the passcode becomes active.","anyOf":[{"description":"Date when the passcode becomes active.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endDate":{"description":"Date when the passcode expires.","anyOf":[{"description":"Date when the passcode expires.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"sendDate":{"description":"Date when the passcode was sent to the lock.","anyOf":[{"description":"Date when the passcode was sent to the lock.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the passcode was created in the system.","anyOf":[{"description":"Date when the passcode was created in the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of passcodes for pagination.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of keyboard passcodes.","type":"array","items":{"description":"Single keyboard passcode item.","type":"object","required":["id","active","deleted","eventList","sendDate","insertedDate"],"properties":{"id":{"description":"TTLock keyboard password ID.","type":"number"},"active":{"description":"Whether the passcode is currently active (not deleted, within date range).","type":"boolean"},"deleted":{"description":"Whether the passcode has been soft-deleted.","type":"boolean"},"password":{"description":"The keyboard passcode digits.","type":"string"},"eventList":{"description":"Calendar events linked to this passcode.","type":"array","items":{"type":"object","required":["title","calendarCode","eventCode"],"properties":{"title":{"description":"Calendar event title.","type":"string"},"calendarCode":{"description":"Calendar external code.","type":"string"},"eventCode":{"description":"Calendar event external code.","type":"string"}}}},"startDate":{"description":"Date when the passcode becomes active.","anyOf":[{"description":"Date when the passcode becomes active.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endDate":{"description":"Date when the passcode expires.","anyOf":[{"description":"Date when the passcode expires.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"sendDate":{"description":"Date when the passcode was sent to the lock.","anyOf":[{"description":"Date when the passcode was sent to the lock.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the passcode was created in the system.","anyOf":[{"description":"Date when the passcode was created in the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of passcodes for pagination.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of keyboard passcodes.","type":"array","items":{"description":"Single keyboard passcode item.","type":"object","required":["id","active","deleted","eventList","sendDate","insertedDate"],"properties":{"id":{"description":"TTLock keyboard password ID.","type":"number"},"active":{"description":"Whether the passcode is currently active (not deleted, within date range).","type":"boolean"},"deleted":{"description":"Whether the passcode has been soft-deleted.","type":"boolean"},"password":{"description":"The keyboard passcode digits.","type":"string"},"eventList":{"description":"Calendar events linked to this passcode.","type":"array","items":{"type":"object","required":["title","calendarCode","eventCode"],"properties":{"title":{"description":"Calendar event title.","type":"string"},"calendarCode":{"description":"Calendar external code.","type":"string"},"eventCode":{"description":"Calendar event external code.","type":"string"}}}},"startDate":{"description":"Date when the passcode becomes active.","anyOf":[{"description":"Date when the passcode becomes active.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endDate":{"description":"Date when the passcode expires.","anyOf":[{"description":"Date when the passcode expires.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"sendDate":{"description":"Date when the passcode was sent to the lock.","anyOf":[{"description":"Date when the passcode was sent to the lock.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the passcode was created in the system.","anyOf":[{"description":"Date when the passcode was created in the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of passcodes for pagination.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffIot-lockPassword-list","tags":["IoT"],"summary":"List lock passcodes","description":"Returns a paginated list of keyboard passcodes for a specific lock. Each passcode includes its validity period, active/deleted status, and linked calendar events (if the passcode was generated for a booking)."}},"/bff/iot-lock/password-add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful passcode creation.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful passcode creation.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful passcode creation.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffIot-lockPassword-add","tags":["IoT"],"summary":"Create new passcode","description":"Creates a new keyboard passcode for a specific lock and sends it to the lock via the TTLock API. If no password is provided, a unique random 8-digit code is generated (retries up to 50 times to avoid duplicates). Start and end dates define the validity window; the system applies configured time offsets automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["lockId"],"properties":{"lockId":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"password":{"description":"Custom passcode digits. If not provided, a random 8-digit code is generated.","type":"string"},"passwordName":{"maxLength":250,"description":"Human-readable label for the passcode (max 250 chars, ASCII only).","type":"string"},"startDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 date-time when the passcode becomes active. Defaults to now.","type":"string"},"endDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 date-time when the passcode expires. If not set, the passcode is permanent.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["lockId"],"properties":{"lockId":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"password":{"description":"Custom passcode digits. If not provided, a random 8-digit code is generated.","type":"string"},"passwordName":{"maxLength":250,"description":"Human-readable label for the passcode (max 250 chars, ASCII only).","type":"string"},"startDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 date-time when the passcode becomes active. Defaults to now.","type":"string"},"endDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 date-time when the passcode expires. If not set, the passcode is permanent.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["lockId"],"properties":{"lockId":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"password":{"description":"Custom passcode digits. If not provided, a random 8-digit code is generated.","type":"string"},"passwordName":{"maxLength":250,"description":"Human-readable label for the passcode (max 250 chars, ASCII only).","type":"string"},"startDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 date-time when the passcode becomes active. Defaults to now.","type":"string"},"endDate":{"format":"date-time","examples":["2024-05-01T10:00:00.000Z"],"description":"ISO 8601 date-time when the passcode expires. If not set, the passcode is permanent.","type":"string"}}}}}}}},"/bff/iot-lock/password-delete":{"get":{"parameters":[{"description":"TTLock keyboard password ID to delete.","examples":["98765"],"schema":{"type":"string"},"in":"query","name":"keyboardPwdId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful deletion.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful deletion.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful deletion.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffIot-lockPassword-delete","tags":["IoT"],"summary":"Delete passcode","description":"Deletes a keyboard passcode from the lock via the TTLock API and marks it as deleted locally. The passcode is verified to belong to the authenticated organisation before deletion."}},"/bff/iot-lock/save-settings":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful update.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful update.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on successful update.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffIot-lockSave-settings","tags":["IoT"],"summary":"Update lock settings","description":"Updates the active/deleted status and administrator assignment for a specific lock. The administrator contact is resolved by external ID and must belong to the same organisation. When an administrator is set, they receive CC on all system notification emails triggered by this lock.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["lockId","active","deleted"],"properties":{"lockId":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"active":{"description":"Whether the lock should be active. Inactive locks are excluded from status checks and notifications.","type":"boolean"},"deleted":{"description":"Whether to soft-delete the lock. Deleted locks are hidden from the list.","type":"boolean"},"administratorContactExternalId":{"description":"External ID of the contact to assign as lock administrator. The administrator receives email notifications for all critical lock events (gateway offline, battery critical, API errors). Pass empty or omit to remove the administrator.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["lockId","active","deleted"],"properties":{"lockId":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"active":{"description":"Whether the lock should be active. Inactive locks are excluded from status checks and notifications.","type":"boolean"},"deleted":{"description":"Whether to soft-delete the lock. Deleted locks are hidden from the list.","type":"boolean"},"administratorContactExternalId":{"description":"External ID of the contact to assign as lock administrator. The administrator receives email notifications for all critical lock events (gateway offline, battery critical, API errors). Pass empty or omit to remove the administrator.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["lockId","active","deleted"],"properties":{"lockId":{"description":"TTLock lock ID (from TTLock API).","type":"number"},"active":{"description":"Whether the lock should be active. Inactive locks are excluded from status checks and notifications.","type":"boolean"},"deleted":{"description":"Whether to soft-delete the lock. Deleted locks are hidden from the list.","type":"boolean"},"administratorContactExternalId":{"description":"External ID of the contact to assign as lock administrator. The administrator receives email notifications for all critical lock events (gateway offline, battery critical, API errors). Pass empty or omit to remove the administrator.","type":"string"}}}}}}}},"/bff/iot-lock/credentials-detail":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"description":"TTLock OAuth2 client ID (app identifier issued by TTLock). Empty string when not set.","type":"string"},"clientSecretIsSet":{"description":"True when a non-empty ttlock_client_secret is stored. The value itself is never returned.","type":"boolean"},"username":{"description":"TTLock account username / e-mail. Empty string when not set.","type":"string"},"passwordIsSet":{"description":"True when a non-empty ttlock_password (MD5) is stored. The value itself is never returned.","type":"boolean"}},"required":["clientId","clientSecretIsSet","username","passwordIsSet"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"clientId":{"description":"TTLock OAuth2 client ID (app identifier issued by TTLock). Empty string when not set.","type":"string"},"clientSecretIsSet":{"description":"True when a non-empty ttlock_client_secret is stored. The value itself is never returned.","type":"boolean"},"username":{"description":"TTLock account username / e-mail. Empty string when not set.","type":"string"},"passwordIsSet":{"description":"True when a non-empty ttlock_password (MD5) is stored. The value itself is never returned.","type":"boolean"}},"required":["clientId","clientSecretIsSet","username","passwordIsSet"]}},"text/plain":{"schema":{"type":"object","properties":{"clientId":{"description":"TTLock OAuth2 client ID (app identifier issued by TTLock). Empty string when not set.","type":"string"},"clientSecretIsSet":{"description":"True when a non-empty ttlock_client_secret is stored. The value itself is never returned.","type":"boolean"},"username":{"description":"TTLock account username / e-mail. Empty string when not set.","type":"string"},"passwordIsSet":{"description":"True when a non-empty ttlock_password (MD5) is stored. The value itself is never returned.","type":"boolean"}},"required":["clientId","clientSecretIsSet","username","passwordIsSet"]}}}}},"operationId":"getBffIot-lockCredentials-detail","tags":["IoT"],"summary":"Get TTLock credentials status","description":"Returns the TTLock OAuth2 credentials currently configured for the authenticated organisation. Non-secret values (clientId, username) are returned in full so the frontend can display and pre-fill them. Secret values (clientSecret, password) are never returned — instead the response contains boolean flags (clientSecretIsSet, passwordIsSet) indicating whether each secret is configured. The auto-managed access and refresh tokens are never exposed by this endpoint."}},"/bff/iot-lock/credentials-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"True if TTLock accepted the credentials and they were persisted.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"True if TTLock accepted the credentials and they were persisted.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"True if TTLock accepted the credentials and they were persisted.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffIot-lockCredentials-update","tags":["IoT"],"summary":"Update TTLock account credentials","description":"Verifies a new TTLock OAuth2 credential set against euapi.ttlock.com/oauth2/token and, on success, persists it. Only `password` is required in the body — the other three fields (clientId, clientSecret, username) are optional and fall back to the values already stored in the organisation configuration. This makes the common case of \"my TTLock app password was reset\" a single-field call, without needing to re-enter the clientSecret (which is only obtainable from the TTLock developer portal). Fields that were actually supplied (non-empty) are written back to the config; fields left out are kept as-is. The plain-text password is always MD5-hashed server-side. After a successful OAuth response the new MD5 password plus fresh access and refresh tokens are persisted atomically. Any TTLock-side failure (invalid credentials, invalid client, etc.) is thrown as an Error and surfaced by the standard API error-logging layer.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["password"],"properties":{"clientId":{"description":"TTLock OAuth2 client ID (app-level identifier issued by TTLock developer portal). Optional — when omitted or empty, the previously stored value is used. Only send when rotating app credentials; day-to-day password resets do not need it.","type":"string"},"clientSecret":{"description":"TTLock OAuth2 client secret. Optional — when omitted or empty, the previously stored value is used. Only obtainable from the TTLock developer portal, not from the TTLock mobile app, so regular users should not need to enter it.","type":"string"},"username":{"description":"TTLock account username (the e-mail used in the TTLock mobile app). Optional — when omitted or empty, the previously stored value is used. Send only when the TTLock account itself changes.","examples":["alexander.dioszeghy@gmail.com"],"type":"string"},"password":{"description":"TTLock account password in plain text. Required. MD5-hashed server-side before being sent to TTLock and before being stored. Primary field for the common case of recovering after a password change in the TTLock mobile app.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["password"],"properties":{"clientId":{"description":"TTLock OAuth2 client ID (app-level identifier issued by TTLock developer portal). Optional — when omitted or empty, the previously stored value is used. Only send when rotating app credentials; day-to-day password resets do not need it.","type":"string"},"clientSecret":{"description":"TTLock OAuth2 client secret. Optional — when omitted or empty, the previously stored value is used. Only obtainable from the TTLock developer portal, not from the TTLock mobile app, so regular users should not need to enter it.","type":"string"},"username":{"description":"TTLock account username (the e-mail used in the TTLock mobile app). Optional — when omitted or empty, the previously stored value is used. Send only when the TTLock account itself changes.","examples":["alexander.dioszeghy@gmail.com"],"type":"string"},"password":{"description":"TTLock account password in plain text. Required. MD5-hashed server-side before being sent to TTLock and before being stored. Primary field for the common case of recovering after a password change in the TTLock mobile app.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["password"],"properties":{"clientId":{"description":"TTLock OAuth2 client ID (app-level identifier issued by TTLock developer portal). Optional — when omitted or empty, the previously stored value is used. Only send when rotating app credentials; day-to-day password resets do not need it.","type":"string"},"clientSecret":{"description":"TTLock OAuth2 client secret. Optional — when omitted or empty, the previously stored value is used. Only obtainable from the TTLock developer portal, not from the TTLock mobile app, so regular users should not need to enter it.","type":"string"},"username":{"description":"TTLock account username (the e-mail used in the TTLock mobile app). Optional — when omitted or empty, the previously stored value is used. Send only when the TTLock account itself changes.","examples":["alexander.dioszeghy@gmail.com"],"type":"string"},"password":{"description":"TTLock account password in plain text. Required. MD5-hashed server-side before being sent to TTLock and before being stored. Primary field for the common case of recovering after a password change in the TTLock mobile app.","type":"string"}}}}}}}},"/bff/iot-lock/queue-stats":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"depth":{"description":"Unprocessed rows still eligible for retry (ttl > 0).","type":"number"},"dead":{"description":"Unprocessed rows that exhausted retries (ttl = 0). Manual action required.","type":"number"},"calls24h":{"description":"All queue rows inserted in the last 24 hours.","type":"number"},"retries24h":{"description":"Rows in the last 24 hours retried at least once.","type":"number"},"errors24h":{"description":"Rows in the last 24 hours with a non-null error_response.","type":"number"}},"required":["depth","dead","calls24h","retries24h","errors24h"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"depth":{"description":"Unprocessed rows still eligible for retry (ttl > 0).","type":"number"},"dead":{"description":"Unprocessed rows that exhausted retries (ttl = 0). Manual action required.","type":"number"},"calls24h":{"description":"All queue rows inserted in the last 24 hours.","type":"number"},"retries24h":{"description":"Rows in the last 24 hours retried at least once.","type":"number"},"errors24h":{"description":"Rows in the last 24 hours with a non-null error_response.","type":"number"}},"required":["depth","dead","calls24h","retries24h","errors24h"]}},"text/plain":{"schema":{"type":"object","properties":{"depth":{"description":"Unprocessed rows still eligible for retry (ttl > 0).","type":"number"},"dead":{"description":"Unprocessed rows that exhausted retries (ttl = 0). Manual action required.","type":"number"},"calls24h":{"description":"All queue rows inserted in the last 24 hours.","type":"number"},"retries24h":{"description":"Rows in the last 24 hours retried at least once.","type":"number"},"errors24h":{"description":"Rows in the last 24 hours with a non-null error_response.","type":"number"}},"required":["depth","dead","calls24h","retries24h","errors24h"]}}}}},"operationId":"getBffIot-lockQueue-stats","tags":["IoT"],"summary":"TTLock API queue health","description":"Aggregate counters over `iot__ttlock_queue` scoped to the caller organisation. Powers the small \"API: 12 calls/min, 2 retry, 0 dead\" widget in admin. Values are point-in-time; the queue itself is drained by the medium-priority cron worker `processTTLockQueue`."}},"/bff/iot-lock/activity-timeline":{"get":{"parameters":[{"description":"TTLock lock ID (from TTLock API).","examples":["12345"],"schema":{"type":"string"},"in":"query","name":"lockId","required":true},{"description":"ISO timestamp. Defaults to 7 days ago.","schema":{"type":"string"},"in":"query","name":"since","required":false},{"description":"ISO timestamp. Defaults to now.","schema":{"type":"string"},"in":"query","name":"until","required":false},{"description":"Comma-separated activity kinds. One of: unlock_attempt, api_call, passcode_op, gateway_event, battery_event, system_log.","schema":{"type":"string"},"in":"query","name":"kinds","required":false},{"description":"Comma-separated severity levels. One of: info, success, error, warning, critical.","schema":{"type":"string"},"in":"query","name":"levels","required":false},{"description":"Page size, default 100, max 500.","schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Offset for pagination, default 0.","schema":{"type":"string"},"in":"query","name":"offset","required":false}],"operationId":"getBffIot-lockActivity-timeline","tags":["IoT"],"summary":"Per-lock activity timeline","description":"Unified time-ordered feed of everything that has happened with a given lock: unlock attempts, TTLock API calls (failed only), passcode operations (create / delete), gateway online/offline transitions, battery readings, and system log entries scoped to TTLock components. Powers the Activity log tab on the lock detail page. Result is paginated; default window is the last 7 days.","responses":{"200":{}}}},"/bff/iot-lock/health-overview":{"get":{"operationId":"getBffIot-lockHealth-overview","tags":["IoT"],"summary":"Organisation-wide lock health","description":"Counters and small \"top-N worst\" subsets across all active, non-deleted locks of the caller organisation: total/online/offline, backup status buckets (ok / expiring_soon / missing / expired / ignored), low and critical battery lists, currently open outages, worst 5 uptime locks, plus 24h TTLock API health.","responses":{"200":{}}}},"/bff/member/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Full-text search across member name and email.","schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false}],"operationId":"getBffMemberList","tags":["Member"],"summary":"List organisation members","description":"Returns a paginated list of organisation members with their roles, activity status and avatar info. Includes pending invitations (members with `isPending: true` and `id` prefixed with `pending-`).","responses":{"200":{}}}},"/bff/member/detail":{"get":{"parameters":[{"description":"Identifier of the member. For active members it is `shop__contact.external_id`; for pending invitations it is `pending-<token>`.","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffMemberDetail","tags":["Member"],"summary":"Get member detail","description":"Returns detailed information about a specific organisation member. Includes user profile data, contact information, activity status, and timezone settings. Pending invitations are also supported — pass `pending-<token>` as the `id`.","responses":{"200":{}}}},"/bff/member/invite-email":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"status":{"anyOf":[{"const":"pending","type":"string"},{"const":"added-existing-user","type":"string"}]},"memberId":{"description":"External id of the new (or pending) member — for routing to detail.","type":"string"}},"required":["success","status","memberId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"status":{"anyOf":[{"const":"pending","type":"string"},{"const":"added-existing-user","type":"string"}]},"memberId":{"description":"External id of the new (or pending) member — for routing to detail.","type":"string"}},"required":["success","status","memberId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"status":{"anyOf":[{"const":"pending","type":"string"},{"const":"added-existing-user","type":"string"}]},"memberId":{"description":"External id of the new (or pending) member — for routing to detail.","type":"string"}},"required":["success","status","memberId"]}}}}},"operationId":"postBffMemberInvite-email","tags":["Member"],"summary":"Invite member by email","description":"Sends an invitation e-mail to join the organisation. If the e-mail already belongs to a registered user the member is added immediately (and the pre-granted permissions are applied); otherwise a pending invitation is created — admin can still edit its permissions before the invitee accepts.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Optional first name pre-filled on the registration form.","maxLength":128,"type":"string"},"lastName":{"description":"Optional last name pre-filled on the registration form.","maxLength":128,"type":"string"},"permissionCodes":{"description":"Permission codes to grant when the invitation is accepted.","type":"array","items":{"type":"string"}},"roleCodes":{"description":"Role codes to grant when the invitation is accepted.","type":"array","items":{"type":"string"}},"description":{"description":"Internal note about this invitation.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Optional first name pre-filled on the registration form.","maxLength":128,"type":"string"},"lastName":{"description":"Optional last name pre-filled on the registration form.","maxLength":128,"type":"string"},"permissionCodes":{"description":"Permission codes to grant when the invitation is accepted.","type":"array","items":{"type":"string"}},"roleCodes":{"description":"Role codes to grant when the invitation is accepted.","type":"array","items":{"type":"string"}},"description":{"description":"Internal note about this invitation.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Optional first name pre-filled on the registration form.","maxLength":128,"type":"string"},"lastName":{"description":"Optional last name pre-filled on the registration form.","maxLength":128,"type":"string"},"permissionCodes":{"description":"Permission codes to grant when the invitation is accepted.","type":"array","items":{"type":"string"}},"roleCodes":{"description":"Role codes to grant when the invitation is accepted.","type":"array","items":{"type":"string"}},"description":{"description":"Internal note about this invitation.","type":"string"}}}}}}}},"/bff/member/resend-invite":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberResend-invite","tags":["Member"],"summary":"Resend a pending invitation","description":"Sends the invitation e-mail again and resets its expiration timer.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Pending invitation id (`pending-<token>`).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Pending invitation id (`pending-<token>`).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Pending invitation id (`pending-<token>`).","type":"string"}}}}}}}},"/bff/member/cancel-invite":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberCancel-invite","tags":["Member"],"summary":"Cancel a pending invitation","description":"Deletes the pending invitation, invalidating the registration link in the e-mail that was sent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Pending invitation id (`pending-<token>`).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Pending invitation id (`pending-<token>`).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Pending invitation id (`pending-<token>`).","type":"string"}}}}}}}},"/bff/member/confirm-invite":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberConfirm-invite","tags":["Member"],"summary":"Confirm member invitation","description":"Completes the member invitation flow — creates the user account and links them to the organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","locale","firstName","lastName","password","checkboxTerms","checkboxMarketing"],"properties":{"token":{"description":"Invitation token from the email link.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"firstName":{"description":"New member first name.","examples":["Jan"],"type":"string"},"lastName":{"description":"New member last name.","examples":["Novák"],"type":"string"},"password":{"description":"Account password (min 8 chars).","minLength":8,"type":"string"},"checkboxTerms":{"description":"Accepted terms of service.","type":"boolean"},"checkboxMarketing":{"description":"Accepted marketing communications.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["token","locale","firstName","lastName","password","checkboxTerms","checkboxMarketing"],"properties":{"token":{"description":"Invitation token from the email link.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"firstName":{"description":"New member first name.","examples":["Jan"],"type":"string"},"lastName":{"description":"New member last name.","examples":["Novák"],"type":"string"},"password":{"description":"Account password (min 8 chars).","minLength":8,"type":"string"},"checkboxTerms":{"description":"Accepted terms of service.","type":"boolean"},"checkboxMarketing":{"description":"Accepted marketing communications.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["token","locale","firstName","lastName","password","checkboxTerms","checkboxMarketing"],"properties":{"token":{"description":"Invitation token from the email link.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"firstName":{"description":"New member first name.","examples":["Jan"],"type":"string"},"lastName":{"description":"New member last name.","examples":["Novák"],"type":"string"},"password":{"description":"Account password (min 8 chars).","minLength":8,"type":"string"},"checkboxTerms":{"description":"Accepted terms of service.","type":"boolean"},"checkboxMarketing":{"description":"Accepted marketing communications.","type":"boolean"}}}}}}}},"/bff/member/invite-detail":{"get":{"parameters":[{"description":"Invitation token from the email link.","schema":{"type":"string"},"in":"query","name":"token","required":true}],"operationId":"getBffMemberInvite-detail","tags":["Member"],"summary":"Get invitation details","description":"Returns details about a pending member invitation — organisation name, invitee email, etc.","responses":{"200":{}}}},"/bff/member/permissions":{"get":{"parameters":[{"description":"Identifier of the member (`shop__contact.external_id` for active members, `pending-<token>` for pending invitations).","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffMemberPermissions","tags":["Member"],"summary":"Get member permissions","description":"Returns all permissions assigned to a specific member. Includes both direct permissions and role-based permissions. Each permission shows its source (direct assignment or via role). For pending invitations, returns the pre-granted permissions stored on the invitation row.","responses":{"200":{}}}},"/bff/member/available-permissions":{"get":{"operationId":"getBffMemberAvailable-permissions","tags":["Member"],"summary":"Get available permissions and roles","description":"Returns all available permissions and roles in the system that can be assigned to members. Use this to populate permission/role selection UI when editing member permissions.","responses":{"200":{}}}},"/bff/member/save-permissions":{"post":{"parameters":[],"responses":{"200":{"description":"Permissions saved successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberSave-permissions","tags":["Member"],"summary":"Save member permissions","description":"Updates the permissions and roles assigned to a member. For active members this replaces all existing direct permissions and role assignments. For pending invitations the values are stored on the invitation row and applied when the invitee confirms.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Identifier of the member (`shop__contact.external_id` for active members, `pending-<token>` for pending invitations).","type":"string"},"permissionCodes":{"description":"Legacy array of permission codes (no expiry). Ignored if `permissionGrants` is set.","type":"array","items":{"description":"Permission code.","type":"string"}},"roleCodes":{"description":"Legacy array of role codes (no expiry). Ignored if `roleGrants` is set.","type":"array","items":{"description":"Role code.","type":"string"}},"permissionGrants":{"description":"Granular permission grants with optional per-code expiry.","type":"array","items":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"validTo":{"anyOf":[{"description":"ISO timestamp when the grant expires.","type":"string"},{"type":"null"}]}}}},"roleGrants":{"description":"Granular role grants with optional per-code expiry.","type":"array","items":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Identifier of the member (`shop__contact.external_id` for active members, `pending-<token>` for pending invitations).","type":"string"},"permissionCodes":{"description":"Legacy array of permission codes (no expiry). Ignored if `permissionGrants` is set.","type":"array","items":{"description":"Permission code.","type":"string"}},"roleCodes":{"description":"Legacy array of role codes (no expiry). Ignored if `roleGrants` is set.","type":"array","items":{"description":"Role code.","type":"string"}},"permissionGrants":{"description":"Granular permission grants with optional per-code expiry.","type":"array","items":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"validTo":{"anyOf":[{"description":"ISO timestamp when the grant expires.","type":"string"},{"type":"null"}]}}}},"roleGrants":{"description":"Granular role grants with optional per-code expiry.","type":"array","items":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Identifier of the member (`shop__contact.external_id` for active members, `pending-<token>` for pending invitations).","type":"string"},"permissionCodes":{"description":"Legacy array of permission codes (no expiry). Ignored if `permissionGrants` is set.","type":"array","items":{"description":"Permission code.","type":"string"}},"roleCodes":{"description":"Legacy array of role codes (no expiry). Ignored if `roleGrants` is set.","type":"array","items":{"description":"Role code.","type":"string"}},"permissionGrants":{"description":"Granular permission grants with optional per-code expiry.","type":"array","items":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"validTo":{"anyOf":[{"description":"ISO timestamp when the grant expires.","type":"string"},{"type":"null"}]}}}},"roleGrants":{"description":"Granular role grants with optional per-code expiry.","type":"array","items":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}}}}},"/bff/member/block":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberBlock","tags":["Member"],"summary":"Block/unblock member","description":"Toggles the blocked state of a member. Blocked members cannot access the organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"}}}}}}}},"/bff/member/activity":{"get":{"parameters":[{"description":"External member id (shop__contact.external_id) of the timeline owner.","schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"ISO timestamp; rows strictly older than this are returned.","schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"description":"Page size, 1..100, default 30.","schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Comma-separated component filter (security,order,…).","schema":{"type":"string"},"in":"query","name":"components","required":false},{"description":"Minimum severity: info | success | warning | error | critical.","schema":{"type":"string"},"in":"query","name":"minLevel","required":false}],"operationId":"getBffMemberActivity","tags":["Member"],"summary":"Member activity timeline","responses":{"200":{}}}},"/bff/member/assigned-work":{"get":{"parameters":[{"description":"External member id.","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffMemberAssigned-work","tags":["Member"],"summary":"Open work assigned to one member (counts + 3 examples per surface)","responses":{"200":{}}}},"/bff/member/tags":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberTags","tags":["Member"],"summary":"Replace the free-form tag list on a member","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","tags"],"properties":{"id":{"description":"External member id.","type":"string"},"tags":{"description":"Replacement tag list; pass [] to clear.","type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","tags"],"properties":{"id":{"description":"External member id.","type":"string"},"tags":{"description":"Replacement tag list; pass [] to clear.","type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["id","tags"],"properties":{"id":{"description":"External member id.","type":"string"},"tags":{"description":"Replacement tag list; pass [] to clear.","type":"array","items":{"type":"string"}}}}}}}}},"/bff/member/notes":{"get":{"parameters":[{"description":"External member id.","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffMemberNotes","tags":["Member"],"summary":"List internal notes pinned to a member","responses":{"200":{}}}},"/bff/member/notes/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"}},"required":["id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"number"}},"required":["id"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"number"}},"required":["id"]}}}}},"operationId":"postBffMemberNotesCreate","tags":["Member"],"summary":"Create a new internal note","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","bodyMd"],"properties":{"id":{"description":"External member id whose profile the note belongs to.","type":"string"},"bodyMd":{"description":"Markdown body. May contain @mentions which are parsed server-side.","type":"string"},"pinned":{"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","bodyMd"],"properties":{"id":{"description":"External member id whose profile the note belongs to.","type":"string"},"bodyMd":{"description":"Markdown body. May contain @mentions which are parsed server-side.","type":"string"},"pinned":{"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id","bodyMd"],"properties":{"id":{"description":"External member id whose profile the note belongs to.","type":"string"},"bodyMd":{"description":"Markdown body. May contain @mentions which are parsed server-side.","type":"string"},"pinned":{"type":"boolean"}}}}}}}},"/bff/member/notes/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberNotesUpdate","tags":["Member"],"summary":"Update / pin / unpin an internal note","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["noteId"],"properties":{"noteId":{"description":"Internal note id.","type":"number"},"bodyMd":{"type":"string"},"pinned":{"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["noteId"],"properties":{"noteId":{"description":"Internal note id.","type":"number"},"bodyMd":{"type":"string"},"pinned":{"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["noteId"],"properties":{"noteId":{"description":"Internal note id.","type":"number"},"bodyMd":{"type":"string"},"pinned":{"type":"boolean"}}}}}}}},"/bff/member/notes/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberNotesDelete","tags":["Member"],"summary":"Soft-delete an internal note","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["noteId"],"properties":{"noteId":{"description":"Internal note id.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["noteId"],"properties":{"noteId":{"description":"Internal note id.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["noteId"],"properties":{"noteId":{"description":"Internal note id.","type":"number"}}}}}}}},"/bff/member/permission-templates":{"get":{"operationId":"getBffMemberPermission-templates","tags":["Member"],"summary":"List permission templates for the organisation","responses":{"200":{}}}},"/bff/member/permission-templates/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"}},"required":["id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"number"}},"required":["id"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"number"}},"required":["id"]}}}}},"operationId":"postBffMemberPermission-templatesCreate","tags":["Member"],"summary":"Create a permission template","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"description":"Display name; unique within the organisation.","type":"string"},"description":{"type":"string"},"color":{"description":"Hex like \"#ec6c50\" for chip styling.","type":"string"},"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["name"],"properties":{"name":{"description":"Display name; unique within the organisation.","type":"string"},"description":{"type":"string"},"color":{"description":"Hex like \"#ec6c50\" for chip styling.","type":"string"},"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["name"],"properties":{"name":{"description":"Display name; unique within the organisation.","type":"string"},"description":{"type":"string"},"color":{"description":"Hex like \"#ec6c50\" for chip styling.","type":"string"},"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}}}}}}}},"/bff/member/permission-templates/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberPermission-templatesUpdate","tags":["Member"],"summary":"Update a permission template","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"color":{"anyOf":[{"type":"string"},{"type":"null"}]},"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"color":{"anyOf":[{"type":"string"},{"type":"null"}]},"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"color":{"anyOf":[{"type":"string"},{"type":"null"}]},"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}}}}}}}},"/bff/member/permission-templates/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffMemberPermission-templatesDelete","tags":["Member"],"summary":"Hard-delete a permission template","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"}}}}}}}},"/bff/member/clone-permissions-source":{"get":{"parameters":[{"description":"External id of the member to clone from.","schema":{"type":"string"},"in":"query","name":"sourceId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}},"required":["permissionCodes","roleCodes"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}},"required":["permissionCodes","roleCodes"]}},"text/plain":{"schema":{"type":"object","properties":{"permissionCodes":{"type":"array","items":{"type":"string"}},"roleCodes":{"type":"array","items":{"type":"string"}}},"required":["permissionCodes","roleCodes"]}}}}},"operationId":"getBffMemberClone-permissions-source","tags":["Member"],"summary":"Read a source member’s current permissions for a clone-to flow"}},"/bff/newsletter/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffNewsletterList","tags":["Newsletter"],"summary":"List newsletter subscribers","description":"Returns a paginated list of newsletter subscribers with their authorization and cancellation status.","responses":{"200":{}}}},"/bff/newsletter/job-list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffNewsletterJob-list","tags":["Newsletter"],"summary":"List newsletter jobs","description":"Returns a paginated list of newsletter sending jobs with their progress and speed limits.","responses":{"200":{}}}},"/bff/newsletter/job-contact-list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Newsletter job ID.","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffNewsletterJob-contact-list","tags":["bff"],"responses":{"200":{}}}},"/bff/newsletter/job-statistics":{"get":{"parameters":[{"description":"Newsletter job ID.","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffNewsletterJob-statistics","tags":["Newsletter"],"summary":"Get job sending statistics","description":"Returns delivery statistics (sent, pending, failed) for a specific newsletter job.","responses":{"200":{}}}},"/bff/newsletter/job-preview":{"get":{"parameters":[{"description":"Newsletter job ID.","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffNewsletterJob-preview","tags":["Newsletter"],"summary":"Preview newsletter job email","description":"Returns the subject and HTML body that recipients will receive for the given newsletter job. The body includes a representative unsubscribe footer but omits the per-recipient tracking pixel. The admin UI wraps the response in the organisation's emailer layout (logo + footer template).","responses":{"200":{}}}},"/bff/newsletter/job-update-content":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffNewsletterJob-update-content","tags":["Newsletter"],"summary":"Edit newsletter job content","description":"Updates the subject and body of the post backing a newsletter job. The runner reloads the post each cron tick, so the new content reaches every contact not yet delivered.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","subject","content"],"properties":{"id":{"description":"Newsletter job ID.","type":"string"},"subject":{"description":"New email subject. Stored normalised (single-line, max 300 chars).","type":"string"},"content":{"description":"New email body. Stored verbatim as HTML.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","subject","content"],"properties":{"id":{"description":"Newsletter job ID.","type":"string"},"subject":{"description":"New email subject. Stored normalised (single-line, max 300 chars).","type":"string"},"content":{"description":"New email body. Stored verbatim as HTML.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","subject","content"],"properties":{"id":{"description":"Newsletter job ID.","type":"string"},"subject":{"description":"New email subject. Stored normalised (single-line, max 300 chars).","type":"string"},"content":{"description":"New email body. Stored verbatim as HTML.","type":"string"}}}}}}}},"/bff/newsletter/job-run-action":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffNewsletterJob-run-action","tags":["Newsletter"],"summary":"Run action on newsletter job","description":"Executes a control action (start, pause, resume, cancel) on a newsletter sending job.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","action"],"properties":{"id":{"description":"Newsletter job ID.","type":"string"},"action":{"description":"Action to run: start, pause, resume, cancel.","examples":["start"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","action"],"properties":{"id":{"description":"Newsletter job ID.","type":"string"},"action":{"description":"Action to run: start, pause, resume, cancel.","examples":["start"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","action"],"properties":{"id":{"description":"Newsletter job ID.","type":"string"},"action":{"description":"Action to run: start, pause, resume, cancel.","examples":["start"],"type":"string"}}}}}}}},"/bff/newsletter/bulk-import":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffNewsletterBulk-import","tags":["Newsletter"],"summary":"Bulk import newsletter subscribers","description":"Imports a list of email addresses as newsletter subscribers. Invalid emails are silently skipped.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contactList"],"properties":{"contactList":{"description":"List of email addresses to import.","type":"array","items":{"examples":["jan@example.com"],"type":"string"}},"source":{"description":"Source label for tracking.","examples":["csv import"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["contactList"],"properties":{"contactList":{"description":"List of email addresses to import.","type":"array","items":{"examples":["jan@example.com"],"type":"string"}},"source":{"description":"Source label for tracking.","examples":["csv import"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["contactList"],"properties":{"contactList":{"description":"List of email addresses to import.","type":"array","items":{"examples":["jan@example.com"],"type":"string"}},"source":{"description":"Source label for tracking.","examples":["csv import"],"type":"string"}}}}}}}},"/bff/newsroom/shortlist":{"get":{"parameters":[{"description":"YYYY-MM-DD shortlist date filter.","schema":{"type":"string"},"in":"query","name":"date","required":false},{"description":"Status filter: pending, generating, generated, dismissed.","schema":{"type":"string"},"in":"query","name":"status","required":false},{"description":"Maximum number of items to return.","schema":{"type":"string"},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","shortlistDate","rank","title","hotnessScore","czRelevanceScore","cctvFitScore","totalScore","status","insertedDate"],"properties":{"id":{"type":"string"},"shortlistDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"rank":{"type":"number"},"title":{"type":"string"},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"},"hotnessScore":{"type":"number"},"czRelevanceScore":{"type":"number"},"cctvFitScore":{"type":"number"},"totalScore":{"type":"number"},"reason":{"type":"string"},"status":{"type":"string"},"draftId":{"type":"string"},"draftStatus":{"type":"string"},"topicType":{"type":"string"},"severity":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","shortlistDate","rank","title","hotnessScore","czRelevanceScore","cctvFitScore","totalScore","status","insertedDate"],"properties":{"id":{"type":"string"},"shortlistDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"rank":{"type":"number"},"title":{"type":"string"},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"},"hotnessScore":{"type":"number"},"czRelevanceScore":{"type":"number"},"cctvFitScore":{"type":"number"},"totalScore":{"type":"number"},"reason":{"type":"string"},"status":{"type":"string"},"draftId":{"type":"string"},"draftStatus":{"type":"string"},"topicType":{"type":"string"},"severity":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","shortlistDate","rank","title","hotnessScore","czRelevanceScore","cctvFitScore","totalScore","status","insertedDate"],"properties":{"id":{"type":"string"},"shortlistDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"rank":{"type":"number"},"title":{"type":"string"},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"},"hotnessScore":{"type":"number"},"czRelevanceScore":{"type":"number"},"cctvFitScore":{"type":"number"},"totalScore":{"type":"number"},"reason":{"type":"string"},"status":{"type":"string"},"draftId":{"type":"string"},"draftStatus":{"type":"string"},"topicType":{"type":"string"},"severity":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffNewsroomShortlist","tags":["Newsroom"],"summary":"List newsroom shortlist","description":"Returns the daily TOP-N candidate articles for the authenticated organisation, ranked by score. Each item exposes scores, source, status and (if generated) draft reference."}},"/bff/newsroom/run-pipeline":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","required":["organisationId","enrichment","shortlist"],"properties":{"organisationId":{"type":"number"},"rssSync":{"type":"object","required":["updatedFeeds","errors"],"properties":{"updatedFeeds":{"type":"number"},"errors":{"type":"number"}}},"enrichment":{"type":"object","required":["attempted","succeeded","failed"],"properties":{"attempted":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"}}},"shortlist":{"type":"object","required":["shortlistDate","itemCount"],"properties":{"shortlistDate":{"type":"string"},"itemCount":{"type":"number"}}}}}}},"required":["success","results"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","required":["organisationId","enrichment","shortlist"],"properties":{"organisationId":{"type":"number"},"rssSync":{"type":"object","required":["updatedFeeds","errors"],"properties":{"updatedFeeds":{"type":"number"},"errors":{"type":"number"}}},"enrichment":{"type":"object","required":["attempted","succeeded","failed"],"properties":{"attempted":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"}}},"shortlist":{"type":"object","required":["shortlistDate","itemCount"],"properties":{"shortlistDate":{"type":"string"},"itemCount":{"type":"number"}}}}}}},"required":["success","results"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","required":["organisationId","enrichment","shortlist"],"properties":{"organisationId":{"type":"number"},"rssSync":{"type":"object","required":["updatedFeeds","errors"],"properties":{"updatedFeeds":{"type":"number"},"errors":{"type":"number"}}},"enrichment":{"type":"object","required":["attempted","succeeded","failed"],"properties":{"attempted":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"}}},"shortlist":{"type":"object","required":["shortlistDate","itemCount"],"properties":{"shortlistDate":{"type":"string"},"itemCount":{"type":"number"}}}}}}},"required":["success","results"]}}}}},"operationId":"postBffNewsroomRun-pipeline","tags":["Newsroom"],"summary":"Run newsroom daily pipeline","description":"Synchronises RSS feeds, enriches new articles via AI, and rebuilds the shortlist for the authenticated organisation. Safe to run repeatedly.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"skipRssSync":{"description":"Skip the RSS feed sync step before enrichment.","type":"boolean"},"size":{"description":"Override default shortlist size (default 5).","type":"number"},"shortlistDate":{"description":"YYYY-MM-DD date for the shortlist (default today).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"skipRssSync":{"description":"Skip the RSS feed sync step before enrichment.","type":"boolean"},"size":{"description":"Override default shortlist size (default 5).","type":"number"},"shortlistDate":{"description":"YYYY-MM-DD date for the shortlist (default today).","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"skipRssSync":{"description":"Skip the RSS feed sync step before enrichment.","type":"boolean"},"size":{"description":"Override default shortlist size (default 5).","type":"number"},"shortlistDate":{"description":"YYYY-MM-DD date for the shortlist (default today).","type":"string"}}}}}}}},"/bff/newsroom/enrich":{"post":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"attempted":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"}},"required":["success","attempted","succeeded","failed"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"attempted":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"}},"required":["success","attempted","succeeded","failed"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"attempted":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"}},"required":["success","attempted","succeeded","failed"]}}}}},"operationId":"postBffNewsroomEnrich","tags":["Newsroom"],"summary":"Enrich pending RSS articles","description":"Runs AI enrichment on RSS articles that have not been analysed yet. Safe to call manually to backfill enrichment without rebuilding the shortlist."}},"/bff/newsroom/rebuild-shortlist":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"shortlistDate":{"type":"string"},"itemCount":{"type":"number"}},"required":["success","shortlistDate","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"shortlistDate":{"type":"string"},"itemCount":{"type":"number"}},"required":["success","shortlistDate","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"shortlistDate":{"type":"string"},"itemCount":{"type":"number"}},"required":["success","shortlistDate","itemCount"]}}}}},"operationId":"postBffNewsroomRebuild-shortlist","tags":["Newsroom"],"summary":"Rebuild newsroom shortlist","description":"Recomputes the daily TOP-N selection from existing enrichment data, without re-running AI.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"size":{"type":"number"},"shortlistDate":{"description":"YYYY-MM-DD date for the shortlist (default today).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"size":{"type":"number"},"shortlistDate":{"description":"YYYY-MM-DD date for the shortlist (default today).","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"size":{"type":"number"},"shortlistDate":{"description":"YYYY-MM-DD date for the shortlist (default today).","type":"string"}}}}}}}},"/bff/newsroom/shortlist/{shortlistId}/generate-draft":{"post":{"parameters":[{"description":"External ID of the shortlist item.","schema":{"type":"string"},"in":"path","name":"shortlistId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"draftId":{"description":"External ID of the generated draft.","type":"string"},"status":{"description":"ready | error","type":"string"}},"required":["success","draftId","status"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"draftId":{"description":"External ID of the generated draft.","type":"string"},"status":{"description":"ready | error","type":"string"}},"required":["success","draftId","status"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"draftId":{"description":"External ID of the generated draft.","type":"string"},"status":{"description":"ready | error","type":"string"}},"required":["success","draftId","status"]}}}}},"operationId":"postBffNewsroomShortlistByShortlistIdGenerate-draft","tags":["Newsroom"],"summary":"Generate article draft","description":"Runs the 3-pass AI writing pipeline (digest, article, fact-check) for a shortlist item. The resulting draft is saved as a private record and can be reviewed before being published as a Post."}},"/bff/newsroom/shortlist/{shortlistId}/dismiss":{"post":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"shortlistId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffNewsroomShortlistByShortlistIdDismiss","tags":["Newsroom"],"summary":"Dismiss shortlist item","description":"Marks a shortlist item as dismissed; it will not be re-included in subsequent rebuilds for the same date."}},"/bff/newsroom/draft/{draftId}":{"get":{"parameters":[{"description":"External ID of the draft.","schema":{"type":"string"},"in":"path","name":"draftId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"shortlistId":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"perex":{"type":"string"},"articleMarkdown":{"type":"string"},"thumbnail169":{"type":"object","properties":{"prompt":{"type":"string"},"description":{"type":"string"}}},"thumbnail916":{"type":"object","properties":{"prompt":{"type":"string"},"description":{"type":"string"}}},"linkedinText":{"type":"string"},"instagramText":{"type":"string"},"factCheckNotes":{"type":"object","required":["isClean","summary","findings"],"properties":{"isClean":{"type":"boolean"},"summary":{"type":"string"},"findings":{"type":"array","items":{"type":"object","required":["category","severity","excerpt","issue","justification","suggestedFix"],"properties":{"category":{"anyOf":[{"const":"error","type":"string"},{"const":"falsehood","type":"string"},{"const":"recommendation","type":"string"}]},"severity":{"anyOf":[{"const":"low","type":"string"},{"const":"medium","type":"string"},{"const":"high","type":"string"}]},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"issue":{"type":"string"},"justification":{"type":"string"},"suggestedFix":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"postId":{"type":"number"},"errorMessage":{"type":"string"},"modelWriter":{"type":"string"},"modelFactCheck":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"}},"required":["id","shortlistId","status","insertedDate","updatedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"string"},"shortlistId":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"perex":{"type":"string"},"articleMarkdown":{"type":"string"},"thumbnail169":{"type":"object","properties":{"prompt":{"type":"string"},"description":{"type":"string"}}},"thumbnail916":{"type":"object","properties":{"prompt":{"type":"string"},"description":{"type":"string"}}},"linkedinText":{"type":"string"},"instagramText":{"type":"string"},"factCheckNotes":{"type":"object","required":["isClean","summary","findings"],"properties":{"isClean":{"type":"boolean"},"summary":{"type":"string"},"findings":{"type":"array","items":{"type":"object","required":["category","severity","excerpt","issue","justification","suggestedFix"],"properties":{"category":{"anyOf":[{"const":"error","type":"string"},{"const":"falsehood","type":"string"},{"const":"recommendation","type":"string"}]},"severity":{"anyOf":[{"const":"low","type":"string"},{"const":"medium","type":"string"},{"const":"high","type":"string"}]},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"issue":{"type":"string"},"justification":{"type":"string"},"suggestedFix":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"postId":{"type":"number"},"errorMessage":{"type":"string"},"modelWriter":{"type":"string"},"modelFactCheck":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"}},"required":["id","shortlistId","status","insertedDate","updatedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"string"},"shortlistId":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"perex":{"type":"string"},"articleMarkdown":{"type":"string"},"thumbnail169":{"type":"object","properties":{"prompt":{"type":"string"},"description":{"type":"string"}}},"thumbnail916":{"type":"object","properties":{"prompt":{"type":"string"},"description":{"type":"string"}}},"linkedinText":{"type":"string"},"instagramText":{"type":"string"},"factCheckNotes":{"type":"object","required":["isClean","summary","findings"],"properties":{"isClean":{"type":"boolean"},"summary":{"type":"string"},"findings":{"type":"array","items":{"type":"object","required":["category","severity","excerpt","issue","justification","suggestedFix"],"properties":{"category":{"anyOf":[{"const":"error","type":"string"},{"const":"falsehood","type":"string"},{"const":"recommendation","type":"string"}]},"severity":{"anyOf":[{"const":"low","type":"string"},{"const":"medium","type":"string"},{"const":"high","type":"string"}]},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"issue":{"type":"string"},"justification":{"type":"string"},"suggestedFix":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"postId":{"type":"number"},"errorMessage":{"type":"string"},"modelWriter":{"type":"string"},"modelFactCheck":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"}},"required":["id","shortlistId","status","insertedDate","updatedDate"]}}}}},"operationId":"getBffNewsroomDraftByDraftId","tags":["Newsroom"],"summary":"Get draft detail","description":"Returns the generated article markdown plus thumbnail prompts and social media texts."}},"/bff/newsroom/draft/{draftId}/publish-as-post":{"post":{"parameters":[{"description":"External ID of the draft.","schema":{"type":"string"},"in":"path","name":"draftId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"postId":{"type":"number"},"postExternalId":{"type":"string"}},"required":["success","postId","postExternalId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"postId":{"type":"number"},"postExternalId":{"type":"string"}},"required":["success","postId","postExternalId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"postId":{"type":"number"},"postExternalId":{"type":"string"}},"required":["success","postId","postExternalId"]}}}}},"operationId":"postBffNewsroomDraftByDraftIdPublish-as-post","tags":["Newsroom"],"summary":"Publish draft as Post","description":"Materialises a ready draft into a content__post record using the standard addPost flow. By default the post is created as \"unlisted\" so the editor can review before going public.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"description":"public | private | unlisted | subscribe (default unlisted).","type":"string"},"mainCategory":{"description":"External ID of the post category (defaults to first active).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"visibility":{"description":"public | private | unlisted | subscribe (default unlisted).","type":"string"},"mainCategory":{"description":"External ID of the post category (defaults to first active).","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"visibility":{"description":"public | private | unlisted | subscribe (default unlisted).","type":"string"},"mainCategory":{"description":"External ID of the post category (defaults to first active).","type":"string"}}}}}}}},"/bff/notification/inbox":{"get":{"parameters":[{"description":"ISO timestamp. Defaults to 30 days ago.","schema":{"type":"string"},"in":"query","name":"since","required":false},{"description":"Minimum level (info, success, error, warning, critical). Default: error.","schema":{"type":"string"},"in":"query","name":"minLevel","required":false},{"description":"Comma-separated component allowlist.","schema":{"type":"string"},"in":"query","name":"components","required":false},{"description":"Pass \"true\" to return only unread items.","schema":{"type":"string"},"in":"query","name":"unreadOnly","required":false},{"description":"Page size, default 50, max 200.","schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Offset for pagination, default 0.","schema":{"type":"string"},"in":"query","name":"offset","required":false}],"operationId":"getBffNotificationInbox","tags":["Notification"],"summary":"Notification inbox","description":"Paginated, filterable feed of `core__system_log` entries with per-member read state. Default filter: severity >= error in the last 30 days. Powers the in-app bell + drawer.","responses":{"200":{}}}},"/bff/notification/unread-count":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"unreadCount":{"description":"Number of unread notifications for the current member.","type":"number"}},"required":["unreadCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"unreadCount":{"description":"Number of unread notifications for the current member.","type":"number"}},"required":["unreadCount"]}},"text/plain":{"schema":{"type":"object","properties":{"unreadCount":{"description":"Number of unread notifications for the current member.","type":"number"}},"required":["unreadCount"]}}}}},"operationId":"getBffNotificationUnread-count","tags":["Notification"],"summary":"Unread notification count","description":"Lightweight endpoint for the header bell badge. Returns only the unread count under the default filters (>= error in the last 30 days)."}},"/bff/notification/mark-read":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"marked":{"description":"Number of log IDs accepted (already-read ones are silently no-op).","type":"number"}},"required":["success","marked"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"marked":{"description":"Number of log IDs accepted (already-read ones are silently no-op).","type":"number"}},"required":["success","marked"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"marked":{"description":"Number of log IDs accepted (already-read ones are silently no-op).","type":"number"}},"required":["success","marked"]}}}}},"operationId":"postBffNotificationMark-read","tags":["Notification"],"summary":"Mark notifications as read","description":"Idempotent — inserts into `core__system_log_read_state` with ON CONFLICT DO NOTHING. Existing rows keep their original `read_at`; the timestamp is \"first time seen\", not \"last time seen\".","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["logIds"],"properties":{"logIds":{"description":"System log IDs to mark as read for the current member.","type":"array","items":{"type":"number"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["logIds"],"properties":{"logIds":{"description":"System log IDs to mark as read for the current member.","type":"array","items":{"type":"number"}}}}},"text/plain":{"schema":{"type":"object","required":["logIds"],"properties":{"logIds":{"description":"System log IDs to mark as read for the current member.","type":"array","items":{"type":"number"}}}}}}}}},"/bff/ip-info/detail":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"asn":{"type":"object","required":["id","title"],"properties":{"id":{"description":"Autonomous System Number.","examples":["AS12709"],"type":"string"},"title":{"description":"ASN organization name.","examples":["Melita Limited"],"type":"string"}}},"hostname":{"description":"Reverse DNS hostname.","examples":["c56-75.i05-15.onvol.net"],"type":"string"},"range":{"description":"IP CIDR range.","examples":["88.203.56.0/21"],"type":"string"},"company":{"description":"Company name of IP owner.","examples":["Melita plc"],"type":"string"},"hostedDomains":{"description":"Number of domains hosted on this IP.","type":"number"},"privacy":{"description":"Whether the IP is behind a privacy service (VPN/proxy).","type":"boolean"},"anycast":{"description":"Whether the IP is an anycast address.","type":"boolean"},"asnType":{"description":"ASN type: ISP, hosting, business or education.","examples":["ISP"],"type":"string"},"abuseContact":{"description":"Abuse contact email.","examples":["abuse@melitacable.com"],"type":"string"},"geoIp":{"type":"object","required":["city","state","country","postal","localTime","timezone","coordinates"],"properties":{"city":{"description":"City name.","examples":["Qormi"],"type":"string"},"state":{"description":"State or region.","examples":["Qormi"],"type":"string"},"country":{"description":"Country name.","examples":["Malta"],"type":"string"},"postal":{"description":"Postal code.","examples":["QRM"],"type":"string"},"localTime":{"description":"Local time at the IP location.","examples":["01:16 PM, Monday, November 25, 2024"],"type":"string"},"timezone":{"description":"IANA timezone identifier.","examples":["Europe/Malta"],"type":"string"},"coordinates":{"description":"GPS coordinates [latitude, longitude].","examples":[[35.876,14.472]],"type":"array","items":{"type":"number"}}}}},"required":["asn","hostname","range","company","hostedDomains","privacy","anycast","asnType","abuseContact","geoIp"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"asn":{"type":"object","required":["id","title"],"properties":{"id":{"description":"Autonomous System Number.","examples":["AS12709"],"type":"string"},"title":{"description":"ASN organization name.","examples":["Melita Limited"],"type":"string"}}},"hostname":{"description":"Reverse DNS hostname.","examples":["c56-75.i05-15.onvol.net"],"type":"string"},"range":{"description":"IP CIDR range.","examples":["88.203.56.0/21"],"type":"string"},"company":{"description":"Company name of IP owner.","examples":["Melita plc"],"type":"string"},"hostedDomains":{"description":"Number of domains hosted on this IP.","type":"number"},"privacy":{"description":"Whether the IP is behind a privacy service (VPN/proxy).","type":"boolean"},"anycast":{"description":"Whether the IP is an anycast address.","type":"boolean"},"asnType":{"description":"ASN type: ISP, hosting, business or education.","examples":["ISP"],"type":"string"},"abuseContact":{"description":"Abuse contact email.","examples":["abuse@melitacable.com"],"type":"string"},"geoIp":{"type":"object","required":["city","state","country","postal","localTime","timezone","coordinates"],"properties":{"city":{"description":"City name.","examples":["Qormi"],"type":"string"},"state":{"description":"State or region.","examples":["Qormi"],"type":"string"},"country":{"description":"Country name.","examples":["Malta"],"type":"string"},"postal":{"description":"Postal code.","examples":["QRM"],"type":"string"},"localTime":{"description":"Local time at the IP location.","examples":["01:16 PM, Monday, November 25, 2024"],"type":"string"},"timezone":{"description":"IANA timezone identifier.","examples":["Europe/Malta"],"type":"string"},"coordinates":{"description":"GPS coordinates [latitude, longitude].","examples":[[35.876,14.472]],"type":"array","items":{"type":"number"}}}}},"required":["asn","hostname","range","company","hostedDomains","privacy","anycast","asnType","abuseContact","geoIp"]}},"text/plain":{"schema":{"type":"object","properties":{"asn":{"type":"object","required":["id","title"],"properties":{"id":{"description":"Autonomous System Number.","examples":["AS12709"],"type":"string"},"title":{"description":"ASN organization name.","examples":["Melita Limited"],"type":"string"}}},"hostname":{"description":"Reverse DNS hostname.","examples":["c56-75.i05-15.onvol.net"],"type":"string"},"range":{"description":"IP CIDR range.","examples":["88.203.56.0/21"],"type":"string"},"company":{"description":"Company name of IP owner.","examples":["Melita plc"],"type":"string"},"hostedDomains":{"description":"Number of domains hosted on this IP.","type":"number"},"privacy":{"description":"Whether the IP is behind a privacy service (VPN/proxy).","type":"boolean"},"anycast":{"description":"Whether the IP is an anycast address.","type":"boolean"},"asnType":{"description":"ASN type: ISP, hosting, business or education.","examples":["ISP"],"type":"string"},"abuseContact":{"description":"Abuse contact email.","examples":["abuse@melitacable.com"],"type":"string"},"geoIp":{"type":"object","required":["city","state","country","postal","localTime","timezone","coordinates"],"properties":{"city":{"description":"City name.","examples":["Qormi"],"type":"string"},"state":{"description":"State or region.","examples":["Qormi"],"type":"string"},"country":{"description":"Country name.","examples":["Malta"],"type":"string"},"postal":{"description":"Postal code.","examples":["QRM"],"type":"string"},"localTime":{"description":"Local time at the IP location.","examples":["01:16 PM, Monday, November 25, 2024"],"type":"string"},"timezone":{"description":"IANA timezone identifier.","examples":["Europe/Malta"],"type":"string"},"coordinates":{"description":"GPS coordinates [latitude, longitude].","examples":[[35.876,14.472]],"type":"array","items":{"type":"number"}}}}},"required":["asn","hostname","range","company","hostedDomains","privacy","anycast","asnType","abuseContact","geoIp"]}}}}},"operationId":"getBffIp-infoDetail","tags":["IP Info"],"summary":"Get IP address information","description":"Returns detailed information about the requesting IP address including ASN, geolocation and privacy data."}},"/bff/issue/list":{"get":{"parameters":[{"description":"Filter by project key (e.g. \"PROJ\").","examples":["PROJ"],"schema":{"type":"string"},"in":"query","name":"projectCode","required":false},{"description":"Filter by status category (1=new, 2=progress, 3=waiting, 4=done).","examples":[1],"schema":{"type":"number"},"in":"query","name":"statusCategoryId","required":false},{"description":"Filter by assignee contact ID.","examples":[10],"schema":{"type":"number"},"in":"query","name":"assigneeId","required":false},{"description":"Filter by reporter contact ID.","examples":[5],"schema":{"type":"number"},"in":"query","name":"reporterId","required":false},{"description":"Filter by spam status.","schema":{"type":"boolean"},"in":"query","name":"isSpam","required":false},{"description":"Page number (1-based).","examples":[1],"schema":{"type":"number","default":1},"in":"query","name":"page","required":false},{"description":"Items per page.","examples":[50],"schema":{"type":"number","default":50},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","issueKey","subject","priority","priorityLabel","status","assignee","reporter","isSpam","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key (e.g. \"PROJ-123\"), used as public identifier.","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key.","type":"string"},"subject":{"description":"Issue subject/title.","type":"string"},"priority":{"description":"Priority number (1=low, 2=normal, 3=high, 4=critical, 5=blocker).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID (1=new, 2=progress, 3=waiting, 4=done).","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"assignee":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"isSpam":{"nullable":true,"anyOf":[{"description":"Spam classification. Null = not yet classified.","type":"boolean"},{"type":"null"}]},"insertedDate":{"description":"When the issue was created.","anyOf":[{"description":"When the issue was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"itemCount":{"description":"Total matching issues (for pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","issueKey","subject","priority","priorityLabel","status","assignee","reporter","isSpam","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key (e.g. \"PROJ-123\"), used as public identifier.","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key.","type":"string"},"subject":{"description":"Issue subject/title.","type":"string"},"priority":{"description":"Priority number (1=low, 2=normal, 3=high, 4=critical, 5=blocker).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID (1=new, 2=progress, 3=waiting, 4=done).","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"assignee":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"isSpam":{"nullable":true,"anyOf":[{"description":"Spam classification. Null = not yet classified.","type":"boolean"},{"type":"null"}]},"insertedDate":{"description":"When the issue was created.","anyOf":[{"description":"When the issue was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"itemCount":{"description":"Total matching issues (for pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","issueKey","subject","priority","priorityLabel","status","assignee","reporter","isSpam","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key (e.g. \"PROJ-123\"), used as public identifier.","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key.","type":"string"},"subject":{"description":"Issue subject/title.","type":"string"},"priority":{"description":"Priority number (1=low, 2=normal, 3=high, 4=critical, 5=blocker).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID (1=new, 2=progress, 3=waiting, 4=done).","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"assignee":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"isSpam":{"nullable":true,"anyOf":[{"description":"Spam classification. Null = not yet classified.","type":"boolean"},{"type":"null"}]},"insertedDate":{"description":"When the issue was created.","anyOf":[{"description":"When the issue was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"itemCount":{"description":"Total matching issues (for pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffIssueList","tags":["Issue"],"summary":"List issues","description":"Returns a paginated list of issues for the organisation. Supports filtering by project, status category, assignee, reporter, and spam status. Issues are ordered by creation date (newest first)."}},"/bff/issue/detail":{"get":{"parameters":[{"description":"Issue key (e.g. \"PROJ-123\").","examples":["PROJ-123"],"schema":{"type":"string"},"in":"query","name":"issueKey","required":true}],"responses":{"200":{"anyOf":[{"type":"object","required":["id","internalId","issueKey","subject","description","internalDescription","priority","priorityLabel","projectKey","projectName","status","assignee","reporter","isSpam","parentId","dueDate","testUrl","documentationUrl","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key.","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key (e.g. \"PROJ-123\").","type":"string"},"subject":{"description":"Issue subject/title.","type":"string"},"description":{"description":"Issue description (HTML).","type":"string"},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal notes visible only to team members.","type":"string"},{"type":"null"}]},"priority":{"description":"Priority (1-5).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"projectKey":{"description":"Project key (e.g. \"PROJ\").","type":"string"},"projectName":{"description":"Project display name.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID (1=new, 2=progress, 3=waiting, 4=done).","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"assignee":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"isSpam":{"nullable":true,"anyOf":[{"description":"Spam classification. Null = not yet classified.","type":"boolean"},{"type":"null"}]},"parentId":{"nullable":true,"anyOf":[{"description":"Internal ID of the parent issue (for sub-tasks).","type":"number"},{"type":"null"}]},"dueDate":{"nullable":true,"anyOf":[{"description":"Due date.","anyOf":[{"description":"Due date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"testUrl":{"nullable":true,"anyOf":[{"description":"URL to test environment.","type":"string"},{"type":"null"}]},"documentationUrl":{"nullable":true,"anyOf":[{"description":"URL to documentation.","type":"string"},{"type":"null"}]},"insertedDate":{"description":"When the issue was created.","anyOf":[{"description":"When the issue was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}},{"type":"object","required":["exist"],"properties":{"exist":{"const":false,"type":"boolean"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["id","internalId","issueKey","subject","description","internalDescription","priority","priorityLabel","projectKey","projectName","status","assignee","reporter","isSpam","parentId","dueDate","testUrl","documentationUrl","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key.","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key (e.g. \"PROJ-123\").","type":"string"},"subject":{"description":"Issue subject/title.","type":"string"},"description":{"description":"Issue description (HTML).","type":"string"},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal notes visible only to team members.","type":"string"},{"type":"null"}]},"priority":{"description":"Priority (1-5).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"projectKey":{"description":"Project key (e.g. \"PROJ\").","type":"string"},"projectName":{"description":"Project display name.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID (1=new, 2=progress, 3=waiting, 4=done).","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"assignee":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"isSpam":{"nullable":true,"anyOf":[{"description":"Spam classification. Null = not yet classified.","type":"boolean"},{"type":"null"}]},"parentId":{"nullable":true,"anyOf":[{"description":"Internal ID of the parent issue (for sub-tasks).","type":"number"},{"type":"null"}]},"dueDate":{"nullable":true,"anyOf":[{"description":"Due date.","anyOf":[{"description":"Due date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"testUrl":{"nullable":true,"anyOf":[{"description":"URL to test environment.","type":"string"},{"type":"null"}]},"documentationUrl":{"nullable":true,"anyOf":[{"description":"URL to documentation.","type":"string"},{"type":"null"}]},"insertedDate":{"description":"When the issue was created.","anyOf":[{"description":"When the issue was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}},{"type":"object","required":["exist"],"properties":{"exist":{"const":false,"type":"boolean"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["id","internalId","issueKey","subject","description","internalDescription","priority","priorityLabel","projectKey","projectName","status","assignee","reporter","isSpam","parentId","dueDate","testUrl","documentationUrl","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key.","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key (e.g. \"PROJ-123\").","type":"string"},"subject":{"description":"Issue subject/title.","type":"string"},"description":{"description":"Issue description (HTML).","type":"string"},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal notes visible only to team members.","type":"string"},{"type":"null"}]},"priority":{"description":"Priority (1-5).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"projectKey":{"description":"Project key (e.g. \"PROJ\").","type":"string"},"projectName":{"description":"Project display name.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID (1=new, 2=progress, 3=waiting, 4=done).","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"assignee":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"isSpam":{"nullable":true,"anyOf":[{"description":"Spam classification. Null = not yet classified.","type":"boolean"},{"type":"null"}]},"parentId":{"nullable":true,"anyOf":[{"description":"Internal ID of the parent issue (for sub-tasks).","type":"number"},{"type":"null"}]},"dueDate":{"nullable":true,"anyOf":[{"description":"Due date.","anyOf":[{"description":"Due date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"testUrl":{"nullable":true,"anyOf":[{"description":"URL to test environment.","type":"string"},{"type":"null"}]},"documentationUrl":{"nullable":true,"anyOf":[{"description":"URL to documentation.","type":"string"},{"type":"null"}]},"insertedDate":{"description":"When the issue was created.","anyOf":[{"description":"When the issue was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}},{"type":"object","required":["exist"],"properties":{"exist":{"const":false,"type":"boolean"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["id","internalId","issueKey","subject","description","internalDescription","priority","priorityLabel","projectKey","projectName","status","assignee","reporter","isSpam","parentId","dueDate","testUrl","documentationUrl","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key.","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key (e.g. \"PROJ-123\").","type":"string"},"subject":{"description":"Issue subject/title.","type":"string"},"description":{"description":"Issue description (HTML).","type":"string"},"internalDescription":{"nullable":true,"anyOf":[{"description":"Internal notes visible only to team members.","type":"string"},{"type":"null"}]},"priority":{"description":"Priority (1-5).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"projectKey":{"description":"Project key (e.g. \"PROJ\").","type":"string"},"projectName":{"description":"Project display name.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID (1=new, 2=progress, 3=waiting, 4=done).","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"assignee":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Contact ID.","type":"number"},"name":{"description":"Full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Contact e-mail. `null` for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to `name` or the contact ID.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"isSpam":{"nullable":true,"anyOf":[{"description":"Spam classification. Null = not yet classified.","type":"boolean"},{"type":"null"}]},"parentId":{"nullable":true,"anyOf":[{"description":"Internal ID of the parent issue (for sub-tasks).","type":"number"},{"type":"null"}]},"dueDate":{"nullable":true,"anyOf":[{"description":"Due date.","anyOf":[{"description":"Due date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"testUrl":{"nullable":true,"anyOf":[{"description":"URL to test environment.","type":"string"},{"type":"null"}]},"documentationUrl":{"nullable":true,"anyOf":[{"description":"URL to documentation.","type":"string"},{"type":"null"}]},"insertedDate":{"description":"When the issue was created.","anyOf":[{"description":"When the issue was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}},{"type":"object","required":["exist"],"properties":{"exist":{"const":false,"type":"boolean"}}}]}}}}},"operationId":"getBffIssueDetail","tags":["Issue"],"summary":"Get issue detail","description":"Returns full issue detail including description, project info, assignee, reporter, parent issue, due date, and linked URLs. Returns `{ exist: false }` if the issue is not found."}},"/bff/issue/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the issue was created successfully.","type":"boolean"},"issueKey":{"description":"Generated issue key.","examples":["PROJ-124"],"type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"}},"required":["success","issueKey","internalId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the issue was created successfully.","type":"boolean"},"issueKey":{"description":"Generated issue key.","examples":["PROJ-124"],"type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"}},"required":["success","issueKey","internalId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the issue was created successfully.","type":"boolean"},"issueKey":{"description":"Generated issue key.","examples":["PROJ-124"],"type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"}},"required":["success","issueKey","internalId"]}}}}},"operationId":"postBffIssueCreate","tags":["Issue"],"summary":"Create issue","description":"Creates a new issue in the default project. The AI workflow is triggered automatically to classify and process the issue.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Issue subject/title.","examples":["Login page returns 500 error"],"type":"string"},"description":{"description":"Issue description (supports HTML).","type":"string"},"internalDescription":{"description":"Internal notes visible only to team members.","type":"string"},"priority":{"minimum":1,"maximum":5,"default":2,"description":"Priority: 1=low, 2=normal, 3=high, 4=critical, 5=blocker.","type":"number"},"assigneeContactId":{"description":"Assignee contact ID.","examples":[10],"type":"number"},"reporterContactId":{"description":"Reporter contact ID.","examples":[5],"type":"number"},"parentIssueKey":{"description":"Parent issue key for sub-tasks (e.g. \"PROJ-100\").","examples":["PROJ-100"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Issue subject/title.","examples":["Login page returns 500 error"],"type":"string"},"description":{"description":"Issue description (supports HTML).","type":"string"},"internalDescription":{"description":"Internal notes visible only to team members.","type":"string"},"priority":{"minimum":1,"maximum":5,"default":2,"description":"Priority: 1=low, 2=normal, 3=high, 4=critical, 5=blocker.","type":"number"},"assigneeContactId":{"description":"Assignee contact ID.","examples":[10],"type":"number"},"reporterContactId":{"description":"Reporter contact ID.","examples":[5],"type":"number"},"parentIssueKey":{"description":"Parent issue key for sub-tasks (e.g. \"PROJ-100\").","examples":["PROJ-100"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Issue subject/title.","examples":["Login page returns 500 error"],"type":"string"},"description":{"description":"Issue description (supports HTML).","type":"string"},"internalDescription":{"description":"Internal notes visible only to team members.","type":"string"},"priority":{"minimum":1,"maximum":5,"default":2,"description":"Priority: 1=low, 2=normal, 3=high, 4=critical, 5=blocker.","type":"number"},"assigneeContactId":{"description":"Assignee contact ID.","examples":[10],"type":"number"},"reporterContactId":{"description":"Reporter contact ID.","examples":[5],"type":"number"},"parentIssueKey":{"description":"Parent issue key for sub-tasks (e.g. \"PROJ-100\").","examples":["PROJ-100"],"type":"string"}}}}}}}},"/bff/issue/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the issue was updated successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the issue was updated successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the issue was updated successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffIssueUpdate","tags":["Issue"],"summary":"Update issue","description":"Updates an existing issue. Only provided fields are changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["issueKey"],"properties":{"issueKey":{"description":"Issue key to update.","examples":["PROJ-123"],"type":"string"},"subject":{"description":"New subject.","examples":["Updated issue title"],"type":"string"},"description":{"description":"New description.","type":"string"},"internalDescription":{"description":"New internal description.","type":"string"},"priority":{"minimum":1,"maximum":5,"description":"New priority (1-5).","examples":[3],"type":"number"},"statusId":{"description":"New status ID.","examples":[2],"type":"number"},"assigneeContactId":{"description":"New assignee contact ID (0 to unassign).","examples":[10],"type":"number"},"dueDate":{"format":"date-time","description":"Due date (ISO timestamp).","examples":["2026-06-01T00:00:00Z"],"type":"string"},"testUrl":{"description":"Test URL.","examples":["https://test.example.com/feature"],"type":"string"},"documentationUrl":{"description":"Documentation URL.","examples":["https://docs.example.com/guide"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["issueKey"],"properties":{"issueKey":{"description":"Issue key to update.","examples":["PROJ-123"],"type":"string"},"subject":{"description":"New subject.","examples":["Updated issue title"],"type":"string"},"description":{"description":"New description.","type":"string"},"internalDescription":{"description":"New internal description.","type":"string"},"priority":{"minimum":1,"maximum":5,"description":"New priority (1-5).","examples":[3],"type":"number"},"statusId":{"description":"New status ID.","examples":[2],"type":"number"},"assigneeContactId":{"description":"New assignee contact ID (0 to unassign).","examples":[10],"type":"number"},"dueDate":{"format":"date-time","description":"Due date (ISO timestamp).","examples":["2026-06-01T00:00:00Z"],"type":"string"},"testUrl":{"description":"Test URL.","examples":["https://test.example.com/feature"],"type":"string"},"documentationUrl":{"description":"Documentation URL.","examples":["https://docs.example.com/guide"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["issueKey"],"properties":{"issueKey":{"description":"Issue key to update.","examples":["PROJ-123"],"type":"string"},"subject":{"description":"New subject.","examples":["Updated issue title"],"type":"string"},"description":{"description":"New description.","type":"string"},"internalDescription":{"description":"New internal description.","type":"string"},"priority":{"minimum":1,"maximum":5,"description":"New priority (1-5).","examples":[3],"type":"number"},"statusId":{"description":"New status ID.","examples":[2],"type":"number"},"assigneeContactId":{"description":"New assignee contact ID (0 to unassign).","examples":[10],"type":"number"},"dueDate":{"format":"date-time","description":"Due date (ISO timestamp).","examples":["2026-06-01T00:00:00Z"],"type":"string"},"testUrl":{"description":"Test URL.","examples":["https://test.example.com/feature"],"type":"string"},"documentationUrl":{"description":"Documentation URL.","examples":["https://docs.example.com/guide"],"type":"string"}}}}}}}},"/bff/issue/comments":{"get":{"parameters":[{"description":"Issue key.","examples":["PROJ-123"],"schema":{"type":"string"},"in":"query","name":"issueKey","required":true},{"description":"Page number.","examples":[1],"schema":{"type":"number","default":1},"in":"query","name":"page","required":false},{"description":"Items per page.","examples":[100],"schema":{"type":"number","default":100},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","authorId","authorName","authorEmail","message","insertedDate","updatedDate"],"properties":{"id":{"description":"Comment ID (format: \"PROJ-123_c456\").","type":"string"},"authorId":{"description":"Author contact ID.","type":"number"},"authorName":{"description":"Author full name.","type":"string"},"authorEmail":{"description":"Author email.","type":"string"},"message":{"description":"Comment text.","type":"string"},"insertedDate":{"description":"When the comment was created.","anyOf":[{"description":"When the comment was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total comment count.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","authorId","authorName","authorEmail","message","insertedDate","updatedDate"],"properties":{"id":{"description":"Comment ID (format: \"PROJ-123_c456\").","type":"string"},"authorId":{"description":"Author contact ID.","type":"number"},"authorName":{"description":"Author full name.","type":"string"},"authorEmail":{"description":"Author email.","type":"string"},"message":{"description":"Comment text.","type":"string"},"insertedDate":{"description":"When the comment was created.","anyOf":[{"description":"When the comment was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total comment count.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","authorId","authorName","authorEmail","message","insertedDate","updatedDate"],"properties":{"id":{"description":"Comment ID (format: \"PROJ-123_c456\").","type":"string"},"authorId":{"description":"Author contact ID.","type":"number"},"authorName":{"description":"Author full name.","type":"string"},"authorEmail":{"description":"Author email.","type":"string"},"message":{"description":"Comment text.","type":"string"},"insertedDate":{"description":"When the comment was created.","anyOf":[{"description":"When the comment was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total comment count.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffIssueComments","tags":["Issue"],"summary":"List issue comments","description":"Returns a paginated list of comments for a specific issue, ordered by creation date (oldest first)."}},"/bff/issue/add-comment":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the comment was added successfully.","type":"boolean"},"commentId":{"description":"Generated comment ID.","examples":["PROJ-123_c456"],"type":"string"}},"required":["success","commentId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the comment was added successfully.","type":"boolean"},"commentId":{"description":"Generated comment ID.","examples":["PROJ-123_c456"],"type":"string"}},"required":["success","commentId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the comment was added successfully.","type":"boolean"},"commentId":{"description":"Generated comment ID.","examples":["PROJ-123_c456"],"type":"string"}},"required":["success","commentId"]}}}}},"operationId":"postBffIssueAdd-comment","tags":["Issue"],"summary":"Add comment","description":"Adds a comment to an issue. The author is determined from the authenticated user. Email notifications are sent to relevant parties.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["issueKey","message"],"properties":{"issueKey":{"description":"Issue key to comment on.","examples":["PROJ-123"],"type":"string"},"message":{"minLength":1,"description":"Comment message text.","examples":["This has been fixed in the latest release."],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["issueKey","message"],"properties":{"issueKey":{"description":"Issue key to comment on.","examples":["PROJ-123"],"type":"string"},"message":{"minLength":1,"description":"Comment message text.","examples":["This has been fixed in the latest release."],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["issueKey","message"],"properties":{"issueKey":{"description":"Issue key to comment on.","examples":["PROJ-123"],"type":"string"},"message":{"minLength":1,"description":"Comment message text.","examples":["This has been fixed in the latest release."],"type":"string"}}}}}}}},"/bff/issue/run-ai-workflow":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the workflow was triggered successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the workflow was triggered successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the workflow was triggered successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffIssueRun-ai-workflow","tags":["Issue"],"summary":"Run AI workflow","description":"Manually triggers the AI workflow for an issue. This classifies the issue, checks for spam, and processes it through configured AI routes.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["issueKey"],"properties":{"issueKey":{"description":"Issue key to process.","examples":["PROJ-123"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["issueKey"],"properties":{"issueKey":{"description":"Issue key to process.","examples":["PROJ-123"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["issueKey"],"properties":{"issueKey":{"description":"Issue key to process.","examples":["PROJ-123"],"type":"string"}}}}}}}},"/bff/issue/set-spam":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the spam status was updated successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the spam status was updated successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the spam status was updated successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffIssueSet-spam","tags":["Issue"],"summary":"Set spam status","description":"Manually marks or unmarks an issue as spam.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["issueKey","isSpam"],"properties":{"issueKey":{"description":"Issue key.","examples":["PROJ-123"],"type":"string"},"isSpam":{"description":"Mark as spam (true) or not spam (false).","examples":[true],"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["issueKey","isSpam"],"properties":{"issueKey":{"description":"Issue key.","examples":["PROJ-123"],"type":"string"},"isSpam":{"description":"Mark as spam (true) or not spam (false).","examples":[true],"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["issueKey","isSpam"],"properties":{"issueKey":{"description":"Issue key.","examples":["PROJ-123"],"type":"string"},"isSpam":{"description":"Mark as spam (true) or not spam (false).","examples":[true],"type":"boolean"}}}}}}}},"/bff/issue/statuses":{"get":{"parameters":[{"description":"Filter by project key.","examples":["PROJ"],"schema":{"type":"string"},"in":"query","name":"projectCode","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","label","categoryId","categoryCode","projectKey"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID.","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"},"projectKey":{"description":"Project key this status belongs to.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","label","categoryId","categoryCode","projectKey"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID.","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"},"projectKey":{"description":"Project key this status belongs to.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","label","categoryId","categoryCode","projectKey"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status display label.","type":"string"},"categoryId":{"description":"Status category ID.","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"},"projectKey":{"description":"Project key this status belongs to.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffIssueStatuses","tags":["Issue"],"summary":"List statuses","description":"Returns all available issue statuses for the organisation, grouped by status category. Optionally filtered by project."}},"/bff/issue/support-create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the support ticket was created successfully.","type":"boolean"},"issueKey":{"description":"Generated ticket key.","examples":["BIZKIT-42"],"type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"}},"required":["success","issueKey","internalId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the support ticket was created successfully.","type":"boolean"},"issueKey":{"description":"Generated ticket key.","examples":["BIZKIT-42"],"type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"}},"required":["success","issueKey","internalId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the support ticket was created successfully.","type":"boolean"},"issueKey":{"description":"Generated ticket key.","examples":["BIZKIT-42"],"type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"}},"required":["success","issueKey","internalId"]}}}}},"operationId":"postBffIssueSupport-create","tags":["Issue"],"summary":"Create support ticket against BizKitHub","description":"Files an internal support ticket against BizKitHub on behalf of the authenticated organisation. The issue is created inside BizKitHub`s SUPPORT project but the originating organisation can also see and comment on it via /detail, /comments and /add-comment. A confirmation email is sent automatically (existing issue notification flow), and any subsequent comment from BizKitHub is delivered back to the reporter`s mailbox.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Support ticket subject/title.","examples":["Cannot connect TTLock device to gateway"],"type":"string"},"description":{"description":"Detailed description of the issue (supports HTML).","examples":["<p>The device shows blue blinking after pairing but never reaches the cloud.</p>"],"type":"string"},"priority":{"minimum":1,"maximum":5,"default":2,"description":"Priority: 1=low, 2=normal, 3=high, 4=critical, 5=blocker.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Support ticket subject/title.","examples":["Cannot connect TTLock device to gateway"],"type":"string"},"description":{"description":"Detailed description of the issue (supports HTML).","examples":["<p>The device shows blue blinking after pairing but never reaches the cloud.</p>"],"type":"string"},"priority":{"minimum":1,"maximum":5,"default":2,"description":"Priority: 1=low, 2=normal, 3=high, 4=critical, 5=blocker.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Support ticket subject/title.","examples":["Cannot connect TTLock device to gateway"],"type":"string"},"description":{"description":"Detailed description of the issue (supports HTML).","examples":["<p>The device shows blue blinking after pairing but never reaches the cloud.</p>"],"type":"string"},"priority":{"minimum":1,"maximum":5,"default":2,"description":"Priority: 1=low, 2=normal, 3=high, 4=critical, 5=blocker.","type":"number"}}}}}}}},"/bff/issue/support-list":{"get":{"parameters":[{"description":"Filter by status category (1=new, 2=progress, 3=waiting, 4=done).","examples":[1],"schema":{"type":"number"},"in":"query","name":"statusCategoryId","required":false},{"description":"Page number (1-based).","examples":[1],"schema":{"type":"number","default":1},"in":"query","name":"page","required":false},{"description":"Items per page.","examples":[50],"schema":{"type":"number","default":50},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","issueKey","subject","priority","priorityLabel","status","reporter","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key (e.g. \"BIZKIT-42\").","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key.","type":"string"},"subject":{"description":"Ticket subject.","type":"string"},"priority":{"description":"Priority (1-5).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status label.","type":"string"},"categoryId":{"description":"Status category ID.","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Reporter contact ID.","type":"number"},"name":{"description":"Reporter full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Reporter e-mail. `null` for phone-only contacts and anonymised contacts.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"insertedDate":{"description":"When the ticket was created.","anyOf":[{"description":"When the ticket was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"itemCount":{"description":"Total matching tickets.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","issueKey","subject","priority","priorityLabel","status","reporter","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key (e.g. \"BIZKIT-42\").","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key.","type":"string"},"subject":{"description":"Ticket subject.","type":"string"},"priority":{"description":"Priority (1-5).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status label.","type":"string"},"categoryId":{"description":"Status category ID.","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Reporter contact ID.","type":"number"},"name":{"description":"Reporter full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Reporter e-mail. `null` for phone-only contacts and anonymised contacts.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"insertedDate":{"description":"When the ticket was created.","anyOf":[{"description":"When the ticket was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"itemCount":{"description":"Total matching tickets.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","internalId","issueKey","subject","priority","priorityLabel","status","reporter","insertedDate","updatedDate"],"properties":{"id":{"description":"Issue key (e.g. \"BIZKIT-42\").","type":"string"},"internalId":{"description":"Internal numeric ID.","type":"number"},"issueKey":{"description":"Issue key.","type":"string"},"subject":{"description":"Ticket subject.","type":"string"},"priority":{"description":"Priority (1-5).","type":"number"},"priorityLabel":{"description":"Human-readable priority label.","type":"string"},"status":{"type":"object","required":["id","label","categoryId","categoryCode"],"properties":{"id":{"description":"Status ID.","type":"number"},"label":{"description":"Status label.","type":"string"},"categoryId":{"description":"Status category ID.","type":"number"},"categoryCode":{"description":"Status category code.","type":"string"}}},"reporter":{"nullable":true,"anyOf":[{"type":"object","required":["id","name","email"],"properties":{"id":{"description":"Reporter contact ID.","type":"number"},"name":{"description":"Reporter full name.","type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Reporter e-mail. `null` for phone-only contacts and anonymised contacts.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"insertedDate":{"description":"When the ticket was created.","anyOf":[{"description":"When the ticket was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"nullable":true,"anyOf":[{"description":"Last update timestamp.","anyOf":[{"description":"Last update timestamp.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]}}}},"itemCount":{"description":"Total matching tickets.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffIssueSupport-list","tags":["Issue"],"summary":"List support tickets filed by current organisation","description":"Returns support tickets that the authenticated organisation has filed against BizKitHub. These tickets live inside BizKitHub`s SUPPORT project but are visible to the originating organisation thanks to the originatingOrganisationId column on the issue. For BizKitHub itself this endpoint returns an empty list — internal staff should use /list instead."}},"/bff/issue/statistics":{"get":{"parameters":[{"description":"Filter by project key.","examples":["PROJ"],"schema":{"type":"string"},"in":"query","name":"projectCode","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"byCategory":{"description":"Issue count per status category code (e.g. { \"new\": 5, \"progress\": 3 }).","type":"object","patternProperties":{"^(.*)$":{"type":"number"}}},"spamCount":{"description":"Total spam issues.","type":"number"},"totalCount":{"description":"Total non-spam issues.","type":"number"}},"required":["byCategory","spamCount","totalCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"byCategory":{"description":"Issue count per status category code (e.g. { \"new\": 5, \"progress\": 3 }).","type":"object","patternProperties":{"^(.*)$":{"type":"number"}}},"spamCount":{"description":"Total spam issues.","type":"number"},"totalCount":{"description":"Total non-spam issues.","type":"number"}},"required":["byCategory","spamCount","totalCount"]}},"text/plain":{"schema":{"type":"object","properties":{"byCategory":{"description":"Issue count per status category code (e.g. { \"new\": 5, \"progress\": 3 }).","type":"object","patternProperties":{"^(.*)$":{"type":"number"}}},"spamCount":{"description":"Total spam issues.","type":"number"},"totalCount":{"description":"Total non-spam issues.","type":"number"}},"required":["byCategory","spamCount","totalCount"]}}}}},"operationId":"getBffIssueStatistics","tags":["Issue"],"summary":"Get statistics","description":"Returns issue counts grouped by status category, total non-spam count, and spam count. Useful for dashboard widgets and overview panels."}},"/bff/lead/list":{"get":{"parameters":[{"description":"Maximum items per page.","examples":[50],"schema":{"type":"number"},"in":"query","name":"limit","required":false},{"description":"Page number (1-based).","examples":[1],"schema":{"type":"number"},"in":"query","name":"page","required":false},{"description":"Lead pipeline status.","schema":{"anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"in":"query","name":"status","required":false},{"description":"How the lead was acquired.","schema":{"anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"in":"query","name":"source","required":false},{"description":"Filter by assigned member ID.","schema":{"type":"string"},"in":"query","name":"assignedMemberId","required":false},{"description":"Search across subject, description, customer name and email.","schema":{"type":"string"},"in":"query","name":"fulltextQuery","required":false},{"description":"Sort field:direction (e.g. \"insertedDate:desc\", \"estimatedValue:asc\", \"followUpDate:asc\").","schema":{"type":"string"},"in":"query","name":"orderBy","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","status","source","subject","estimatedValue","followUpDate","insertedDate","updatedDate","closedDate","customer","assignedMemberName"],"properties":{"id":{"description":"Lead ID.","type":"number"},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"subject":{"description":"Lead subject/title.","type":"string"},"estimatedValue":{"nullable":true,"anyOf":[{"description":"Estimated deal value.","type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"description":"Next follow-up date.","anyOf":[{"description":"Next follow-up date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"When the lead was created.","anyOf":[{"description":"When the lead was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"closedDate":{"nullable":true,"anyOf":[{"description":"When the lead was closed (won/lost).","anyOf":[{"description":"When the lead was closed (won/lost).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"customer":{"nullable":true,"anyOf":[{"type":"object","required":["externalId","email","name"],"properties":{"externalId":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts.","type":"string"},{"type":"null"}]},"name":{"type":"string"}}},{"type":"null"}]},"assignedMemberName":{"nullable":true,"anyOf":[{"description":"Name of assigned sales rep.","type":"string"},{"type":"null"}]}}}},"itemCount":{"description":"Total matching leads.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","status","source","subject","estimatedValue","followUpDate","insertedDate","updatedDate","closedDate","customer","assignedMemberName"],"properties":{"id":{"description":"Lead ID.","type":"number"},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"subject":{"description":"Lead subject/title.","type":"string"},"estimatedValue":{"nullable":true,"anyOf":[{"description":"Estimated deal value.","type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"description":"Next follow-up date.","anyOf":[{"description":"Next follow-up date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"When the lead was created.","anyOf":[{"description":"When the lead was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"closedDate":{"nullable":true,"anyOf":[{"description":"When the lead was closed (won/lost).","anyOf":[{"description":"When the lead was closed (won/lost).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"customer":{"nullable":true,"anyOf":[{"type":"object","required":["externalId","email","name"],"properties":{"externalId":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts.","type":"string"},{"type":"null"}]},"name":{"type":"string"}}},{"type":"null"}]},"assignedMemberName":{"nullable":true,"anyOf":[{"description":"Name of assigned sales rep.","type":"string"},{"type":"null"}]}}}},"itemCount":{"description":"Total matching leads.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","status","source","subject","estimatedValue","followUpDate","insertedDate","updatedDate","closedDate","customer","assignedMemberName"],"properties":{"id":{"description":"Lead ID.","type":"number"},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"subject":{"description":"Lead subject/title.","type":"string"},"estimatedValue":{"nullable":true,"anyOf":[{"description":"Estimated deal value.","type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"description":"Next follow-up date.","anyOf":[{"description":"Next follow-up date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"When the lead was created.","anyOf":[{"description":"When the lead was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last update.","anyOf":[{"description":"Last update.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"closedDate":{"nullable":true,"anyOf":[{"description":"When the lead was closed (won/lost).","anyOf":[{"description":"When the lead was closed (won/lost).","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"customer":{"nullable":true,"anyOf":[{"type":"object","required":["externalId","email","name"],"properties":{"externalId":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts.","type":"string"},{"type":"null"}]},"name":{"type":"string"}}},{"type":"null"}]},"assignedMemberName":{"nullable":true,"anyOf":[{"description":"Name of assigned sales rep.","type":"string"},{"type":"null"}]}}}},"itemCount":{"description":"Total matching leads.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffLeadList","tags":["Lead"],"summary":"List leads","description":"Returns a paginated list of leads/inquiries with customer and assignee info. Supports filtering by status, source, assigned member, and full-text search."}},"/bff/lead/detail":{"get":{"parameters":[{"description":"Lead ID.","schema":{"type":"string"},"in":"query","name":"leadId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"subject":{"type":"string"},"description":{"type":"string"},"internalNote":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"estimatedValue":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"closedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"lostReason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"customer":{"nullable":true,"anyOf":[{"type":"object","required":["externalId","email","name","phone","companyName"],"properties":{"externalId":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts.","type":"string"},{"type":"null"}]},"name":{"type":"string"},"phone":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"companyName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"assignedMember":{"nullable":true,"anyOf":[{"type":"object","required":["id","name"],"properties":{"id":{"type":"number"},"name":{"type":"string"}}},{"type":"null"}]},"order":{"nullable":true,"anyOf":[{"type":"object","required":["id","orderNumber"],"properties":{"id":{"type":"number"},"orderNumber":{"type":"string"}}},{"type":"null"}]},"issue":{"nullable":true,"anyOf":[{"type":"object","required":["id","issueKey"],"properties":{"id":{"type":"number"},"issueKey":{"type":"string"}}},{"type":"null"}]},"geo":{"nullable":true,"anyOf":[{"type":"object","required":["ip","city","country"],"properties":{"ip":{"type":"string"},"city":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]}},"required":["id","status","source","subject","description","internalNote","estimatedValue","followUpDate","closedDate","lostReason","insertedDate","updatedDate","customer","assignedMember","order","issue","geo"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"number"},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"subject":{"type":"string"},"description":{"type":"string"},"internalNote":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"estimatedValue":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"closedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"lostReason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"customer":{"nullable":true,"anyOf":[{"type":"object","required":["externalId","email","name","phone","companyName"],"properties":{"externalId":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts.","type":"string"},{"type":"null"}]},"name":{"type":"string"},"phone":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"companyName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"assignedMember":{"nullable":true,"anyOf":[{"type":"object","required":["id","name"],"properties":{"id":{"type":"number"},"name":{"type":"string"}}},{"type":"null"}]},"order":{"nullable":true,"anyOf":[{"type":"object","required":["id","orderNumber"],"properties":{"id":{"type":"number"},"orderNumber":{"type":"string"}}},{"type":"null"}]},"issue":{"nullable":true,"anyOf":[{"type":"object","required":["id","issueKey"],"properties":{"id":{"type":"number"},"issueKey":{"type":"string"}}},{"type":"null"}]},"geo":{"nullable":true,"anyOf":[{"type":"object","required":["ip","city","country"],"properties":{"ip":{"type":"string"},"city":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]}},"required":["id","status","source","subject","description","internalNote","estimatedValue","followUpDate","closedDate","lostReason","insertedDate","updatedDate","customer","assignedMember","order","issue","geo"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"number"},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"subject":{"type":"string"},"description":{"type":"string"},"internalNote":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"estimatedValue":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"closedDate":{"nullable":true,"anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"lostReason":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"customer":{"nullable":true,"anyOf":[{"type":"object","required":["externalId","email","name","phone","companyName"],"properties":{"externalId":{"type":"string"},"email":{"nullable":true,"anyOf":[{"description":"Customer e-mail. `null` for phone-only customers and anonymised contacts.","type":"string"},{"type":"null"}]},"name":{"type":"string"},"phone":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"companyName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"assignedMember":{"nullable":true,"anyOf":[{"type":"object","required":["id","name"],"properties":{"id":{"type":"number"},"name":{"type":"string"}}},{"type":"null"}]},"order":{"nullable":true,"anyOf":[{"type":"object","required":["id","orderNumber"],"properties":{"id":{"type":"number"},"orderNumber":{"type":"string"}}},{"type":"null"}]},"issue":{"nullable":true,"anyOf":[{"type":"object","required":["id","issueKey"],"properties":{"id":{"type":"number"},"issueKey":{"type":"string"}}},{"type":"null"}]},"geo":{"nullable":true,"anyOf":[{"type":"object","required":["ip","city","country"],"properties":{"ip":{"type":"string"},"city":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]}},"required":["id","status","source","subject","description","internalNote","estimatedValue","followUpDate","closedDate","lostReason","insertedDate","updatedDate","customer","assignedMember","order","issue","geo"]}}}}},"operationId":"getBffLeadDetail","tags":["Lead"],"summary":"Get lead detail","description":"Returns full lead detail including customer, assignee, linked order/issue, and geo info."}},"/bff/lead/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"description":"Created lead ID.","type":"number"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"description":"Created lead ID.","type":"number"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"description":"Created lead ID.","type":"number"}},"required":["success","id"]}}}}},"operationId":"postBffLeadCreate","tags":["Lead"],"summary":"Create lead","description":"Creates a new lead/inquiry. Optionally creates or links an existing customer by email. The lead starts in \"new\" status.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Lead subject/title.","type":"string"},"description":{"description":"Detailed description of the inquiry.","type":"string"},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"customerEmail":{"description":"Customer email — creates or finds existing contact.","type":"string"},"customerPhone":{"description":"Customer phone.","type":"string"},"customerFirstName":{"description":"Customer first name.","type":"string"},"customerLastName":{"description":"Customer last name.","type":"string"},"assignedMemberId":{"description":"Organisation member ID to assign.","type":"number"},"estimatedValue":{"description":"Estimated deal value.","type":"number"},"followUpDate":{"description":"Next follow-up date (ISO timestamp).","examples":["2026-03-01"],"type":"string"},"internalNote":{"description":"Internal note for the sales team.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Lead subject/title.","type":"string"},"description":{"description":"Detailed description of the inquiry.","type":"string"},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"customerEmail":{"description":"Customer email — creates or finds existing contact.","type":"string"},"customerPhone":{"description":"Customer phone.","type":"string"},"customerFirstName":{"description":"Customer first name.","type":"string"},"customerLastName":{"description":"Customer last name.","type":"string"},"assignedMemberId":{"description":"Organisation member ID to assign.","type":"number"},"estimatedValue":{"description":"Estimated deal value.","type":"number"},"followUpDate":{"description":"Next follow-up date (ISO timestamp).","examples":["2026-03-01"],"type":"string"},"internalNote":{"description":"Internal note for the sales team.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["subject"],"properties":{"subject":{"minLength":1,"description":"Lead subject/title.","type":"string"},"description":{"description":"Detailed description of the inquiry.","type":"string"},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"customerEmail":{"description":"Customer email — creates or finds existing contact.","type":"string"},"customerPhone":{"description":"Customer phone.","type":"string"},"customerFirstName":{"description":"Customer first name.","type":"string"},"customerLastName":{"description":"Customer last name.","type":"string"},"assignedMemberId":{"description":"Organisation member ID to assign.","type":"number"},"estimatedValue":{"description":"Estimated deal value.","type":"number"},"followUpDate":{"description":"Next follow-up date (ISO timestamp).","examples":["2026-03-01"],"type":"string"},"internalNote":{"description":"Internal note for the sales team.","type":"string"}}}}}}}},"/bff/lead/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffLeadUpdate","tags":["Lead"],"summary":"Update lead","description":"Updates lead fields. Only provided fields are changed. When status is set to \"won\" or \"lost\", closedDate is auto-set to now if not provided.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["leadId"],"properties":{"leadId":{"description":"Lead ID to update.","type":"number"},"subject":{"minLength":1,"type":"string"},"description":{"type":"string"},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"assignedMemberId":{"nullable":true,"anyOf":[{"description":"Set assigned member, or null to unassign.","type":"number"},{"type":"null"}]},"customerId":{"nullable":true,"anyOf":[{"description":"Set customer ID, or null to unlink.","type":"number"},{"type":"null"}]},"estimatedValue":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"description":"ISO timestamp or null to clear.","type":"string"},{"type":"null"}]},"closedDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"lostReason":{"nullable":true,"anyOf":[{"description":"Reason for losing the lead (when status=lost).","type":"string"},{"type":"null"}]},"internalNote":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["leadId"],"properties":{"leadId":{"description":"Lead ID to update.","type":"number"},"subject":{"minLength":1,"type":"string"},"description":{"type":"string"},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"assignedMemberId":{"nullable":true,"anyOf":[{"description":"Set assigned member, or null to unassign.","type":"number"},{"type":"null"}]},"customerId":{"nullable":true,"anyOf":[{"description":"Set customer ID, or null to unlink.","type":"number"},{"type":"null"}]},"estimatedValue":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"description":"ISO timestamp or null to clear.","type":"string"},{"type":"null"}]},"closedDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"lostReason":{"nullable":true,"anyOf":[{"description":"Reason for losing the lead (when status=lost).","type":"string"},{"type":"null"}]},"internalNote":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["leadId"],"properties":{"leadId":{"description":"Lead ID to update.","type":"number"},"subject":{"minLength":1,"type":"string"},"description":{"type":"string"},"source":{"description":"How the lead was acquired.","anyOf":[{"const":"web_form","type":"string"},{"const":"phone","type":"string"},{"const":"email","type":"string"},{"const":"referral","type":"string"},{"const":"other","type":"string"}]},"status":{"description":"Lead pipeline status.","anyOf":[{"const":"new","type":"string"},{"const":"contacted","type":"string"},{"const":"qualified","type":"string"},{"const":"proposal","type":"string"},{"const":"negotiation","type":"string"},{"const":"won","type":"string"},{"const":"lost","type":"string"}]},"assignedMemberId":{"nullable":true,"anyOf":[{"description":"Set assigned member, or null to unassign.","type":"number"},{"type":"null"}]},"customerId":{"nullable":true,"anyOf":[{"description":"Set customer ID, or null to unlink.","type":"number"},{"type":"null"}]},"estimatedValue":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"followUpDate":{"nullable":true,"anyOf":[{"description":"ISO timestamp or null to clear.","type":"string"},{"type":"null"}]},"closedDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"lostReason":{"nullable":true,"anyOf":[{"description":"Reason for losing the lead (when status=lost).","type":"string"},{"type":"null"}]},"internalNote":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/locale/list":{"get":{"parameters":[{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","locale","label"],"properties":{"id":{"description":"Internal locale ID.","type":"number"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"label":{"description":"Localized display name of the locale.","examples":["Angličtina"],"type":"string"}}}},"itemCount":{"description":"Total number of locales.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","locale","label"],"properties":{"id":{"description":"Internal locale ID.","type":"number"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"label":{"description":"Localized display name of the locale.","examples":["Angličtina"],"type":"string"}}}},"itemCount":{"description":"Total number of locales.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","locale","label"],"properties":{"id":{"description":"Internal locale ID.","type":"number"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"label":{"description":"Localized display name of the locale.","examples":["Angličtina"],"type":"string"}}}},"itemCount":{"description":"Total number of locales.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffLocaleList","tags":["Locale"],"summary":"List available locales","description":"Returns all available locales with their localized labels. Use the locale query param to control the language of labels."}},"/bff/log/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"External (16-char) id of a contact. When provided, only logs associated with that contact via `core__system_log_contact` are returned.","examples":["Dlko1bEG85c6304a"],"schema":{"type":"string"},"in":"query","name":"contactId","required":false}],"operationId":"getBffLogList","tags":["Log"],"summary":"List system logs","description":"Returns a paginated list of system log entries for the current organisation. Optionally filtered to a single contact via the `contactId` (external id) query parameter.","responses":{"200":{}}}},"/bff/log/detail":{"get":{"parameters":[{"description":"Log entry external ID.","examples":["log_abc123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffLogDetail","tags":["Log"],"summary":"Get log entry detail","description":"Returns a single log entry with full message, metadata and context.","responses":{"200":{}}}},"/bff/log/detail-log-explain":{"get":{"parameters":[{"description":"Log entry external ID to explain.","examples":["log_abc123"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"operationId":"getBffLogDetail-log-explain","tags":["Log"],"summary":"AI-explain a log entry","description":"Uses AI to generate a human-readable explanation of a log entry in the specified locale.","responses":{"200":{}}}},"/bff/log/detail-code":{"get":{"parameters":[{"description":"System log code identifier.","examples":["ORDER_CREATED"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"operationId":"getBffLogDetail-code","tags":["Log"],"summary":"Get log code definition","description":"Returns the title and description for a system log code. Empty object if the code is unknown.","responses":{"200":{}}}},"/bff/log/write-frontend-log":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffLogWrite-frontend-log","tags":["Log"],"summary":"Write a frontend log entry","description":"Writes a log entry from the frontend application. Supports debouncing to prevent log spam.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"description":"Log message text.","type":"string"},"level":{"description":"Log severity level.","examples":["info","error","warning"],"type":"string"},"useDebounce":{"anyOf":[{"type":"boolean"},{"type":"object","required":["maxInterval"],"properties":{"enabled":{"type":"boolean"},"maxInterval":{"type":"string"}}}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["message"],"properties":{"message":{"description":"Log message text.","type":"string"},"level":{"description":"Log severity level.","examples":["info","error","warning"],"type":"string"},"useDebounce":{"anyOf":[{"type":"boolean"},{"type":"object","required":["maxInterval"],"properties":{"enabled":{"type":"boolean"},"maxInterval":{"type":"string"}}}]}}}},"text/plain":{"schema":{"type":"object","required":["message"],"properties":{"message":{"description":"Log message text.","type":"string"},"level":{"description":"Log severity level.","examples":["info","error","warning"],"type":"string"},"useDebounce":{"anyOf":[{"type":"boolean"},{"type":"object","required":["maxInterval"],"properties":{"enabled":{"type":"boolean"},"maxInterval":{"type":"string"}}}]}}}}}}}},"/bff/order/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Filter by customer external ID.","examples":["8zLmc498hr0gJb2I"],"schema":{"type":"string"},"in":"query","name":"customerId","required":false},{"description":"Filter by order group code.","examples":["eshop","rezervace"],"schema":{"type":"string"},"in":"query","name":"groupCode","required":false},{"description":"Filter by order status code.","examples":["new","processing","done","storno"],"schema":{"type":"string"},"in":"query","name":"statusCode","required":false},{"description":"Full-text search across order number, customer email, first/last name, company name, and phone. Multi-word query: whitespace-separated tokens are AND-ed; each token matches any column (ILIKE, accent-insensitive).","examples":["26000432","jan@example.com","Jan Novák"],"schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false},{"description":"Filter orders whose chosen date column is on or after this date (inclusive). See `dateField` for which column is targeted (default: inserted_date).","examples":["2026-01-01"],"schema":{"type":"string"},"in":"query","name":"dateFrom","required":false},{"description":"Filter orders whose chosen date column is on or before this date (inclusive). See `dateField` for which column is targeted (default: inserted_date).","examples":["2026-01-31"],"schema":{"type":"string"},"in":"query","name":"dateTo","required":false},{"description":"Which date column `dateFrom`/`dateTo` apply to: \"inserted\" (default, created_at), \"paid\" (paid_at), \"updated\" (last update), \"due\" (due_date).","examples":["inserted","paid","updated","due"],"schema":{"type":"string"},"in":"query","name":"dateField","required":false},{"description":"Filter by payment status. \"true\" = paid only, \"false\" = unpaid only.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"isPaid","required":false},{"description":"\"true\" = orders past their due_date and still unpaid (cashflow follow-up); \"false\" = orders that are either still in time or already paid.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"overdue","required":false},{"description":"Lower bound for the order total price (inclusive). Compared in raw order currency.","examples":["100","1000"],"schema":{"type":"string"},"in":"query","name":"priceMin","required":false},{"description":"Upper bound for the order total price (inclusive). Compared in raw order currency.","examples":["5000","10000"],"schema":{"type":"string"},"in":"query","name":"priceMax","required":false},{"description":"Broad status type code – aggregates all org-specific statuses sharing the same type. \"new\" / \"processing\" / \"done\" / \"storno\".","examples":["processing","storno"],"schema":{"type":"string"},"in":"query","name":"statusType","required":false},{"description":"\"true\" = order has at least one invoice; \"false\" = no invoice has been issued yet.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"hasInvoice","required":false},{"description":"Aggregated outcome of online payment attempts: \"paid\" (succeeded), \"failed\" (cancelled/timeouted, never paid), \"pending\" (in flight), \"none\" (no online payment attempt at all).","examples":["paid","failed","pending","none"],"schema":{"type":"string"},"in":"query","name":"onlinePaymentResult","required":false},{"description":"\"true\" = exclude orders whose customer is flagged as a test account.","examples":["true"],"schema":{"type":"string"},"in":"query","name":"hideTestAccounts","required":false},{"description":"\"true\" = orders with a non-empty public notice (customer wrote a message). \"false\" = orders without a public notice. Internal notices are not considered.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"hasPublicNote","required":false}],"operationId":"getBffOrderList","tags":["Order"],"summary":"List orders","description":"Returns a paginated list of orders with customer info and attached files. Supports filtering by status, customer, group, date range, payment status, full-text search, overdue (past due-date and unpaid), price range, status type, invoice presence, online-payment outcome, test-account hiding and public-note presence. Pagination is controlled via X-Pagination headers.","responses":{"200":{}}}},"/bff/order/create":{"post":{"parameters":[],"responses":{"200":{"description":"Order created successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"hash":{"description":"Order hash for subsequent operations.","type":"string"},"orderNumber":{"description":"Human-readable order number.","type":"string"}},"required":["success","hash","orderNumber"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"hash":{"description":"Order hash for subsequent operations.","type":"string"},"orderNumber":{"description":"Human-readable order number.","type":"string"}},"required":["success","hash","orderNumber"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"hash":{"description":"Order hash for subsequent operations.","type":"string"},"orderNumber":{"description":"Human-readable order number.","type":"string"}},"required":["success","hash","orderNumber"]}}}}},"operationId":"postBffOrderCreate","tags":["Order"],"summary":"Create a new order","description":"Creates a new order from admin panel (POS mode). By default creates a draft/cart that can be edited before confirmation. Set startAsCart=false to create a confirmed order immediately.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"orderGroupId":{"description":"Order group code (e.g., \"default\", \"eshop\").","type":"string"},"customer":{"description":"Customer information for the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Customer first name.","type":"string"},"lastName":{"description":"Customer last name.","type":"string"},"phone":{"description":"Customer phone number.","type":"string"},"companyName":{"description":"Company name for B2B orders.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","type":"string"},"taxIdentificationNumber":{"description":"Tax ID (DIČ).","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"description":"Country code (e.g., \"CZ\", \"SK\").","type":"string"}}},"items":{"description":"List of order items.","type":"array","items":{"description":"Order item.","type":"object","required":["label"],"properties":{"label":{"description":"Item label/name displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g., 21).","type":"number"},"count":{"description":"Quantity. Defaults to 1.","type":"number"},"sale":{"description":"Discount amount per item.","type":"number"},"unit":{"description":"Unit of measure (e.g., \"ks\", \"hod\").","type":"string"},"productCode":{"description":"Product code to link item to product.","type":"string"},"variantCode":{"description":"Product variant code.","type":"string"},"eventCode":{"description":"Calendar event code for event tickets.","type":"string"},"creditAmount":{"description":"Credit amount if item adds credit.","type":"number"}}}},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"currency":{"description":"Currency code (e.g., \"CZK\", \"EUR\"). Defaults to organisation currency.","type":"string"},"sale":{"description":"Global discount amount for the entire order.","type":"number"},"paymentMethod":{"description":"Payment method: \"credits\" for credit balance, \"money\" for standard payment.","anyOf":[{"const":"credits","type":"string"},{"const":"money","type":"string"}]},"deliveryPrice":{"description":"Delivery/shipping price.","type":"number"},"paymentPrice":{"description":"Payment processing fee.","type":"number"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"},"publicNotice":{"description":"Public note visible to customer.","type":"string"},"tags":{"description":"Tags to attach to the order.","type":"object","patternProperties":{"^(.*)$":{}}},"ignoreNotification":{"description":"Skip sending order confirmation email. Defaults to true.","type":"boolean"},"startAsCart":{"description":"Create order as draft/cart (true) or as new order (false). Defaults to false.","type":"boolean"},"preventAutoPayment":{"description":"Prevent automatic marking as paid when order price is 0. Defaults to true.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"orderGroupId":{"description":"Order group code (e.g., \"default\", \"eshop\").","type":"string"},"customer":{"description":"Customer information for the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Customer first name.","type":"string"},"lastName":{"description":"Customer last name.","type":"string"},"phone":{"description":"Customer phone number.","type":"string"},"companyName":{"description":"Company name for B2B orders.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","type":"string"},"taxIdentificationNumber":{"description":"Tax ID (DIČ).","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"description":"Country code (e.g., \"CZ\", \"SK\").","type":"string"}}},"items":{"description":"List of order items.","type":"array","items":{"description":"Order item.","type":"object","required":["label"],"properties":{"label":{"description":"Item label/name displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g., 21).","type":"number"},"count":{"description":"Quantity. Defaults to 1.","type":"number"},"sale":{"description":"Discount amount per item.","type":"number"},"unit":{"description":"Unit of measure (e.g., \"ks\", \"hod\").","type":"string"},"productCode":{"description":"Product code to link item to product.","type":"string"},"variantCode":{"description":"Product variant code.","type":"string"},"eventCode":{"description":"Calendar event code for event tickets.","type":"string"},"creditAmount":{"description":"Credit amount if item adds credit.","type":"number"}}}},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"currency":{"description":"Currency code (e.g., \"CZK\", \"EUR\"). Defaults to organisation currency.","type":"string"},"sale":{"description":"Global discount amount for the entire order.","type":"number"},"paymentMethod":{"description":"Payment method: \"credits\" for credit balance, \"money\" for standard payment.","anyOf":[{"const":"credits","type":"string"},{"const":"money","type":"string"}]},"deliveryPrice":{"description":"Delivery/shipping price.","type":"number"},"paymentPrice":{"description":"Payment processing fee.","type":"number"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"},"publicNotice":{"description":"Public note visible to customer.","type":"string"},"tags":{"description":"Tags to attach to the order.","type":"object","patternProperties":{"^(.*)$":{}}},"ignoreNotification":{"description":"Skip sending order confirmation email. Defaults to true.","type":"boolean"},"startAsCart":{"description":"Create order as draft/cart (true) or as new order (false). Defaults to false.","type":"boolean"},"preventAutoPayment":{"description":"Prevent automatic marking as paid when order price is 0. Defaults to true.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","properties":{"orderGroupId":{"description":"Order group code (e.g., \"default\", \"eshop\").","type":"string"},"customer":{"description":"Customer information for the order.","type":"object","required":["email"],"properties":{"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"firstName":{"description":"Customer first name.","type":"string"},"lastName":{"description":"Customer last name.","type":"string"},"phone":{"description":"Customer phone number.","type":"string"},"companyName":{"description":"Company name for B2B orders.","type":"string"},"companyRegistrationNumber":{"description":"Company registration number (IČO).","type":"string"},"taxIdentificationNumber":{"description":"Tax ID (DIČ).","type":"string"},"streetAddress":{"description":"Street address.","type":"string"},"city":{"description":"City.","type":"string"},"postalCode":{"description":"Postal/ZIP code.","type":"string"},"country":{"description":"Country code (e.g., \"CZ\", \"SK\").","type":"string"}}},"items":{"description":"List of order items.","type":"array","items":{"description":"Order item.","type":"object","required":["label"],"properties":{"label":{"description":"Item label/name displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g., 21).","type":"number"},"count":{"description":"Quantity. Defaults to 1.","type":"number"},"sale":{"description":"Discount amount per item.","type":"number"},"unit":{"description":"Unit of measure (e.g., \"ks\", \"hod\").","type":"string"},"productCode":{"description":"Product code to link item to product.","type":"string"},"variantCode":{"description":"Product variant code.","type":"string"},"eventCode":{"description":"Calendar event code for event tickets.","type":"string"},"creditAmount":{"description":"Credit amount if item adds credit.","type":"number"}}}},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"currency":{"description":"Currency code (e.g., \"CZK\", \"EUR\"). Defaults to organisation currency.","type":"string"},"sale":{"description":"Global discount amount for the entire order.","type":"number"},"paymentMethod":{"description":"Payment method: \"credits\" for credit balance, \"money\" for standard payment.","anyOf":[{"const":"credits","type":"string"},{"const":"money","type":"string"}]},"deliveryPrice":{"description":"Delivery/shipping price.","type":"number"},"paymentPrice":{"description":"Payment processing fee.","type":"number"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"},"publicNotice":{"description":"Public note visible to customer.","type":"string"},"tags":{"description":"Tags to attach to the order.","type":"object","patternProperties":{"^(.*)$":{}}},"ignoreNotification":{"description":"Skip sending order confirmation email. Defaults to true.","type":"boolean"},"startAsCart":{"description":"Create order as draft/cart (true) or as new order (false). Defaults to false.","type":"boolean"},"preventAutoPayment":{"description":"Prevent automatic marking as paid when order price is 0. Defaults to true.","type":"boolean"}}}}}}}},"/bff/order/detail":{"get":{"parameters":[{"description":"Unique order hash identifier.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"operationId":"getBffOrderDetail","tags":["Order"],"summary":"Get order detail","description":"Returns full order detail including items, customer info, pricing, tags, events, IP geolocation, and payment status.","responses":{"200":{}}}},"/bff/order/detail-recurrence":{"get":{"parameters":[{"description":"Unique order hash identifier.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"operationId":"getBffOrderDetail-recurrence","tags":["Order"],"summary":"Get order recurrence payments","description":"Returns a list of recurrence payment records associated with the order.","responses":{"200":{}}}},"/bff/order/detail-file":{"get":{"parameters":[{"description":"Unique order hash identifier.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"operationId":"getBffOrderDetail-file","tags":["Order"],"summary":"Get order files","description":"Returns invoices and attached files for the given order.","responses":{"200":{}}}},"/bff/order/detail-log":{"get":{"parameters":[{"description":"Unique order hash identifier.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"hash","required":true},{"description":"Page number (1-based).","examples":[1],"schema":{"type":"number"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (default 500).","examples":[500],"schema":{"type":"number"},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","message","level","insertedDate"],"properties":{"id":{"description":"Log entry index within the current page.","type":"number"},"message":{"description":"Human-readable log message.","type":"string"},"level":{"description":"Log severity level (e.g. info, success, warning, error).","type":"string"},"insertedDate":{"description":"Timestamp when the log entry was created.","examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"description":"Timestamp when the log entry was created.","examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of log entries for this order.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","message","level","insertedDate"],"properties":{"id":{"description":"Log entry index within the current page.","type":"number"},"message":{"description":"Human-readable log message.","type":"string"},"level":{"description":"Log severity level (e.g. info, success, warning, error).","type":"string"},"insertedDate":{"description":"Timestamp when the log entry was created.","examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"description":"Timestamp when the log entry was created.","examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of log entries for this order.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","message","level","insertedDate"],"properties":{"id":{"description":"Log entry index within the current page.","type":"number"},"message":{"description":"Human-readable log message.","type":"string"},"level":{"description":"Log severity level (e.g. info, success, warning, error).","type":"string"},"insertedDate":{"description":"Timestamp when the log entry was created.","examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"description":"Timestamp when the log entry was created.","examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of log entries for this order.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffOrderDetail-log","tags":["Order"],"summary":"Get order log entries","description":"Returns a paginated list of log entries for the given order, sorted by newest first."}},"/bff/order/detail-log-explain":{"get":{"parameters":[{"description":"Unique order hash identifier.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"hash","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"operationId":"getBffOrderDetail-log-explain","tags":["Order"],"summary":"AI-explain order log","description":"Uses AI to generate a human-readable summary of the order log in the requested locale.","responses":{"200":{}}}},"/bff/order/mark-as-paid":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderMark-as-paid","tags":["Order"],"summary":"Mark order as paid","description":"Manually marks the order as paid. Inserts a `manual_mark` receipt row for the unpaid remainder so the leakage audit (`SUM(price) WHERE kind=manual_mark`) stays accurate. Prefer `/bff/order-payment/record` from new UI — that supports combined payments and the explicit cash / bank_transfer / credit kinds.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"description":"Unique order hash identifier.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"description":"Unique order hash identifier.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"description":"Unique order hash identifier.","type":"string"}}}}}}}},"/bff/order/mark-as-non-paid":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderMark-as-non-paid","tags":["Order"],"summary":"Mark order as non-paid","description":"Reverts the order payment status to unpaid and logs the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"description":"Unique order hash identifier.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"description":"Unique order hash identifier.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["hash"],"properties":{"hash":{"description":"Unique order hash identifier.","type":"string"}}}}}}}},"/bff/order/set-item-storno":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderSet-item-storno","tags":["Order"],"summary":"Toggle item storno","description":"Toggles the storno flag on an order item and recalculates the order price.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","itemId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"itemId":{"description":"External item ID to toggle storno on.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","itemId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"itemId":{"description":"External item ID to toggle storno on.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","itemId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"itemId":{"description":"External item ID to toggle storno on.","type":"string"}}}}}}}},"/bff/order/remove-item":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderRemove-item","tags":["Order"],"summary":"Remove order item","description":"Permanently deletes an item from the order and recalculates the order price.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","itemId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"itemId":{"description":"External item ID to remove.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","itemId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"itemId":{"description":"External item ID to remove.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","itemId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"itemId":{"description":"External item ID to remove.","type":"string"}}}}}}}},"/bff/order/create-payment":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"redirectUrl":{"type":"string"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"redirectUrl":{"type":"string"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"redirectUrl":{"type":"string"}},"required":["success"]}}}}},"operationId":"postBffOrderCreate-payment","tags":["Order"],"summary":"Create payment for order","description":"Initiates an online payment session for the order and returns a redirect URL.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","provider"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"provider":{"description":"Payment provider code (e.g. \"stripe\", \"gopay\").","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","provider"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"provider":{"description":"Payment provider code (e.g. \"stripe\", \"gopay\").","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","provider"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"provider":{"description":"Payment provider code (e.g. \"stripe\", \"gopay\").","type":"string"}}}}}}}},"/bff/order/resend-notification":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderResend-notification","tags":["Order"],"summary":"Resend order notification","description":"Re-sends the status notification email for the order using the specified or current status template.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"statusCode":{"description":"Status code whose notification template to send. Defaults to current status.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"statusCode":{"description":"Status code whose notification template to send. Defaults to current status.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"statusCode":{"description":"Status code whose notification template to send. Defaults to current status.","type":"string"}}}}}}}},"/bff/order/update-notice":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderUpdate-notice","tags":["Order"],"summary":"Update order notices","description":"Updates the internal and public notice texts on the order.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","internalNotice","publicNotice"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"},"publicNotice":{"description":"Public note visible to the customer.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","internalNotice","publicNotice"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"},"publicNotice":{"description":"Public note visible to the customer.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","internalNotice","publicNotice"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"internalNotice":{"description":"Internal note visible only to staff.","type":"string"},"publicNotice":{"description":"Public note visible to the customer.","type":"string"}}}}}}}},"/bff/order/add-product":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderAdd-product","tags":["Order"],"summary":"Add product to order","description":"Adds an existing product as a new line item to the order and recalculates the total price.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","productCode","label","price","vat","count"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"productCode":{"description":"Product code to link the item to.","type":"string"},"productVariantCode":{"description":"Product variant code.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"},"count":{"description":"Quantity to add.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","productCode","label","price","vat","count"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"productCode":{"description":"Product code to link the item to.","type":"string"},"productVariantCode":{"description":"Product variant code.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"},"count":{"description":"Quantity to add.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","productCode","label","price","vat","count"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"productCode":{"description":"Product code to link the item to.","type":"string"},"productVariantCode":{"description":"Product variant code.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"},"count":{"description":"Quantity to add.","type":"number"}}}}}}}},"/bff/order/add-virtual-product":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderAdd-virtual-product","tags":["Order"],"summary":"Add virtual product to order","description":"Adds a custom (virtual) line item not linked to any product and recalculates the total price.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","label","price","vat","count"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"},"count":{"description":"Quantity to add.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","label","price","vat","count"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"},"count":{"description":"Quantity to add.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","label","price","vat","count"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"},"count":{"description":"Quantity to add.","type":"number"}}}}}}}},"/bff/order/add-credit":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderAdd-credit","tags":["Order"],"summary":"Add credit item to order","description":"Adds a credit-granting line item to the order and recalculates the total price.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","label","price","credit","vat"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"credit":{"description":"Credit amount to grant to the customer.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","label","price","credit","vat"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"credit":{"description":"Credit amount to grant to the customer.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","label","price","credit","vat"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"label":{"description":"Item label displayed on invoice.","type":"string"},"price":{"description":"Unit price including VAT.","type":"number"},"credit":{"description":"Credit amount to grant to the customer.","type":"number"},"vat":{"description":"VAT rate in percent (e.g. 21).","type":"number"}}}}}}}},"/bff/order/add-event":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderAdd-event","tags":["Order"],"summary":"Add event to order","description":"Adds a calendar event as a line item to the order and recalculates the total price.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","eventCode"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"eventCode":{"description":"Calendar event code to attach as an order item.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","eventCode"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"eventCode":{"description":"Calendar event code to attach as an order item.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","eventCode"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"eventCode":{"description":"Calendar event code to attach as an order item.","type":"string"}}}}}}}},"/bff/order/detail-recurrence-delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrderDetail-recurrence-delete","tags":["Order"],"summary":"Delete recurrence payment","description":"Removes a single recurrence payment record from the order.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","paymentId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"paymentId":{"description":"External recurrence payment ID to delete.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","paymentId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"paymentId":{"description":"External recurrence payment ID to delete.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","paymentId"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"paymentId":{"description":"External recurrence payment ID to delete.","type":"string"}}}}}}}},"/bff/order/create-invoice":{"get":{"parameters":[{"description":"Unique order hash identifier.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"hash","required":true},{"description":"Invoice type (e.g. \"proforma\", \"invoice\", \"credit-note\").","examples":["invoice"],"schema":{"type":"string"},"in":"query","name":"type","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffOrderCreate-invoice","tags":["Order"],"summary":"Create invoice for order","description":"Generates an invoice document of the specified type for the order."}},"/bff/order/set-status":{"post":{"parameters":[],"operationId":"postBffOrderSet-status","tags":["Order"],"summary":"Set order status","description":"Manually changes the order status and sends the corresponding notification.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderHash","statusCode"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"statusCode":{"description":"Target status code to set on the order.","examples":["processing","done","storno"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderHash","statusCode"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"statusCode":{"description":"Target status code to set on the order.","examples":["processing","done","storno"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["orderHash","statusCode"],"properties":{"orderHash":{"description":"Unique order hash identifier.","type":"string"},"statusCode":{"description":"Target status code to set on the order.","examples":["processing","done","storno"],"type":"string"}}}}}},"responses":{"200":{}}}},"/bff/order/statistics":{"get":{"parameters":[{"description":"Filter statistics by order group code.","examples":["eshop"],"schema":{"type":"string"},"in":"query","name":"groupCode","required":false}],"operationId":"getBffOrderStatistics","tags":["Order"],"summary":"Get order statistics","description":"Returns aggregated order statistics, optionally filtered by order group.","responses":{"200":{}}}},"/bff/order/link-blob":{"get":{"parameters":[{"description":"Unique order hash identifier.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"hash","required":true},{"description":"Token of the blob (file) to attach.","schema":{"type":"string"},"in":"query","name":"blobToken","required":true},{"description":"Optional label for the attached file.","schema":{"type":"string"},"in":"query","name":"label","required":false}],"operationId":"getBffOrderLink-blob","tags":["Order"],"summary":"Link blob to order","description":"Attaches an uploaded file (blob) to the order. Skips if already linked.","responses":{"200":{}}}},"/bff/order/grid-configuration":{"get":{"parameters":[{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"operationId":"getBffOrderGrid-configuration","tags":["Order"],"summary":"Get order grid configuration","description":"Returns column definitions, filter options, and status list for the order data grid.","responses":{"200":{}}}},"/bff/order/create-recurrence-payment":{"post":{"operationId":"postBffOrderCreate-recurrence-payment","tags":["Order"],"summary":"Create recurrence payment schedule","description":"Creates a recurring payment schedule for the order based on the provided cycle, period, and strategy.","responses":{"200":{}}}},"/bff/order/detail-recurrence-edit":{"post":{"operationId":"postBffOrderDetail-recurrence-edit","tags":["Order"],"summary":"Edit recurrence payment amount","description":"Updates the amount of a single recurrence payment record.","responses":{"200":{}}}},"/bff/order-payment/list":{"get":{"parameters":[{"description":"Unique order hash.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"hash","required":true}],"operationId":"getBffOrder-paymentList","tags":["Order Payment"],"summary":"List order payment receipts","description":"Unified payment-receipt timeline for an order: gateway attempts, bank wires, customer-credit applications and admin-recorded cash / manual_mark / refund rows — all sources joined into one chronological list. `summary` exposes the totals used by the order paid-state engine.","responses":{"200":{}}}},"/bff/order-payment/record":{"post":{"parameters":[],"operationId":"postBffOrder-paymentRecord","tags":["Order Payment"],"summary":"Record order payment(s)","description":"Records one or more payment-receipt rows against the order. Supports combined payments (e.g. 1500 cash + 500 manual_mark in one call). If the cumulative receipt log now covers the order price, the order is flipped to paid via the standard workflow hooks. The acting admin's contact id is captured as `recorded_by_contact_id` on every inserted row.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hash","entries"],"properties":{"hash":{"description":"Unique order hash.","examples":["a1b2c3d4"],"type":"string"},"entries":{"minItems":1,"description":"One or more receipt rows. Multiple = combined payment in one call.","type":"array","items":{"type":"object","required":["kindCode","price"],"properties":{"kindCode":{"description":"Payment kind code (FK to shop__order_payment_kind.code).","anyOf":[{"const":"gateway","type":"string"},{"const":"bank_transfer","type":"string"},{"const":"cash","type":"string"},{"const":"manual_mark","type":"string"},{"const":"credit","type":"string"},{"const":"voucher_redeem","type":"string"},{"const":"refund","type":"string"}]},"price":{"description":"Positive amount in the order currency.","minimum":0.0001,"type":"number"},"status":{"description":"Override status; otherwise per-kind default.","type":"string"},"direction":{"anyOf":[{"const":"in","type":"string"},{"const":"out","type":"string"}]},"note":{"type":"string"},"branchId":{"description":"Branch (cash register) where the receipt was taken.","type":"number"},"currencyId":{"type":"number"}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["hash","entries"],"properties":{"hash":{"description":"Unique order hash.","examples":["a1b2c3d4"],"type":"string"},"entries":{"minItems":1,"description":"One or more receipt rows. Multiple = combined payment in one call.","type":"array","items":{"type":"object","required":["kindCode","price"],"properties":{"kindCode":{"description":"Payment kind code (FK to shop__order_payment_kind.code).","anyOf":[{"const":"gateway","type":"string"},{"const":"bank_transfer","type":"string"},{"const":"cash","type":"string"},{"const":"manual_mark","type":"string"},{"const":"credit","type":"string"},{"const":"voucher_redeem","type":"string"},{"const":"refund","type":"string"}]},"price":{"description":"Positive amount in the order currency.","minimum":0.0001,"type":"number"},"status":{"description":"Override status; otherwise per-kind default.","type":"string"},"direction":{"anyOf":[{"const":"in","type":"string"},{"const":"out","type":"string"}]},"note":{"type":"string"},"branchId":{"description":"Branch (cash register) where the receipt was taken.","type":"number"},"currencyId":{"type":"number"}}}}}}},"text/plain":{"schema":{"type":"object","required":["hash","entries"],"properties":{"hash":{"description":"Unique order hash.","examples":["a1b2c3d4"],"type":"string"},"entries":{"minItems":1,"description":"One or more receipt rows. Multiple = combined payment in one call.","type":"array","items":{"type":"object","required":["kindCode","price"],"properties":{"kindCode":{"description":"Payment kind code (FK to shop__order_payment_kind.code).","anyOf":[{"const":"gateway","type":"string"},{"const":"bank_transfer","type":"string"},{"const":"cash","type":"string"},{"const":"manual_mark","type":"string"},{"const":"credit","type":"string"},{"const":"voucher_redeem","type":"string"},{"const":"refund","type":"string"}]},"price":{"description":"Positive amount in the order currency.","minimum":0.0001,"type":"number"},"status":{"description":"Override status; otherwise per-kind default.","type":"string"},"direction":{"anyOf":[{"const":"in","type":"string"},{"const":"out","type":"string"}]},"note":{"type":"string"},"branchId":{"description":"Branch (cash register) where the receipt was taken.","type":"number"},"currencyId":{"type":"number"}}}}}}}}},"responses":{"200":{}}}},"/bff/organisation/profile":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"Organisation display name. Used as the sender name in all outgoing emails (transactional, marketing, newsletters), shown on invoices as the supplier name, displayed in admin panels and organisation switcher. Must be unique across all organisations.","type":"string"},"slug":{"description":"URL-safe unique identifier. Used in public URLs (e.g. /[slug]/...), newsletter unsubscribe links, Firmy.cz feed paths, and terminal commands for org switching. Read-only — set at creation from the org name.","type":"string"},"storageSlug":{"description":"CDN storage path prefix. All uploaded files (images, documents) are stored under this slug at the storage CDN (e.g. https://storage.xhp.cz/{storageSlug}/...). Read-only — set at creation, same as slug.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Organisation about text / profile description. Shown in admin organisation lists. Optional free-form text for internal reference.","type":"string"},{"type":"null"}]},"emoji":{"nullable":true,"anyOf":[{"description":"Visual emoji icon for the organisation. Displayed next to the org name in account details, org switcher, and terminal output. If not set manually, the system auto-generates one using AI based on the org configuration.","type":"string"},{"type":"null"}]},"companyRegistrationNumber":{"nullable":true,"anyOf":[{"description":"Czech company registration number (IČO). Printed on invoices and receipts as \"IČO: {value}\". Used for ARES address lookup, Firmy.cz feed integration, and invoice export data for accounting.","type":"string"},{"type":"null"}]},"taxIdentificationNumber":{"nullable":true,"anyOf":[{"description":"Tax identification number (DIČ). Printed on invoices and receipts as \"DIČ: {value}\". Used for address lookup validation and included in invoice exports for accounting software.","type":"string"},{"type":"null"}]},"vatPayer":{"description":"Whether the organisation is a VAT payer. When true, invoices include VAT rates (21%, 12%, 0%) on line items. When false, all invoice items use 0% VAT. Also triggers unreliable VAT payer fraud checks against the Czech Ministry of Finance list.","type":"boolean"},"accountingCountry":{"nullable":true,"anyOf":[{"type":"object","required":["id","code","name"],"properties":{"id":{"description":"Internal country ID. Use this value as accountingCountryId in update-profile.","type":"number"},"code":{"description":"ISO 3166-1 alpha-2 country code. Defines accounting / tax jurisdiction (used for VAT rules, ARES vs RPO lookup, legal form picker scoping).","examples":["CZ"],"type":"string"},"name":{"description":"Localized country name (English).","type":"string"}}},{"type":"null"}]},"legalForm":{"nullable":true,"anyOf":[{"type":"object","required":["id","code","slug","name"],"properties":{"id":{"description":"Internal legal form ID. Use this value as legalFormId in update-profile.","type":"number"},"code":{"description":"Country-specific legal form code (e.g. ARES \"pravniForma\" 112 = s.r.o. in CZ).","examples":["112"],"type":"string"},"slug":{"description":"Cross-country slug (osvc, sro, as, vos, ks, druzstvo, po, fo_podnikatel, neziskovka...).","examples":["sro"],"type":"string"},"name":{"description":"Localized human-readable legal form name.","examples":["Společnost s ručením omezeným (s.r.o.)"],"type":"string"}}},{"type":"null"}]},"disableExperiments":{"description":"Disables experimental AI-powered features for this organisation. When true, the system skips AI issue routing and AI-generated responses in the issue/ticket workflow. Organisations start with this disabled (false) by default.","type":"boolean"},"timezone":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"description":"Internal timezone ID. Use this value when setting timezoneId in update-profile.","type":"number"},"timezone":{"description":"IANA timezone identifier. Used to format dates in email notifications and calendar events.","examples":["Europe/Prague"],"type":"string"},"gmt":{"description":"GMT offset string for display purposes.","examples":["+01:00"],"type":"string"},"label":{"description":"Human-readable timezone label for picker display.","examples":["Central European Time - Prague"],"type":"string"}}},"primaryLocale":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Internal locale ID. Use this value when setting primaryLocaleId in update-profile.","type":"number"},"locale":{"description":"ISO 639-1 locale code. Determines default language for contacts, emails, and content selection.","examples":["cs"],"type":"string"}}},"defaultCurrency":{"description":"Default currency ISO 4217 code (e.g. \"CZK\"). Used for pricing of products and orders. Changing this value is a sensitive operation — update requests that attempt to change it are rejected and logged as a warning; contact BizKitHub technical support to change the organisation default currency.","examples":["CZK"],"type":"string"},"supportPerson":{"nullable":true,"anyOf":[{"type":"object","required":["id","fullName"],"properties":{"id":{"description":"Internal member ID of the support person (from GET /organisation/members).","type":"number"},"fullName":{"description":"Full name of the designated support contact for this organisation.","type":"string"}}},{"type":"null"}]},"vendor":{"nullable":true,"anyOf":[{"description":"Vendor (parent) organisation that resells / technically manages this org. Returned only when (a) parent_id is set AND (b) the parent holds an active white-label licence. NULL otherwise — i.e. either we sell directly to the customer or the parent's licence has been revoked.","type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug — used by /vendor/switch.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor (mirror of cas__white_label_licence.licence_key).","type":"string"},"contactPerson":{"nullable":true,"anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"description":"cas__organisation_member.id of the vendor's nominated contact.","type":"number"},"firstName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"nullable":true,"anyOf":[{"description":"Email address customers should write to. Resolved as: vendor's `default_send_from_email` (transactional sender) → contact person's login username → null.","type":"string"},{"type":"null"}]},"myTariff":{"description":"The CUSTOMER's own tariff & billing summary — what the vendor manages on their behalf. Bundled here so the settings page can render \"Spravuje mě\" + \"Můj tarif\" in one go.","type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"description":"Tariff id from cas__tariff.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"description":"Tariff display name.","type":"string"},"monthlyPriceCzk":{"description":"Final monthly price the customer actually pays, in WHOLE CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"},"customPriceCzk":{"nullable":true,"anyOf":[{"description":"Negotiated price (CZK) when set, NULL = catalogue minus discount.","type":"number"},{"type":"null"}]},"discountPercent":{"description":"Discount applied on top of catalogue price (0-100).","type":"number"},"expiresAt":{"nullable":true,"anyOf":[{"description":"ISO datetime when the current paid period ends. NULL = no paid-until set.","type":"string"},{"type":"null"}]},"daysUntilExpiry":{"nullable":true,"anyOf":[{"description":"Whole days until expiry. Negative = already expired.","type":"number"},{"type":"null"}]},"isExpired":{"description":"TRUE when expiresAt < now.","type":"boolean"}}}}},{"type":"null"}]},"tariff":{"type":"object","required":["id","code","storageMb","limitMembers","limitProducts","limitOrdersMonthly","limitCustomers","limitEmailsMonthly","limitAiTokensMonthly","limitForms"],"properties":{"id":{"description":"Tariff ID (read-only — managed via /tariff endpoints by admins).","type":"number"},"code":{"description":"Tariff plan identifier. Determines resource limits and pricing for the organisation.","examples":["business"],"type":"string"},"storageMb":{"description":"File storage limit in MB. Compare with storageUsed (in bytes) to calculate usage. 0 = unlimited.","type":"number"},"limitMembers":{"description":"Max active (non-blocked) organisation members. 0 = unlimited.","type":"number"},"limitProducts":{"description":"Max non-deleted products in the shop. 0 = unlimited.","type":"number"},"limitOrdersMonthly":{"description":"Max orders per calendar month. Tracked in usage_monthly table. 0 = unlimited.","type":"number"},"limitCustomers":{"description":"Max contact records in the system. 0 = unlimited.","type":"number"},"limitEmailsMonthly":{"description":"Max transactional emails per calendar month. 0 = unlimited.","type":"number"},"limitAiTokensMonthly":{"description":"Max AI token usage per calendar month. 0 = unlimited.","type":"number"},"limitForms":{"description":"Max form records. 0 = unlimited.","type":"number"}}},"logoUrl":{"nullable":true,"anyOf":[{"description":"Organisation logo URL displayed in the header of all outgoing email templates. Rendered as an <img> tag in the default email layout. If not set, the logo section is hidden. Also shown in the account organisation list for the logged-in user.","type":"string"},{"type":"null"}]},"printLogoUrl":{"nullable":true,"anyOf":[{"description":"Organisation logo URL optimized for print use (invoices, receipts, contracts, PDF documents). If not set, the standard logoUrl is used as fallback when generating print documents.","type":"string"},{"type":"null"}]},"primaryColor":{"nullable":true,"anyOf":[{"description":"Primary brand hex color of the organisation (e.g. \"#1a2b3c\"). Used for branding customization. Must be a valid 3 or 6 digit hex color with leading #.","examples":["#1a2b3c"],"type":"string"},{"type":"null"}]},"secondaryColor":{"nullable":true,"anyOf":[{"description":"Secondary brand hex color of the organisation (e.g. \"#f0f0f0\"). Used for branding customization. Must be a valid 3 or 6 digit hex color with leading #.","examples":["#f0f0f0"],"type":"string"},{"type":"null"}]},"supportEmail":{"nullable":true,"anyOf":[{"description":"Default \"From\" email address for all transactional emails: order confirmations, calendar event notifications, account registration, password resets, member invitations, credit/voucher notifications, and system alerts. If not configured, falls back to the organisation's internal contact email, then to \"info@brj.cz\".","examples":["info@example.com"],"type":"string"},{"type":"null"}]},"supportEmailMarketing":{"nullable":true,"anyOf":[{"description":"Override \"From\" email address used only for newsletter and marketing bulk emails. Allows separating marketing sender identity from transactional emails (different IP reputation, branding). If not set, marketing emails use the transactional supportEmail instead.","type":"string"},{"type":"null"}]},"emailerFooter":{"nullable":true,"anyOf":[{"description":"Custom HTML footer appended to the bottom of all outgoing emails (transactional, marketing, newsletters). Typically contains company info, legal disclaimers, and unsubscribe links. If not set, a default footer is auto-generated with the organisation name.","type":"string"},{"type":"null"}]},"emailerLayout":{"nullable":true,"anyOf":[{"description":"Custom HTML email template wrapper using Handlebars syntax. Wraps all outgoing email content. Supported variables: {{ htmlBody }} (email content), {{ logoUrl }} (org logo), {{ footer }} (footer HTML). Supports conditionals: {{ if logoUrl }}...{{ /if }}. If not set, uses the built-in default template with logo header, content area, and footer.","type":"string"},{"type":"null"}]},"emailerSmtpHost":{"nullable":true,"anyOf":[{"description":"SMTP server hostname for transactional email delivery (e.g. \"smtp.gmail.com\"). Required to enable any email sending. Without SMTP configured, the organisation cannot send emails. Validated by sending a test email during initial setup via /bff/emailer/setup-smtp.","type":"string"},{"type":"null"}]},"emailerSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP server port. Use \"587\" for STARTTLS (recommended) or \"465\" for implicit SSL. Port 465 enables secure: true in the SMTP connection; all other ports use STARTTLS upgrade.","type":"string"},{"type":"null"}]},"emailerSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP authentication username for transactional email delivery. Usually the email address itself (e.g. \"info@example.com\").","type":"string"},{"type":"null"}]},"emailerMarketingSmtpHost":{"nullable":true,"anyOf":[{"description":"Separate SMTP server for newsletter and marketing bulk emails. Allows using a dedicated email service (SendGrid, Mailchimp SMTP, etc.) with different rate limits and IP reputation. If not configured, marketing emails fall back to the transactional SMTP above.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port for marketing email server. Same port logic as transactional: \"587\" for STARTTLS, \"465\" for SSL.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP authentication username for marketing email server.","type":"string"},{"type":"null"}]},"emailerNewsletterReturnUrl":{"nullable":true,"anyOf":[{"description":"URL where users are redirected after clicking the newsletter subscription confirmation link. For example \"/newsletter-thanks\" or a specific blog post. If not set, no redirect happens and the API just returns a success response.","type":"string"},{"type":"null"}]},"smsSluzbaCzLogin":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account login (username). Required together with the password for outgoing SMS via the apixml30 gateway.","type":"string"},{"type":"null"}]},"smsSluzbaCzDefaultSender":{"nullable":true,"anyOf":[{"description":"Optional default sender label (numeric msisdn or alphanumeric brand) attached to outgoing SMS when the caller does not pass one explicitly.","type":"string"},{"type":"null"}]},"orderInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated email addresses that receive BCC copies of all order status notification emails. Internal team members listed here get notified whenever an order changes status (new, paid, shipped, cancelled, etc.). Emails are deduplicated and validated before sending.","type":"string"},{"type":"null"}]},"orderNewInternalNotificationEnabled":{"description":"When true, every new order creates a BizKitHub-internal notification e-mail delivered from `info@bizkithub.com` to the organisation support inbox (technical, system-baked template). Defaults to false. Throttled to a maximum of 10 deliveries per organisation per UTC day.","type":"boolean"},"orderRefundStrategy":{"nullable":true,"anyOf":[{"description":"Default refund strategy when an order is cancelled (storno). \"credit\" = money returned as store account credit (default). \"cash\" = triggers credit note generation and manual bank transfer refund. \"none\" = no refund issued. Can be overridden per individual storno request.","examples":["credit"],"type":"string"},{"type":"null"}]},"orderAccountingMode":{"nullable":true,"anyOf":[{"description":"Controls automatic credit note generation during cash refunds. \"auto\" or \"always\" = credit note (tax document) is auto-generated with storno items linked to the original invoice. \"never\" = skips credit note, requires manual accounting. Only applies when refund strategy is \"cash\" and the order was paid. Defaults to \"auto\".","examples":["auto"],"type":"string"},{"type":"null"}]},"logInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated email addresses that receive system error alert emails. Added as BCC on: (1) Daily log report — aggregated CRITICAL/ERROR/WARNING logs from the past 24 hours grouped by severity; (2) Individual critical error notifications triggered in real-time. Separate from order notification emails.","type":"string"},{"type":"null"}]},"logReportDisabled":{"description":"Per-organisation opt-out of the daily operational log report e-mail. False (default) keeps the report enabled. True suppresses it. Critical-level errors override this flag and are always delivered.","type":"boolean"},"postDigestEnabled":{"description":"Master switch for the automatic newsletter digest feature. When enabled, a cron job periodically collects recent blog posts and sends a digest email to all contacts with active newsletter subscriptions. Posts are ordered by star status and recency.","type":"boolean"},"postDigestIntervalDays":{"nullable":true,"anyOf":[{"description":"Number of days between automatic digest sends. The cron job checks: if (now - lastSentDate) >= intervalDays, send a new digest. Defaults to 14 days if not set. The timer resets even if no posts are found or no subscribers exist, to prevent retry storms.","type":"number"},{"type":"null"}]},"postDigestLastSentDate":{"nullable":true,"anyOf":[{"description":"ISO 8601 timestamp of the last digest send attempt. Managed automatically by the system — updated after each run (whether successful, no posts found, or no subscribers). Can be manually cleared to force an immediate next send. Read-only in the UI.","type":"string"},{"type":"null"}]},"postDigestSubject":{"nullable":true,"anyOf":[{"description":"Email subject line template for digest newsletters. Supports Handlebars variables: {{ postCount }} (number of articles in this digest) and {{ intervalDays }} (configured interval). Default: \"Nové články ({{ postCount }})\" → renders as e.g. \"Nové články (5)\".","type":"string"},{"type":"null"}]},"postDigestIntroText":{"nullable":true,"anyOf":[{"description":"Custom HTML text inserted before the article list in the digest email body. Rendered as raw HTML without sanitization. Use for welcome messages, promotional text, or instructions. If empty, the email starts directly with the post list.","type":"string"},{"type":"null"}]},"postDigestLocale":{"nullable":true,"anyOf":[{"description":"Override locale code (e.g. \"cs\", \"en\") for selecting which posts appear in the digest. Only posts in this locale are included. If not set, falls back to the organisation's primary locale. Useful for multilingual organisations that want to send Czech-only or English-only digests.","type":"string"},{"type":"null"}]},"postDigestMaxPosts":{"nullable":true,"anyOf":[{"description":"Maximum number of posts to include in a single digest email. Posts are selected by: starred first, then most recently updated. Defaults to 20 if not set. Controls email length — lower values keep digests concise.","type":"number"},{"type":"null"}]},"paymentRecurringEnabled":{"description":"Enables automatic recurring subscription payment charging via Comgate gateway. When true, the system can: (1) initialize card tokenization on first payment (initRecurring flag), and (2) charge subsequent subscription payments automatically without customer re-authentication. Required for SaaS/subscription billing models.","type":"boolean"},"customerCreditDefaultExpiration":{"nullable":true,"anyOf":[{"description":"Default expiration period for newly created customer account credit (e.g. from refunds or manual additions). Value in days (e.g. \"365\" for 1 year). Expired credit cannot be used for purchases. If not set, credit records are created without expiration. Applied automatically when credit is issued via storno refund or manual addition.","type":"string"},{"type":"null"}]},"storageUsed":{"description":"Current total storage usage in bytes (read-only). Calculated by summing all blob file sizes for this organisation. Updated automatically by the storage read model. Compare with tariff.storageMb to show usage percentage.","type":"number"},"insertedDate":{"description":"ISO 8601 timestamp when the organisation was created. Read-only metadata for display purposes.","type":"string"}},"required":["name","slug","storageSlug","description","emoji","companyRegistrationNumber","taxIdentificationNumber","vatPayer","accountingCountry","legalForm","disableExperiments","timezone","primaryLocale","defaultCurrency","supportPerson","vendor","tariff","logoUrl","printLogoUrl","primaryColor","secondaryColor","supportEmail","supportEmailMarketing","emailerFooter","emailerLayout","emailerSmtpHost","emailerSmtpPort","emailerSmtpUser","emailerMarketingSmtpHost","emailerMarketingSmtpPort","emailerMarketingSmtpUser","emailerNewsletterReturnUrl","smsSluzbaCzLogin","smsSluzbaCzDefaultSender","orderInternalNotificationEmails","orderNewInternalNotificationEnabled","orderRefundStrategy","orderAccountingMode","logInternalNotificationEmails","logReportDisabled","postDigestEnabled","postDigestIntervalDays","postDigestLastSentDate","postDigestSubject","postDigestIntroText","postDigestLocale","postDigestMaxPosts","paymentRecurringEnabled","customerCreditDefaultExpiration","storageUsed","insertedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"description":"Organisation display name. Used as the sender name in all outgoing emails (transactional, marketing, newsletters), shown on invoices as the supplier name, displayed in admin panels and organisation switcher. Must be unique across all organisations.","type":"string"},"slug":{"description":"URL-safe unique identifier. Used in public URLs (e.g. /[slug]/...), newsletter unsubscribe links, Firmy.cz feed paths, and terminal commands for org switching. Read-only — set at creation from the org name.","type":"string"},"storageSlug":{"description":"CDN storage path prefix. All uploaded files (images, documents) are stored under this slug at the storage CDN (e.g. https://storage.xhp.cz/{storageSlug}/...). Read-only — set at creation, same as slug.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Organisation about text / profile description. Shown in admin organisation lists. Optional free-form text for internal reference.","type":"string"},{"type":"null"}]},"emoji":{"nullable":true,"anyOf":[{"description":"Visual emoji icon for the organisation. Displayed next to the org name in account details, org switcher, and terminal output. If not set manually, the system auto-generates one using AI based on the org configuration.","type":"string"},{"type":"null"}]},"companyRegistrationNumber":{"nullable":true,"anyOf":[{"description":"Czech company registration number (IČO). Printed on invoices and receipts as \"IČO: {value}\". Used for ARES address lookup, Firmy.cz feed integration, and invoice export data for accounting.","type":"string"},{"type":"null"}]},"taxIdentificationNumber":{"nullable":true,"anyOf":[{"description":"Tax identification number (DIČ). Printed on invoices and receipts as \"DIČ: {value}\". Used for address lookup validation and included in invoice exports for accounting software.","type":"string"},{"type":"null"}]},"vatPayer":{"description":"Whether the organisation is a VAT payer. When true, invoices include VAT rates (21%, 12%, 0%) on line items. When false, all invoice items use 0% VAT. Also triggers unreliable VAT payer fraud checks against the Czech Ministry of Finance list.","type":"boolean"},"accountingCountry":{"nullable":true,"anyOf":[{"type":"object","required":["id","code","name"],"properties":{"id":{"description":"Internal country ID. Use this value as accountingCountryId in update-profile.","type":"number"},"code":{"description":"ISO 3166-1 alpha-2 country code. Defines accounting / tax jurisdiction (used for VAT rules, ARES vs RPO lookup, legal form picker scoping).","examples":["CZ"],"type":"string"},"name":{"description":"Localized country name (English).","type":"string"}}},{"type":"null"}]},"legalForm":{"nullable":true,"anyOf":[{"type":"object","required":["id","code","slug","name"],"properties":{"id":{"description":"Internal legal form ID. Use this value as legalFormId in update-profile.","type":"number"},"code":{"description":"Country-specific legal form code (e.g. ARES \"pravniForma\" 112 = s.r.o. in CZ).","examples":["112"],"type":"string"},"slug":{"description":"Cross-country slug (osvc, sro, as, vos, ks, druzstvo, po, fo_podnikatel, neziskovka...).","examples":["sro"],"type":"string"},"name":{"description":"Localized human-readable legal form name.","examples":["Společnost s ručením omezeným (s.r.o.)"],"type":"string"}}},{"type":"null"}]},"disableExperiments":{"description":"Disables experimental AI-powered features for this organisation. When true, the system skips AI issue routing and AI-generated responses in the issue/ticket workflow. Organisations start with this disabled (false) by default.","type":"boolean"},"timezone":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"description":"Internal timezone ID. Use this value when setting timezoneId in update-profile.","type":"number"},"timezone":{"description":"IANA timezone identifier. Used to format dates in email notifications and calendar events.","examples":["Europe/Prague"],"type":"string"},"gmt":{"description":"GMT offset string for display purposes.","examples":["+01:00"],"type":"string"},"label":{"description":"Human-readable timezone label for picker display.","examples":["Central European Time - Prague"],"type":"string"}}},"primaryLocale":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Internal locale ID. Use this value when setting primaryLocaleId in update-profile.","type":"number"},"locale":{"description":"ISO 639-1 locale code. Determines default language for contacts, emails, and content selection.","examples":["cs"],"type":"string"}}},"defaultCurrency":{"description":"Default currency ISO 4217 code (e.g. \"CZK\"). Used for pricing of products and orders. Changing this value is a sensitive operation — update requests that attempt to change it are rejected and logged as a warning; contact BizKitHub technical support to change the organisation default currency.","examples":["CZK"],"type":"string"},"supportPerson":{"nullable":true,"anyOf":[{"type":"object","required":["id","fullName"],"properties":{"id":{"description":"Internal member ID of the support person (from GET /organisation/members).","type":"number"},"fullName":{"description":"Full name of the designated support contact for this organisation.","type":"string"}}},{"type":"null"}]},"vendor":{"nullable":true,"anyOf":[{"description":"Vendor (parent) organisation that resells / technically manages this org. Returned only when (a) parent_id is set AND (b) the parent holds an active white-label licence. NULL otherwise — i.e. either we sell directly to the customer or the parent's licence has been revoked.","type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug — used by /vendor/switch.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor (mirror of cas__white_label_licence.licence_key).","type":"string"},"contactPerson":{"nullable":true,"anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"description":"cas__organisation_member.id of the vendor's nominated contact.","type":"number"},"firstName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"nullable":true,"anyOf":[{"description":"Email address customers should write to. Resolved as: vendor's `default_send_from_email` (transactional sender) → contact person's login username → null.","type":"string"},{"type":"null"}]},"myTariff":{"description":"The CUSTOMER's own tariff & billing summary — what the vendor manages on their behalf. Bundled here so the settings page can render \"Spravuje mě\" + \"Můj tarif\" in one go.","type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"description":"Tariff id from cas__tariff.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"description":"Tariff display name.","type":"string"},"monthlyPriceCzk":{"description":"Final monthly price the customer actually pays, in WHOLE CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"},"customPriceCzk":{"nullable":true,"anyOf":[{"description":"Negotiated price (CZK) when set, NULL = catalogue minus discount.","type":"number"},{"type":"null"}]},"discountPercent":{"description":"Discount applied on top of catalogue price (0-100).","type":"number"},"expiresAt":{"nullable":true,"anyOf":[{"description":"ISO datetime when the current paid period ends. NULL = no paid-until set.","type":"string"},{"type":"null"}]},"daysUntilExpiry":{"nullable":true,"anyOf":[{"description":"Whole days until expiry. Negative = already expired.","type":"number"},{"type":"null"}]},"isExpired":{"description":"TRUE when expiresAt < now.","type":"boolean"}}}}},{"type":"null"}]},"tariff":{"type":"object","required":["id","code","storageMb","limitMembers","limitProducts","limitOrdersMonthly","limitCustomers","limitEmailsMonthly","limitAiTokensMonthly","limitForms"],"properties":{"id":{"description":"Tariff ID (read-only — managed via /tariff endpoints by admins).","type":"number"},"code":{"description":"Tariff plan identifier. Determines resource limits and pricing for the organisation.","examples":["business"],"type":"string"},"storageMb":{"description":"File storage limit in MB. Compare with storageUsed (in bytes) to calculate usage. 0 = unlimited.","type":"number"},"limitMembers":{"description":"Max active (non-blocked) organisation members. 0 = unlimited.","type":"number"},"limitProducts":{"description":"Max non-deleted products in the shop. 0 = unlimited.","type":"number"},"limitOrdersMonthly":{"description":"Max orders per calendar month. Tracked in usage_monthly table. 0 = unlimited.","type":"number"},"limitCustomers":{"description":"Max contact records in the system. 0 = unlimited.","type":"number"},"limitEmailsMonthly":{"description":"Max transactional emails per calendar month. 0 = unlimited.","type":"number"},"limitAiTokensMonthly":{"description":"Max AI token usage per calendar month. 0 = unlimited.","type":"number"},"limitForms":{"description":"Max form records. 0 = unlimited.","type":"number"}}},"logoUrl":{"nullable":true,"anyOf":[{"description":"Organisation logo URL displayed in the header of all outgoing email templates. Rendered as an <img> tag in the default email layout. If not set, the logo section is hidden. Also shown in the account organisation list for the logged-in user.","type":"string"},{"type":"null"}]},"printLogoUrl":{"nullable":true,"anyOf":[{"description":"Organisation logo URL optimized for print use (invoices, receipts, contracts, PDF documents). If not set, the standard logoUrl is used as fallback when generating print documents.","type":"string"},{"type":"null"}]},"primaryColor":{"nullable":true,"anyOf":[{"description":"Primary brand hex color of the organisation (e.g. \"#1a2b3c\"). Used for branding customization. Must be a valid 3 or 6 digit hex color with leading #.","examples":["#1a2b3c"],"type":"string"},{"type":"null"}]},"secondaryColor":{"nullable":true,"anyOf":[{"description":"Secondary brand hex color of the organisation (e.g. \"#f0f0f0\"). Used for branding customization. Must be a valid 3 or 6 digit hex color with leading #.","examples":["#f0f0f0"],"type":"string"},{"type":"null"}]},"supportEmail":{"nullable":true,"anyOf":[{"description":"Default \"From\" email address for all transactional emails: order confirmations, calendar event notifications, account registration, password resets, member invitations, credit/voucher notifications, and system alerts. If not configured, falls back to the organisation's internal contact email, then to \"info@brj.cz\".","examples":["info@example.com"],"type":"string"},{"type":"null"}]},"supportEmailMarketing":{"nullable":true,"anyOf":[{"description":"Override \"From\" email address used only for newsletter and marketing bulk emails. Allows separating marketing sender identity from transactional emails (different IP reputation, branding). If not set, marketing emails use the transactional supportEmail instead.","type":"string"},{"type":"null"}]},"emailerFooter":{"nullable":true,"anyOf":[{"description":"Custom HTML footer appended to the bottom of all outgoing emails (transactional, marketing, newsletters). Typically contains company info, legal disclaimers, and unsubscribe links. If not set, a default footer is auto-generated with the organisation name.","type":"string"},{"type":"null"}]},"emailerLayout":{"nullable":true,"anyOf":[{"description":"Custom HTML email template wrapper using Handlebars syntax. Wraps all outgoing email content. Supported variables: {{ htmlBody }} (email content), {{ logoUrl }} (org logo), {{ footer }} (footer HTML). Supports conditionals: {{ if logoUrl }}...{{ /if }}. If not set, uses the built-in default template with logo header, content area, and footer.","type":"string"},{"type":"null"}]},"emailerSmtpHost":{"nullable":true,"anyOf":[{"description":"SMTP server hostname for transactional email delivery (e.g. \"smtp.gmail.com\"). Required to enable any email sending. Without SMTP configured, the organisation cannot send emails. Validated by sending a test email during initial setup via /bff/emailer/setup-smtp.","type":"string"},{"type":"null"}]},"emailerSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP server port. Use \"587\" for STARTTLS (recommended) or \"465\" for implicit SSL. Port 465 enables secure: true in the SMTP connection; all other ports use STARTTLS upgrade.","type":"string"},{"type":"null"}]},"emailerSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP authentication username for transactional email delivery. Usually the email address itself (e.g. \"info@example.com\").","type":"string"},{"type":"null"}]},"emailerMarketingSmtpHost":{"nullable":true,"anyOf":[{"description":"Separate SMTP server for newsletter and marketing bulk emails. Allows using a dedicated email service (SendGrid, Mailchimp SMTP, etc.) with different rate limits and IP reputation. If not configured, marketing emails fall back to the transactional SMTP above.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port for marketing email server. Same port logic as transactional: \"587\" for STARTTLS, \"465\" for SSL.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP authentication username for marketing email server.","type":"string"},{"type":"null"}]},"emailerNewsletterReturnUrl":{"nullable":true,"anyOf":[{"description":"URL where users are redirected after clicking the newsletter subscription confirmation link. For example \"/newsletter-thanks\" or a specific blog post. If not set, no redirect happens and the API just returns a success response.","type":"string"},{"type":"null"}]},"smsSluzbaCzLogin":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account login (username). Required together with the password for outgoing SMS via the apixml30 gateway.","type":"string"},{"type":"null"}]},"smsSluzbaCzDefaultSender":{"nullable":true,"anyOf":[{"description":"Optional default sender label (numeric msisdn or alphanumeric brand) attached to outgoing SMS when the caller does not pass one explicitly.","type":"string"},{"type":"null"}]},"orderInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated email addresses that receive BCC copies of all order status notification emails. Internal team members listed here get notified whenever an order changes status (new, paid, shipped, cancelled, etc.). Emails are deduplicated and validated before sending.","type":"string"},{"type":"null"}]},"orderNewInternalNotificationEnabled":{"description":"When true, every new order creates a BizKitHub-internal notification e-mail delivered from `info@bizkithub.com` to the organisation support inbox (technical, system-baked template). Defaults to false. Throttled to a maximum of 10 deliveries per organisation per UTC day.","type":"boolean"},"orderRefundStrategy":{"nullable":true,"anyOf":[{"description":"Default refund strategy when an order is cancelled (storno). \"credit\" = money returned as store account credit (default). \"cash\" = triggers credit note generation and manual bank transfer refund. \"none\" = no refund issued. Can be overridden per individual storno request.","examples":["credit"],"type":"string"},{"type":"null"}]},"orderAccountingMode":{"nullable":true,"anyOf":[{"description":"Controls automatic credit note generation during cash refunds. \"auto\" or \"always\" = credit note (tax document) is auto-generated with storno items linked to the original invoice. \"never\" = skips credit note, requires manual accounting. Only applies when refund strategy is \"cash\" and the order was paid. Defaults to \"auto\".","examples":["auto"],"type":"string"},{"type":"null"}]},"logInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated email addresses that receive system error alert emails. Added as BCC on: (1) Daily log report — aggregated CRITICAL/ERROR/WARNING logs from the past 24 hours grouped by severity; (2) Individual critical error notifications triggered in real-time. Separate from order notification emails.","type":"string"},{"type":"null"}]},"logReportDisabled":{"description":"Per-organisation opt-out of the daily operational log report e-mail. False (default) keeps the report enabled. True suppresses it. Critical-level errors override this flag and are always delivered.","type":"boolean"},"postDigestEnabled":{"description":"Master switch for the automatic newsletter digest feature. When enabled, a cron job periodically collects recent blog posts and sends a digest email to all contacts with active newsletter subscriptions. Posts are ordered by star status and recency.","type":"boolean"},"postDigestIntervalDays":{"nullable":true,"anyOf":[{"description":"Number of days between automatic digest sends. The cron job checks: if (now - lastSentDate) >= intervalDays, send a new digest. Defaults to 14 days if not set. The timer resets even if no posts are found or no subscribers exist, to prevent retry storms.","type":"number"},{"type":"null"}]},"postDigestLastSentDate":{"nullable":true,"anyOf":[{"description":"ISO 8601 timestamp of the last digest send attempt. Managed automatically by the system — updated after each run (whether successful, no posts found, or no subscribers). Can be manually cleared to force an immediate next send. Read-only in the UI.","type":"string"},{"type":"null"}]},"postDigestSubject":{"nullable":true,"anyOf":[{"description":"Email subject line template for digest newsletters. Supports Handlebars variables: {{ postCount }} (number of articles in this digest) and {{ intervalDays }} (configured interval). Default: \"Nové články ({{ postCount }})\" → renders as e.g. \"Nové články (5)\".","type":"string"},{"type":"null"}]},"postDigestIntroText":{"nullable":true,"anyOf":[{"description":"Custom HTML text inserted before the article list in the digest email body. Rendered as raw HTML without sanitization. Use for welcome messages, promotional text, or instructions. If empty, the email starts directly with the post list.","type":"string"},{"type":"null"}]},"postDigestLocale":{"nullable":true,"anyOf":[{"description":"Override locale code (e.g. \"cs\", \"en\") for selecting which posts appear in the digest. Only posts in this locale are included. If not set, falls back to the organisation's primary locale. Useful for multilingual organisations that want to send Czech-only or English-only digests.","type":"string"},{"type":"null"}]},"postDigestMaxPosts":{"nullable":true,"anyOf":[{"description":"Maximum number of posts to include in a single digest email. Posts are selected by: starred first, then most recently updated. Defaults to 20 if not set. Controls email length — lower values keep digests concise.","type":"number"},{"type":"null"}]},"paymentRecurringEnabled":{"description":"Enables automatic recurring subscription payment charging via Comgate gateway. When true, the system can: (1) initialize card tokenization on first payment (initRecurring flag), and (2) charge subsequent subscription payments automatically without customer re-authentication. Required for SaaS/subscription billing models.","type":"boolean"},"customerCreditDefaultExpiration":{"nullable":true,"anyOf":[{"description":"Default expiration period for newly created customer account credit (e.g. from refunds or manual additions). Value in days (e.g. \"365\" for 1 year). Expired credit cannot be used for purchases. If not set, credit records are created without expiration. Applied automatically when credit is issued via storno refund or manual addition.","type":"string"},{"type":"null"}]},"storageUsed":{"description":"Current total storage usage in bytes (read-only). Calculated by summing all blob file sizes for this organisation. Updated automatically by the storage read model. Compare with tariff.storageMb to show usage percentage.","type":"number"},"insertedDate":{"description":"ISO 8601 timestamp when the organisation was created. Read-only metadata for display purposes.","type":"string"}},"required":["name","slug","storageSlug","description","emoji","companyRegistrationNumber","taxIdentificationNumber","vatPayer","accountingCountry","legalForm","disableExperiments","timezone","primaryLocale","defaultCurrency","supportPerson","vendor","tariff","logoUrl","printLogoUrl","primaryColor","secondaryColor","supportEmail","supportEmailMarketing","emailerFooter","emailerLayout","emailerSmtpHost","emailerSmtpPort","emailerSmtpUser","emailerMarketingSmtpHost","emailerMarketingSmtpPort","emailerMarketingSmtpUser","emailerNewsletterReturnUrl","smsSluzbaCzLogin","smsSluzbaCzDefaultSender","orderInternalNotificationEmails","orderNewInternalNotificationEnabled","orderRefundStrategy","orderAccountingMode","logInternalNotificationEmails","logReportDisabled","postDigestEnabled","postDigestIntervalDays","postDigestLastSentDate","postDigestSubject","postDigestIntroText","postDigestLocale","postDigestMaxPosts","paymentRecurringEnabled","customerCreditDefaultExpiration","storageUsed","insertedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"name":{"description":"Organisation display name. Used as the sender name in all outgoing emails (transactional, marketing, newsletters), shown on invoices as the supplier name, displayed in admin panels and organisation switcher. Must be unique across all organisations.","type":"string"},"slug":{"description":"URL-safe unique identifier. Used in public URLs (e.g. /[slug]/...), newsletter unsubscribe links, Firmy.cz feed paths, and terminal commands for org switching. Read-only — set at creation from the org name.","type":"string"},"storageSlug":{"description":"CDN storage path prefix. All uploaded files (images, documents) are stored under this slug at the storage CDN (e.g. https://storage.xhp.cz/{storageSlug}/...). Read-only — set at creation, same as slug.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Organisation about text / profile description. Shown in admin organisation lists. Optional free-form text for internal reference.","type":"string"},{"type":"null"}]},"emoji":{"nullable":true,"anyOf":[{"description":"Visual emoji icon for the organisation. Displayed next to the org name in account details, org switcher, and terminal output. If not set manually, the system auto-generates one using AI based on the org configuration.","type":"string"},{"type":"null"}]},"companyRegistrationNumber":{"nullable":true,"anyOf":[{"description":"Czech company registration number (IČO). Printed on invoices and receipts as \"IČO: {value}\". Used for ARES address lookup, Firmy.cz feed integration, and invoice export data for accounting.","type":"string"},{"type":"null"}]},"taxIdentificationNumber":{"nullable":true,"anyOf":[{"description":"Tax identification number (DIČ). Printed on invoices and receipts as \"DIČ: {value}\". Used for address lookup validation and included in invoice exports for accounting software.","type":"string"},{"type":"null"}]},"vatPayer":{"description":"Whether the organisation is a VAT payer. When true, invoices include VAT rates (21%, 12%, 0%) on line items. When false, all invoice items use 0% VAT. Also triggers unreliable VAT payer fraud checks against the Czech Ministry of Finance list.","type":"boolean"},"accountingCountry":{"nullable":true,"anyOf":[{"type":"object","required":["id","code","name"],"properties":{"id":{"description":"Internal country ID. Use this value as accountingCountryId in update-profile.","type":"number"},"code":{"description":"ISO 3166-1 alpha-2 country code. Defines accounting / tax jurisdiction (used for VAT rules, ARES vs RPO lookup, legal form picker scoping).","examples":["CZ"],"type":"string"},"name":{"description":"Localized country name (English).","type":"string"}}},{"type":"null"}]},"legalForm":{"nullable":true,"anyOf":[{"type":"object","required":["id","code","slug","name"],"properties":{"id":{"description":"Internal legal form ID. Use this value as legalFormId in update-profile.","type":"number"},"code":{"description":"Country-specific legal form code (e.g. ARES \"pravniForma\" 112 = s.r.o. in CZ).","examples":["112"],"type":"string"},"slug":{"description":"Cross-country slug (osvc, sro, as, vos, ks, druzstvo, po, fo_podnikatel, neziskovka...).","examples":["sro"],"type":"string"},"name":{"description":"Localized human-readable legal form name.","examples":["Společnost s ručením omezeným (s.r.o.)"],"type":"string"}}},{"type":"null"}]},"disableExperiments":{"description":"Disables experimental AI-powered features for this organisation. When true, the system skips AI issue routing and AI-generated responses in the issue/ticket workflow. Organisations start with this disabled (false) by default.","type":"boolean"},"timezone":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"description":"Internal timezone ID. Use this value when setting timezoneId in update-profile.","type":"number"},"timezone":{"description":"IANA timezone identifier. Used to format dates in email notifications and calendar events.","examples":["Europe/Prague"],"type":"string"},"gmt":{"description":"GMT offset string for display purposes.","examples":["+01:00"],"type":"string"},"label":{"description":"Human-readable timezone label for picker display.","examples":["Central European Time - Prague"],"type":"string"}}},"primaryLocale":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Internal locale ID. Use this value when setting primaryLocaleId in update-profile.","type":"number"},"locale":{"description":"ISO 639-1 locale code. Determines default language for contacts, emails, and content selection.","examples":["cs"],"type":"string"}}},"defaultCurrency":{"description":"Default currency ISO 4217 code (e.g. \"CZK\"). Used for pricing of products and orders. Changing this value is a sensitive operation — update requests that attempt to change it are rejected and logged as a warning; contact BizKitHub technical support to change the organisation default currency.","examples":["CZK"],"type":"string"},"supportPerson":{"nullable":true,"anyOf":[{"type":"object","required":["id","fullName"],"properties":{"id":{"description":"Internal member ID of the support person (from GET /organisation/members).","type":"number"},"fullName":{"description":"Full name of the designated support contact for this organisation.","type":"string"}}},{"type":"null"}]},"vendor":{"nullable":true,"anyOf":[{"description":"Vendor (parent) organisation that resells / technically manages this org. Returned only when (a) parent_id is set AND (b) the parent holds an active white-label licence. NULL otherwise — i.e. either we sell directly to the customer or the parent's licence has been revoked.","type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug — used by /vendor/switch.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor (mirror of cas__white_label_licence.licence_key).","type":"string"},"contactPerson":{"nullable":true,"anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"description":"cas__organisation_member.id of the vendor's nominated contact.","type":"number"},"firstName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"nullable":true,"anyOf":[{"description":"Email address customers should write to. Resolved as: vendor's `default_send_from_email` (transactional sender) → contact person's login username → null.","type":"string"},{"type":"null"}]},"myTariff":{"description":"The CUSTOMER's own tariff & billing summary — what the vendor manages on their behalf. Bundled here so the settings page can render \"Spravuje mě\" + \"Můj tarif\" in one go.","type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"description":"Tariff id from cas__tariff.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"description":"Tariff display name.","type":"string"},"monthlyPriceCzk":{"description":"Final monthly price the customer actually pays, in WHOLE CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"},"customPriceCzk":{"nullable":true,"anyOf":[{"description":"Negotiated price (CZK) when set, NULL = catalogue minus discount.","type":"number"},{"type":"null"}]},"discountPercent":{"description":"Discount applied on top of catalogue price (0-100).","type":"number"},"expiresAt":{"nullable":true,"anyOf":[{"description":"ISO datetime when the current paid period ends. NULL = no paid-until set.","type":"string"},{"type":"null"}]},"daysUntilExpiry":{"nullable":true,"anyOf":[{"description":"Whole days until expiry. Negative = already expired.","type":"number"},{"type":"null"}]},"isExpired":{"description":"TRUE when expiresAt < now.","type":"boolean"}}}}},{"type":"null"}]},"tariff":{"type":"object","required":["id","code","storageMb","limitMembers","limitProducts","limitOrdersMonthly","limitCustomers","limitEmailsMonthly","limitAiTokensMonthly","limitForms"],"properties":{"id":{"description":"Tariff ID (read-only — managed via /tariff endpoints by admins).","type":"number"},"code":{"description":"Tariff plan identifier. Determines resource limits and pricing for the organisation.","examples":["business"],"type":"string"},"storageMb":{"description":"File storage limit in MB. Compare with storageUsed (in bytes) to calculate usage. 0 = unlimited.","type":"number"},"limitMembers":{"description":"Max active (non-blocked) organisation members. 0 = unlimited.","type":"number"},"limitProducts":{"description":"Max non-deleted products in the shop. 0 = unlimited.","type":"number"},"limitOrdersMonthly":{"description":"Max orders per calendar month. Tracked in usage_monthly table. 0 = unlimited.","type":"number"},"limitCustomers":{"description":"Max contact records in the system. 0 = unlimited.","type":"number"},"limitEmailsMonthly":{"description":"Max transactional emails per calendar month. 0 = unlimited.","type":"number"},"limitAiTokensMonthly":{"description":"Max AI token usage per calendar month. 0 = unlimited.","type":"number"},"limitForms":{"description":"Max form records. 0 = unlimited.","type":"number"}}},"logoUrl":{"nullable":true,"anyOf":[{"description":"Organisation logo URL displayed in the header of all outgoing email templates. Rendered as an <img> tag in the default email layout. If not set, the logo section is hidden. Also shown in the account organisation list for the logged-in user.","type":"string"},{"type":"null"}]},"printLogoUrl":{"nullable":true,"anyOf":[{"description":"Organisation logo URL optimized for print use (invoices, receipts, contracts, PDF documents). If not set, the standard logoUrl is used as fallback when generating print documents.","type":"string"},{"type":"null"}]},"primaryColor":{"nullable":true,"anyOf":[{"description":"Primary brand hex color of the organisation (e.g. \"#1a2b3c\"). Used for branding customization. Must be a valid 3 or 6 digit hex color with leading #.","examples":["#1a2b3c"],"type":"string"},{"type":"null"}]},"secondaryColor":{"nullable":true,"anyOf":[{"description":"Secondary brand hex color of the organisation (e.g. \"#f0f0f0\"). Used for branding customization. Must be a valid 3 or 6 digit hex color with leading #.","examples":["#f0f0f0"],"type":"string"},{"type":"null"}]},"supportEmail":{"nullable":true,"anyOf":[{"description":"Default \"From\" email address for all transactional emails: order confirmations, calendar event notifications, account registration, password resets, member invitations, credit/voucher notifications, and system alerts. If not configured, falls back to the organisation's internal contact email, then to \"info@brj.cz\".","examples":["info@example.com"],"type":"string"},{"type":"null"}]},"supportEmailMarketing":{"nullable":true,"anyOf":[{"description":"Override \"From\" email address used only for newsletter and marketing bulk emails. Allows separating marketing sender identity from transactional emails (different IP reputation, branding). If not set, marketing emails use the transactional supportEmail instead.","type":"string"},{"type":"null"}]},"emailerFooter":{"nullable":true,"anyOf":[{"description":"Custom HTML footer appended to the bottom of all outgoing emails (transactional, marketing, newsletters). Typically contains company info, legal disclaimers, and unsubscribe links. If not set, a default footer is auto-generated with the organisation name.","type":"string"},{"type":"null"}]},"emailerLayout":{"nullable":true,"anyOf":[{"description":"Custom HTML email template wrapper using Handlebars syntax. Wraps all outgoing email content. Supported variables: {{ htmlBody }} (email content), {{ logoUrl }} (org logo), {{ footer }} (footer HTML). Supports conditionals: {{ if logoUrl }}...{{ /if }}. If not set, uses the built-in default template with logo header, content area, and footer.","type":"string"},{"type":"null"}]},"emailerSmtpHost":{"nullable":true,"anyOf":[{"description":"SMTP server hostname for transactional email delivery (e.g. \"smtp.gmail.com\"). Required to enable any email sending. Without SMTP configured, the organisation cannot send emails. Validated by sending a test email during initial setup via /bff/emailer/setup-smtp.","type":"string"},{"type":"null"}]},"emailerSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP server port. Use \"587\" for STARTTLS (recommended) or \"465\" for implicit SSL. Port 465 enables secure: true in the SMTP connection; all other ports use STARTTLS upgrade.","type":"string"},{"type":"null"}]},"emailerSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP authentication username for transactional email delivery. Usually the email address itself (e.g. \"info@example.com\").","type":"string"},{"type":"null"}]},"emailerMarketingSmtpHost":{"nullable":true,"anyOf":[{"description":"Separate SMTP server for newsletter and marketing bulk emails. Allows using a dedicated email service (SendGrid, Mailchimp SMTP, etc.) with different rate limits and IP reputation. If not configured, marketing emails fall back to the transactional SMTP above.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port for marketing email server. Same port logic as transactional: \"587\" for STARTTLS, \"465\" for SSL.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP authentication username for marketing email server.","type":"string"},{"type":"null"}]},"emailerNewsletterReturnUrl":{"nullable":true,"anyOf":[{"description":"URL where users are redirected after clicking the newsletter subscription confirmation link. For example \"/newsletter-thanks\" or a specific blog post. If not set, no redirect happens and the API just returns a success response.","type":"string"},{"type":"null"}]},"smsSluzbaCzLogin":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account login (username). Required together with the password for outgoing SMS via the apixml30 gateway.","type":"string"},{"type":"null"}]},"smsSluzbaCzDefaultSender":{"nullable":true,"anyOf":[{"description":"Optional default sender label (numeric msisdn or alphanumeric brand) attached to outgoing SMS when the caller does not pass one explicitly.","type":"string"},{"type":"null"}]},"orderInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated email addresses that receive BCC copies of all order status notification emails. Internal team members listed here get notified whenever an order changes status (new, paid, shipped, cancelled, etc.). Emails are deduplicated and validated before sending.","type":"string"},{"type":"null"}]},"orderNewInternalNotificationEnabled":{"description":"When true, every new order creates a BizKitHub-internal notification e-mail delivered from `info@bizkithub.com` to the organisation support inbox (technical, system-baked template). Defaults to false. Throttled to a maximum of 10 deliveries per organisation per UTC day.","type":"boolean"},"orderRefundStrategy":{"nullable":true,"anyOf":[{"description":"Default refund strategy when an order is cancelled (storno). \"credit\" = money returned as store account credit (default). \"cash\" = triggers credit note generation and manual bank transfer refund. \"none\" = no refund issued. Can be overridden per individual storno request.","examples":["credit"],"type":"string"},{"type":"null"}]},"orderAccountingMode":{"nullable":true,"anyOf":[{"description":"Controls automatic credit note generation during cash refunds. \"auto\" or \"always\" = credit note (tax document) is auto-generated with storno items linked to the original invoice. \"never\" = skips credit note, requires manual accounting. Only applies when refund strategy is \"cash\" and the order was paid. Defaults to \"auto\".","examples":["auto"],"type":"string"},{"type":"null"}]},"logInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated email addresses that receive system error alert emails. Added as BCC on: (1) Daily log report — aggregated CRITICAL/ERROR/WARNING logs from the past 24 hours grouped by severity; (2) Individual critical error notifications triggered in real-time. Separate from order notification emails.","type":"string"},{"type":"null"}]},"logReportDisabled":{"description":"Per-organisation opt-out of the daily operational log report e-mail. False (default) keeps the report enabled. True suppresses it. Critical-level errors override this flag and are always delivered.","type":"boolean"},"postDigestEnabled":{"description":"Master switch for the automatic newsletter digest feature. When enabled, a cron job periodically collects recent blog posts and sends a digest email to all contacts with active newsletter subscriptions. Posts are ordered by star status and recency.","type":"boolean"},"postDigestIntervalDays":{"nullable":true,"anyOf":[{"description":"Number of days between automatic digest sends. The cron job checks: if (now - lastSentDate) >= intervalDays, send a new digest. Defaults to 14 days if not set. The timer resets even if no posts are found or no subscribers exist, to prevent retry storms.","type":"number"},{"type":"null"}]},"postDigestLastSentDate":{"nullable":true,"anyOf":[{"description":"ISO 8601 timestamp of the last digest send attempt. Managed automatically by the system — updated after each run (whether successful, no posts found, or no subscribers). Can be manually cleared to force an immediate next send. Read-only in the UI.","type":"string"},{"type":"null"}]},"postDigestSubject":{"nullable":true,"anyOf":[{"description":"Email subject line template for digest newsletters. Supports Handlebars variables: {{ postCount }} (number of articles in this digest) and {{ intervalDays }} (configured interval). Default: \"Nové články ({{ postCount }})\" → renders as e.g. \"Nové články (5)\".","type":"string"},{"type":"null"}]},"postDigestIntroText":{"nullable":true,"anyOf":[{"description":"Custom HTML text inserted before the article list in the digest email body. Rendered as raw HTML without sanitization. Use for welcome messages, promotional text, or instructions. If empty, the email starts directly with the post list.","type":"string"},{"type":"null"}]},"postDigestLocale":{"nullable":true,"anyOf":[{"description":"Override locale code (e.g. \"cs\", \"en\") for selecting which posts appear in the digest. Only posts in this locale are included. If not set, falls back to the organisation's primary locale. Useful for multilingual organisations that want to send Czech-only or English-only digests.","type":"string"},{"type":"null"}]},"postDigestMaxPosts":{"nullable":true,"anyOf":[{"description":"Maximum number of posts to include in a single digest email. Posts are selected by: starred first, then most recently updated. Defaults to 20 if not set. Controls email length — lower values keep digests concise.","type":"number"},{"type":"null"}]},"paymentRecurringEnabled":{"description":"Enables automatic recurring subscription payment charging via Comgate gateway. When true, the system can: (1) initialize card tokenization on first payment (initRecurring flag), and (2) charge subsequent subscription payments automatically without customer re-authentication. Required for SaaS/subscription billing models.","type":"boolean"},"customerCreditDefaultExpiration":{"nullable":true,"anyOf":[{"description":"Default expiration period for newly created customer account credit (e.g. from refunds or manual additions). Value in days (e.g. \"365\" for 1 year). Expired credit cannot be used for purchases. If not set, credit records are created without expiration. Applied automatically when credit is issued via storno refund or manual addition.","type":"string"},{"type":"null"}]},"storageUsed":{"description":"Current total storage usage in bytes (read-only). Calculated by summing all blob file sizes for this organisation. Updated automatically by the storage read model. Compare with tariff.storageMb to show usage percentage.","type":"number"},"insertedDate":{"description":"ISO 8601 timestamp when the organisation was created. Read-only metadata for display purposes.","type":"string"}},"required":["name","slug","storageSlug","description","emoji","companyRegistrationNumber","taxIdentificationNumber","vatPayer","accountingCountry","legalForm","disableExperiments","timezone","primaryLocale","defaultCurrency","supportPerson","vendor","tariff","logoUrl","printLogoUrl","primaryColor","secondaryColor","supportEmail","supportEmailMarketing","emailerFooter","emailerLayout","emailerSmtpHost","emailerSmtpPort","emailerSmtpUser","emailerMarketingSmtpHost","emailerMarketingSmtpPort","emailerMarketingSmtpUser","emailerNewsletterReturnUrl","smsSluzbaCzLogin","smsSluzbaCzDefaultSender","orderInternalNotificationEmails","orderNewInternalNotificationEnabled","orderRefundStrategy","orderAccountingMode","logInternalNotificationEmails","logReportDisabled","postDigestEnabled","postDigestIntervalDays","postDigestLastSentDate","postDigestSubject","postDigestIntroText","postDigestLocale","postDigestMaxPosts","paymentRecurringEnabled","customerCreditDefaultExpiration","storageUsed","insertedDate"]}}}}},"operationId":"getBffOrganisationProfile","tags":["Organisation"],"description":"Returns the complete organisation profile including basic info, company details, feature flags, timezone, locale, tariff limits, branding, email configuration, order settings, post digest settings, and payment settings. Combines data from the organisation table and configuration key-value store. Sensitive values (SMTP passwords, payment gateway secrets) are NOT included — use the /settings/env-variable-value endpoint to access those individually.","summary":"Get organisation profile"}},"/bff/organisation/update-profile":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrganisationUpdate-profile","tags":["Organisation"],"description":"Updates organisation profile fields. All fields are optional — only provided fields are updated. Direct organisation columns (name, vatPayer, etc.) are updated in the organisation table. Configuration values (SMTP, branding, etc.) are updated in the key-value configuration store. SMTP passwords are write-only and never returned in the profile GET endpoint. Clears the cache after successful update.","summary":"Update organisation profile","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"minLength":1,"maxLength":255,"description":"Organisation display name. Sanitized on save (disallowed chars removed, first letter capitalized). Changes propagate to email sender names, invoices, and all UI displays.","type":"string"},"description":{"nullable":true,"anyOf":[{"maxLength":5000,"description":"Free-form about text / profile description. Shown in admin org lists. Null to clear.","type":"string"},{"type":"null"}]},"emoji":{"nullable":true,"anyOf":[{"maxLength":16,"description":"Organisation emoji icon (e.g. \"🏢\"). Shown in org switcher, account detail, and terminal. Null to clear (system may auto-generate one via AI).","type":"string"},{"type":"null"}]},"companyRegistrationNumber":{"nullable":true,"anyOf":[{"maxLength":50,"description":"Company registration number (IČO). Printed on invoices/receipts. Used for ARES lookup and Firmy.cz feed.","type":"string"},{"type":"null"}]},"taxIdentificationNumber":{"nullable":true,"anyOf":[{"maxLength":50,"description":"Tax identification number (DIČ). Printed on invoices/receipts. Used in invoice exports for accounting.","type":"string"},{"type":"null"}]},"vatPayer":{"description":"VAT payer flag. When true, invoices include VAT rates on line items and fraud checks run against the unreliable payer list. When false, all invoice items use 0% VAT.","type":"boolean"},"accountingCountryId":{"nullable":true,"anyOf":[{"description":"Accounting / tax jurisdiction country (from GET /organisation/available-countries). Stored on cas__organisation.accounting_country_id and mirrored to the organisation's internal contact (shop__contact.company_country_id). Drives legal form picker scoping and country-specific VAT rules. Null clears the accounting country.","type":"number"},{"type":"null"}]},"legalFormId":{"nullable":true,"anyOf":[{"description":"Legal form ID (from GET /organisation/legal-forms?countryId=X). Must belong to accountingCountryId — the API rejects mismatched country/legalForm pairs. When provided without accountingCountryId, the accounting country is auto-aligned to the legal form's country. Mirrored to the internal contact. Null clears the legal form.","type":"number"},{"type":"null"}]},"disableExperiments":{"description":"When true, disables AI-powered features (issue routing, AI responses in ticket workflow).","type":"boolean"},"timezoneId":{"description":"Default timezone ID (from GET /organisation/timezones). Used to format dates in email notifications and calendar event times. If a calendar has no specific timezone, this org default is used.","type":"number"},"primaryLocaleId":{"description":"Primary locale ID (from GET /organisation/available-locales). Used as default language for: new contacts without a locale preference, email template rendering, and newsletter digest post selection.","type":"number"},"defaultCurrency":{"minLength":3,"maxLength":3,"description":"Requested default currency ISO 4217 code (e.g. \"CZK\"). Changing the default currency is NOT performed through this endpoint: if the provided code differs from the current default, the change is rejected, a warning is logged, and a technical notification is sent to the organisation asking them to contact BizKitHub technical support. Passing the current code is a no-op.","examples":["CZK"],"type":"string"},"supportPersonId":{"nullable":true,"anyOf":[{"description":"Internal member ID of the designated support contact (from GET /organisation/members). Informational field shown in the org profile. Null to unset.","type":"number"},{"type":"null"}]},"logoUrl":{"nullable":true,"anyOf":[{"description":"Logo URL displayed in the header of all email templates and in the account org list. If null, the logo section is hidden in emails. Can also be set via /bff/emailer/layout-link-logo-blob.","type":"string"},{"type":"null"}]},"printLogoUrl":{"nullable":true,"anyOf":[{"description":"Logo URL optimized for print (invoices, receipts, contracts, PDFs). If null, the standard logoUrl is used as fallback. Can also be set via /bff/organisation/link-print-logo-blob.","type":"string"},{"type":"null"}]},"primaryColor":{"nullable":true,"anyOf":[{"description":"Primary brand hex color (e.g. \"#1a2b3c\"). Must be a valid 3 or 6 digit hex with leading #. Invalid values are silently discarded (treated as null).","type":"string"},{"type":"null"}]},"secondaryColor":{"nullable":true,"anyOf":[{"description":"Secondary brand hex color (e.g. \"#f0f0f0\"). Must be a valid 3 or 6 digit hex with leading #. Invalid values are silently discarded (treated as null).","type":"string"},{"type":"null"}]},"supportEmail":{"nullable":true,"anyOf":[{"format":"email","description":"Default \"From\" address for all transactional emails (orders, calendar, accounts, system alerts). If null, falls back to the org internal contact email, then \"info@brj.cz\".","type":"string"},{"type":"null"}]},"supportEmailMarketing":{"nullable":true,"anyOf":[{"format":"email","description":"Override \"From\" address for newsletter/marketing emails only. If null, marketing emails use supportEmail. Useful for separating marketing sender reputation from transactional.","type":"string"},{"type":"null"}]},"emailerFooter":{"nullable":true,"anyOf":[{"description":"Custom HTML footer for all outgoing emails. Typically company info, legal disclaimers, unsubscribe links. If null, a default footer is auto-generated with the org name.","type":"string"},{"type":"null"}]},"emailerLayout":{"nullable":true,"anyOf":[{"description":"Custom Handlebars HTML email wrapper template. Variables: {{ htmlBody }}, {{ logoUrl }}, {{ footer }}. Conditionals: {{ if logoUrl }}...{{ /if }}. If null, uses the built-in default template.","type":"string"},{"type":"null"}]},"emailerSmtpHost":{"nullable":true,"anyOf":[{"description":"SMTP server hostname for transactional emails (e.g. \"smtp.gmail.com\"). Required to enable email sending. Validated during initial setup via test email.","type":"string"},{"type":"null"}]},"emailerSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port. \"587\" for STARTTLS (recommended), \"465\" for implicit SSL. Stored as string.","type":"string"},{"type":"null"}]},"emailerSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP auth username for transactional emails. Usually the email address itself.","type":"string"},{"type":"null"}]},"emailerSmtpPassword":{"nullable":true,"anyOf":[{"description":"SMTP auth password for transactional emails. Write-only — never returned in GET profile. Show as a password field with \"unchanged\" placeholder in the UI.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpHost":{"nullable":true,"anyOf":[{"description":"Separate SMTP hostname for marketing/newsletter bulk emails (e.g. SendGrid, Mailchimp SMTP). If null, marketing emails fall back to the transactional SMTP.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port for marketing server. \"587\" for STARTTLS, \"465\" for SSL.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP auth username for marketing email server.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPassword":{"nullable":true,"anyOf":[{"description":"SMTP auth password for marketing emails. Write-only — never returned in GET profile.","type":"string"},{"type":"null"}]},"emailerNewsletterReturnUrl":{"nullable":true,"anyOf":[{"description":"Redirect URL after newsletter subscription confirmation click. E.g. \"/newsletter-thanks\". If null, no redirect — API returns success response directly.","type":"string"},{"type":"null"}]},"smsSluzbaCzLogin":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account login (username). Together with `smsSluzbaCzPassword` it forms the credentials passed to the apixml30 gateway as query parameters. Both must be set for outgoing SMS to work.","type":"string"},{"type":"null"}]},"smsSluzbaCzPassword":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account password / API key. Write-only — never returned in GET profile. Show as a password field with \"unchanged\" placeholder in the UI.","type":"string"},{"type":"null"}]},"smsSluzbaCzDefaultSender":{"nullable":true,"anyOf":[{"description":"Optional default sender label (numeric msisdn or alphanumeric brand) attached to outgoing SMS when the caller does not pass one explicitly.","type":"string"},{"type":"null"}]},"orderInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated emails that receive BCC copies of all order status change emails. Internal team is notified when orders are created, paid, shipped, cancelled, etc.","type":"string"},{"type":"null"}]},"orderNewInternalNotificationEnabled":{"description":"Master switch for the BizKitHub-internal \"new order created\" notification e-mail. True = send from `info@bizkithub.com` to this organisation on every new order (throttled to 10 / UTC day). False (default) = disabled.","type":"boolean"},"orderRefundStrategy":{"nullable":true,"anyOf":[{"description":"Default refund handling on order storno. \"credit\" = return as store credit (default). \"cash\" = generate credit note + manual bank refund. \"none\" = no refund. Overridable per storno.","type":"string"},{"type":"null"}]},"orderAccountingMode":{"nullable":true,"anyOf":[{"description":"Credit note auto-generation on cash refunds. \"auto\"/\"always\" = auto-generate credit note linked to original invoice. \"never\" = skip, handle manually. Only applies when strategy is \"cash\" and order was paid.","type":"string"},{"type":"null"}]},"logInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated emails for system error alerts. Receive: (1) daily aggregated log reports with CRITICAL/ERROR/WARNING counts, (2) real-time individual critical error notifications. Separate from order notifications.","type":"string"},{"type":"null"}]},"logReportDisabled":{"description":"Opt-out flag for the daily log report e-mail. False = receive (default), true = suppress. Critical-level errors are always delivered regardless of this flag.","type":"boolean"},"postDigestEnabled":{"description":"Master switch for automatic newsletter digest. When enabled, a cron job periodically sends a digest of recent blog posts to all contacts with active newsletter subscriptions.","type":"boolean"},"postDigestIntervalDays":{"nullable":true,"anyOf":[{"minimum":1,"maximum":365,"description":"Days between digest sends. Cron checks: if (now - lastSent) >= interval, send. Default 14.","type":"number"},{"type":"null"}]},"postDigestSubject":{"nullable":true,"anyOf":[{"description":"Handlebars subject template. Variables: {{ postCount }}, {{ intervalDays }}. Default: \"Nové články ({{ postCount }})\" → \"Nové články (5)\".","type":"string"},{"type":"null"}]},"postDigestIntroText":{"nullable":true,"anyOf":[{"description":"Custom HTML intro text before the article list in the digest email. Rendered as raw HTML. Null to omit.","type":"string"},{"type":"null"}]},"postDigestLocale":{"nullable":true,"anyOf":[{"minLength":2,"maxLength":2,"description":"Override locale for post selection (e.g. \"cs\"). Only posts in this locale are included. Falls back to primary locale.","type":"string"},{"type":"null"}]},"postDigestMaxPosts":{"nullable":true,"anyOf":[{"minimum":1,"maximum":100,"description":"Max posts per digest. Starred posts first, then by recency. Default 20.","type":"number"},{"type":"null"}]},"paymentRecurringEnabled":{"description":"Enable Comgate recurring payment charging. When true, allows card tokenization on first payment and automatic subsequent charges without customer re-auth. Required for subscription billing.","type":"boolean"},"customerCreditDefaultExpiration":{"nullable":true,"anyOf":[{"description":"Default expiration for new customer credit records, in days (e.g. \"365\"). Applied when credit is issued via refund or manual addition. Expired credit cannot be used. Null = no expiration.","type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"minLength":1,"maxLength":255,"description":"Organisation display name. Sanitized on save (disallowed chars removed, first letter capitalized). Changes propagate to email sender names, invoices, and all UI displays.","type":"string"},"description":{"nullable":true,"anyOf":[{"maxLength":5000,"description":"Free-form about text / profile description. Shown in admin org lists. Null to clear.","type":"string"},{"type":"null"}]},"emoji":{"nullable":true,"anyOf":[{"maxLength":16,"description":"Organisation emoji icon (e.g. \"🏢\"). Shown in org switcher, account detail, and terminal. Null to clear (system may auto-generate one via AI).","type":"string"},{"type":"null"}]},"companyRegistrationNumber":{"nullable":true,"anyOf":[{"maxLength":50,"description":"Company registration number (IČO). Printed on invoices/receipts. Used for ARES lookup and Firmy.cz feed.","type":"string"},{"type":"null"}]},"taxIdentificationNumber":{"nullable":true,"anyOf":[{"maxLength":50,"description":"Tax identification number (DIČ). Printed on invoices/receipts. Used in invoice exports for accounting.","type":"string"},{"type":"null"}]},"vatPayer":{"description":"VAT payer flag. When true, invoices include VAT rates on line items and fraud checks run against the unreliable payer list. When false, all invoice items use 0% VAT.","type":"boolean"},"accountingCountryId":{"nullable":true,"anyOf":[{"description":"Accounting / tax jurisdiction country (from GET /organisation/available-countries). Stored on cas__organisation.accounting_country_id and mirrored to the organisation's internal contact (shop__contact.company_country_id). Drives legal form picker scoping and country-specific VAT rules. Null clears the accounting country.","type":"number"},{"type":"null"}]},"legalFormId":{"nullable":true,"anyOf":[{"description":"Legal form ID (from GET /organisation/legal-forms?countryId=X). Must belong to accountingCountryId — the API rejects mismatched country/legalForm pairs. When provided without accountingCountryId, the accounting country is auto-aligned to the legal form's country. Mirrored to the internal contact. Null clears the legal form.","type":"number"},{"type":"null"}]},"disableExperiments":{"description":"When true, disables AI-powered features (issue routing, AI responses in ticket workflow).","type":"boolean"},"timezoneId":{"description":"Default timezone ID (from GET /organisation/timezones). Used to format dates in email notifications and calendar event times. If a calendar has no specific timezone, this org default is used.","type":"number"},"primaryLocaleId":{"description":"Primary locale ID (from GET /organisation/available-locales). Used as default language for: new contacts without a locale preference, email template rendering, and newsletter digest post selection.","type":"number"},"defaultCurrency":{"minLength":3,"maxLength":3,"description":"Requested default currency ISO 4217 code (e.g. \"CZK\"). Changing the default currency is NOT performed through this endpoint: if the provided code differs from the current default, the change is rejected, a warning is logged, and a technical notification is sent to the organisation asking them to contact BizKitHub technical support. Passing the current code is a no-op.","examples":["CZK"],"type":"string"},"supportPersonId":{"nullable":true,"anyOf":[{"description":"Internal member ID of the designated support contact (from GET /organisation/members). Informational field shown in the org profile. Null to unset.","type":"number"},{"type":"null"}]},"logoUrl":{"nullable":true,"anyOf":[{"description":"Logo URL displayed in the header of all email templates and in the account org list. If null, the logo section is hidden in emails. Can also be set via /bff/emailer/layout-link-logo-blob.","type":"string"},{"type":"null"}]},"printLogoUrl":{"nullable":true,"anyOf":[{"description":"Logo URL optimized for print (invoices, receipts, contracts, PDFs). If null, the standard logoUrl is used as fallback. Can also be set via /bff/organisation/link-print-logo-blob.","type":"string"},{"type":"null"}]},"primaryColor":{"nullable":true,"anyOf":[{"description":"Primary brand hex color (e.g. \"#1a2b3c\"). Must be a valid 3 or 6 digit hex with leading #. Invalid values are silently discarded (treated as null).","type":"string"},{"type":"null"}]},"secondaryColor":{"nullable":true,"anyOf":[{"description":"Secondary brand hex color (e.g. \"#f0f0f0\"). Must be a valid 3 or 6 digit hex with leading #. Invalid values are silently discarded (treated as null).","type":"string"},{"type":"null"}]},"supportEmail":{"nullable":true,"anyOf":[{"format":"email","description":"Default \"From\" address for all transactional emails (orders, calendar, accounts, system alerts). If null, falls back to the org internal contact email, then \"info@brj.cz\".","type":"string"},{"type":"null"}]},"supportEmailMarketing":{"nullable":true,"anyOf":[{"format":"email","description":"Override \"From\" address for newsletter/marketing emails only. If null, marketing emails use supportEmail. Useful for separating marketing sender reputation from transactional.","type":"string"},{"type":"null"}]},"emailerFooter":{"nullable":true,"anyOf":[{"description":"Custom HTML footer for all outgoing emails. Typically company info, legal disclaimers, unsubscribe links. If null, a default footer is auto-generated with the org name.","type":"string"},{"type":"null"}]},"emailerLayout":{"nullable":true,"anyOf":[{"description":"Custom Handlebars HTML email wrapper template. Variables: {{ htmlBody }}, {{ logoUrl }}, {{ footer }}. Conditionals: {{ if logoUrl }}...{{ /if }}. If null, uses the built-in default template.","type":"string"},{"type":"null"}]},"emailerSmtpHost":{"nullable":true,"anyOf":[{"description":"SMTP server hostname for transactional emails (e.g. \"smtp.gmail.com\"). Required to enable email sending. Validated during initial setup via test email.","type":"string"},{"type":"null"}]},"emailerSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port. \"587\" for STARTTLS (recommended), \"465\" for implicit SSL. Stored as string.","type":"string"},{"type":"null"}]},"emailerSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP auth username for transactional emails. Usually the email address itself.","type":"string"},{"type":"null"}]},"emailerSmtpPassword":{"nullable":true,"anyOf":[{"description":"SMTP auth password for transactional emails. Write-only — never returned in GET profile. Show as a password field with \"unchanged\" placeholder in the UI.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpHost":{"nullable":true,"anyOf":[{"description":"Separate SMTP hostname for marketing/newsletter bulk emails (e.g. SendGrid, Mailchimp SMTP). If null, marketing emails fall back to the transactional SMTP.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port for marketing server. \"587\" for STARTTLS, \"465\" for SSL.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP auth username for marketing email server.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPassword":{"nullable":true,"anyOf":[{"description":"SMTP auth password for marketing emails. Write-only — never returned in GET profile.","type":"string"},{"type":"null"}]},"emailerNewsletterReturnUrl":{"nullable":true,"anyOf":[{"description":"Redirect URL after newsletter subscription confirmation click. E.g. \"/newsletter-thanks\". If null, no redirect — API returns success response directly.","type":"string"},{"type":"null"}]},"smsSluzbaCzLogin":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account login (username). Together with `smsSluzbaCzPassword` it forms the credentials passed to the apixml30 gateway as query parameters. Both must be set for outgoing SMS to work.","type":"string"},{"type":"null"}]},"smsSluzbaCzPassword":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account password / API key. Write-only — never returned in GET profile. Show as a password field with \"unchanged\" placeholder in the UI.","type":"string"},{"type":"null"}]},"smsSluzbaCzDefaultSender":{"nullable":true,"anyOf":[{"description":"Optional default sender label (numeric msisdn or alphanumeric brand) attached to outgoing SMS when the caller does not pass one explicitly.","type":"string"},{"type":"null"}]},"orderInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated emails that receive BCC copies of all order status change emails. Internal team is notified when orders are created, paid, shipped, cancelled, etc.","type":"string"},{"type":"null"}]},"orderNewInternalNotificationEnabled":{"description":"Master switch for the BizKitHub-internal \"new order created\" notification e-mail. True = send from `info@bizkithub.com` to this organisation on every new order (throttled to 10 / UTC day). False (default) = disabled.","type":"boolean"},"orderRefundStrategy":{"nullable":true,"anyOf":[{"description":"Default refund handling on order storno. \"credit\" = return as store credit (default). \"cash\" = generate credit note + manual bank refund. \"none\" = no refund. Overridable per storno.","type":"string"},{"type":"null"}]},"orderAccountingMode":{"nullable":true,"anyOf":[{"description":"Credit note auto-generation on cash refunds. \"auto\"/\"always\" = auto-generate credit note linked to original invoice. \"never\" = skip, handle manually. Only applies when strategy is \"cash\" and order was paid.","type":"string"},{"type":"null"}]},"logInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated emails for system error alerts. Receive: (1) daily aggregated log reports with CRITICAL/ERROR/WARNING counts, (2) real-time individual critical error notifications. Separate from order notifications.","type":"string"},{"type":"null"}]},"logReportDisabled":{"description":"Opt-out flag for the daily log report e-mail. False = receive (default), true = suppress. Critical-level errors are always delivered regardless of this flag.","type":"boolean"},"postDigestEnabled":{"description":"Master switch for automatic newsletter digest. When enabled, a cron job periodically sends a digest of recent blog posts to all contacts with active newsletter subscriptions.","type":"boolean"},"postDigestIntervalDays":{"nullable":true,"anyOf":[{"minimum":1,"maximum":365,"description":"Days between digest sends. Cron checks: if (now - lastSent) >= interval, send. Default 14.","type":"number"},{"type":"null"}]},"postDigestSubject":{"nullable":true,"anyOf":[{"description":"Handlebars subject template. Variables: {{ postCount }}, {{ intervalDays }}. Default: \"Nové články ({{ postCount }})\" → \"Nové články (5)\".","type":"string"},{"type":"null"}]},"postDigestIntroText":{"nullable":true,"anyOf":[{"description":"Custom HTML intro text before the article list in the digest email. Rendered as raw HTML. Null to omit.","type":"string"},{"type":"null"}]},"postDigestLocale":{"nullable":true,"anyOf":[{"minLength":2,"maxLength":2,"description":"Override locale for post selection (e.g. \"cs\"). Only posts in this locale are included. Falls back to primary locale.","type":"string"},{"type":"null"}]},"postDigestMaxPosts":{"nullable":true,"anyOf":[{"minimum":1,"maximum":100,"description":"Max posts per digest. Starred posts first, then by recency. Default 20.","type":"number"},{"type":"null"}]},"paymentRecurringEnabled":{"description":"Enable Comgate recurring payment charging. When true, allows card tokenization on first payment and automatic subsequent charges without customer re-auth. Required for subscription billing.","type":"boolean"},"customerCreditDefaultExpiration":{"nullable":true,"anyOf":[{"description":"Default expiration for new customer credit records, in days (e.g. \"365\"). Applied when credit is issued via refund or manual addition. Expired credit cannot be used. Null = no expiration.","type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","properties":{"name":{"minLength":1,"maxLength":255,"description":"Organisation display name. Sanitized on save (disallowed chars removed, first letter capitalized). Changes propagate to email sender names, invoices, and all UI displays.","type":"string"},"description":{"nullable":true,"anyOf":[{"maxLength":5000,"description":"Free-form about text / profile description. Shown in admin org lists. Null to clear.","type":"string"},{"type":"null"}]},"emoji":{"nullable":true,"anyOf":[{"maxLength":16,"description":"Organisation emoji icon (e.g. \"🏢\"). Shown in org switcher, account detail, and terminal. Null to clear (system may auto-generate one via AI).","type":"string"},{"type":"null"}]},"companyRegistrationNumber":{"nullable":true,"anyOf":[{"maxLength":50,"description":"Company registration number (IČO). Printed on invoices/receipts. Used for ARES lookup and Firmy.cz feed.","type":"string"},{"type":"null"}]},"taxIdentificationNumber":{"nullable":true,"anyOf":[{"maxLength":50,"description":"Tax identification number (DIČ). Printed on invoices/receipts. Used in invoice exports for accounting.","type":"string"},{"type":"null"}]},"vatPayer":{"description":"VAT payer flag. When true, invoices include VAT rates on line items and fraud checks run against the unreliable payer list. When false, all invoice items use 0% VAT.","type":"boolean"},"accountingCountryId":{"nullable":true,"anyOf":[{"description":"Accounting / tax jurisdiction country (from GET /organisation/available-countries). Stored on cas__organisation.accounting_country_id and mirrored to the organisation's internal contact (shop__contact.company_country_id). Drives legal form picker scoping and country-specific VAT rules. Null clears the accounting country.","type":"number"},{"type":"null"}]},"legalFormId":{"nullable":true,"anyOf":[{"description":"Legal form ID (from GET /organisation/legal-forms?countryId=X). Must belong to accountingCountryId — the API rejects mismatched country/legalForm pairs. When provided without accountingCountryId, the accounting country is auto-aligned to the legal form's country. Mirrored to the internal contact. Null clears the legal form.","type":"number"},{"type":"null"}]},"disableExperiments":{"description":"When true, disables AI-powered features (issue routing, AI responses in ticket workflow).","type":"boolean"},"timezoneId":{"description":"Default timezone ID (from GET /organisation/timezones). Used to format dates in email notifications and calendar event times. If a calendar has no specific timezone, this org default is used.","type":"number"},"primaryLocaleId":{"description":"Primary locale ID (from GET /organisation/available-locales). Used as default language for: new contacts without a locale preference, email template rendering, and newsletter digest post selection.","type":"number"},"defaultCurrency":{"minLength":3,"maxLength":3,"description":"Requested default currency ISO 4217 code (e.g. \"CZK\"). Changing the default currency is NOT performed through this endpoint: if the provided code differs from the current default, the change is rejected, a warning is logged, and a technical notification is sent to the organisation asking them to contact BizKitHub technical support. Passing the current code is a no-op.","examples":["CZK"],"type":"string"},"supportPersonId":{"nullable":true,"anyOf":[{"description":"Internal member ID of the designated support contact (from GET /organisation/members). Informational field shown in the org profile. Null to unset.","type":"number"},{"type":"null"}]},"logoUrl":{"nullable":true,"anyOf":[{"description":"Logo URL displayed in the header of all email templates and in the account org list. If null, the logo section is hidden in emails. Can also be set via /bff/emailer/layout-link-logo-blob.","type":"string"},{"type":"null"}]},"printLogoUrl":{"nullable":true,"anyOf":[{"description":"Logo URL optimized for print (invoices, receipts, contracts, PDFs). If null, the standard logoUrl is used as fallback. Can also be set via /bff/organisation/link-print-logo-blob.","type":"string"},{"type":"null"}]},"primaryColor":{"nullable":true,"anyOf":[{"description":"Primary brand hex color (e.g. \"#1a2b3c\"). Must be a valid 3 or 6 digit hex with leading #. Invalid values are silently discarded (treated as null).","type":"string"},{"type":"null"}]},"secondaryColor":{"nullable":true,"anyOf":[{"description":"Secondary brand hex color (e.g. \"#f0f0f0\"). Must be a valid 3 or 6 digit hex with leading #. Invalid values are silently discarded (treated as null).","type":"string"},{"type":"null"}]},"supportEmail":{"nullable":true,"anyOf":[{"format":"email","description":"Default \"From\" address for all transactional emails (orders, calendar, accounts, system alerts). If null, falls back to the org internal contact email, then \"info@brj.cz\".","type":"string"},{"type":"null"}]},"supportEmailMarketing":{"nullable":true,"anyOf":[{"format":"email","description":"Override \"From\" address for newsletter/marketing emails only. If null, marketing emails use supportEmail. Useful for separating marketing sender reputation from transactional.","type":"string"},{"type":"null"}]},"emailerFooter":{"nullable":true,"anyOf":[{"description":"Custom HTML footer for all outgoing emails. Typically company info, legal disclaimers, unsubscribe links. If null, a default footer is auto-generated with the org name.","type":"string"},{"type":"null"}]},"emailerLayout":{"nullable":true,"anyOf":[{"description":"Custom Handlebars HTML email wrapper template. Variables: {{ htmlBody }}, {{ logoUrl }}, {{ footer }}. Conditionals: {{ if logoUrl }}...{{ /if }}. If null, uses the built-in default template.","type":"string"},{"type":"null"}]},"emailerSmtpHost":{"nullable":true,"anyOf":[{"description":"SMTP server hostname for transactional emails (e.g. \"smtp.gmail.com\"). Required to enable email sending. Validated during initial setup via test email.","type":"string"},{"type":"null"}]},"emailerSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port. \"587\" for STARTTLS (recommended), \"465\" for implicit SSL. Stored as string.","type":"string"},{"type":"null"}]},"emailerSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP auth username for transactional emails. Usually the email address itself.","type":"string"},{"type":"null"}]},"emailerSmtpPassword":{"nullable":true,"anyOf":[{"description":"SMTP auth password for transactional emails. Write-only — never returned in GET profile. Show as a password field with \"unchanged\" placeholder in the UI.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpHost":{"nullable":true,"anyOf":[{"description":"Separate SMTP hostname for marketing/newsletter bulk emails (e.g. SendGrid, Mailchimp SMTP). If null, marketing emails fall back to the transactional SMTP.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPort":{"nullable":true,"anyOf":[{"description":"SMTP port for marketing server. \"587\" for STARTTLS, \"465\" for SSL.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpUser":{"nullable":true,"anyOf":[{"description":"SMTP auth username for marketing email server.","type":"string"},{"type":"null"}]},"emailerMarketingSmtpPassword":{"nullable":true,"anyOf":[{"description":"SMTP auth password for marketing emails. Write-only — never returned in GET profile.","type":"string"},{"type":"null"}]},"emailerNewsletterReturnUrl":{"nullable":true,"anyOf":[{"description":"Redirect URL after newsletter subscription confirmation click. E.g. \"/newsletter-thanks\". If null, no redirect — API returns success response directly.","type":"string"},{"type":"null"}]},"smsSluzbaCzLogin":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account login (username). Together with `smsSluzbaCzPassword` it forms the credentials passed to the apixml30 gateway as query parameters. Both must be set for outgoing SMS to work.","type":"string"},{"type":"null"}]},"smsSluzbaCzPassword":{"nullable":true,"anyOf":[{"description":"sms-sluzba.cz account password / API key. Write-only — never returned in GET profile. Show as a password field with \"unchanged\" placeholder in the UI.","type":"string"},{"type":"null"}]},"smsSluzbaCzDefaultSender":{"nullable":true,"anyOf":[{"description":"Optional default sender label (numeric msisdn or alphanumeric brand) attached to outgoing SMS when the caller does not pass one explicitly.","type":"string"},{"type":"null"}]},"orderInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated emails that receive BCC copies of all order status change emails. Internal team is notified when orders are created, paid, shipped, cancelled, etc.","type":"string"},{"type":"null"}]},"orderNewInternalNotificationEnabled":{"description":"Master switch for the BizKitHub-internal \"new order created\" notification e-mail. True = send from `info@bizkithub.com` to this organisation on every new order (throttled to 10 / UTC day). False (default) = disabled.","type":"boolean"},"orderRefundStrategy":{"nullable":true,"anyOf":[{"description":"Default refund handling on order storno. \"credit\" = return as store credit (default). \"cash\" = generate credit note + manual bank refund. \"none\" = no refund. Overridable per storno.","type":"string"},{"type":"null"}]},"orderAccountingMode":{"nullable":true,"anyOf":[{"description":"Credit note auto-generation on cash refunds. \"auto\"/\"always\" = auto-generate credit note linked to original invoice. \"never\" = skip, handle manually. Only applies when strategy is \"cash\" and order was paid.","type":"string"},{"type":"null"}]},"logInternalNotificationEmails":{"nullable":true,"anyOf":[{"description":"Comma-separated emails for system error alerts. Receive: (1) daily aggregated log reports with CRITICAL/ERROR/WARNING counts, (2) real-time individual critical error notifications. Separate from order notifications.","type":"string"},{"type":"null"}]},"logReportDisabled":{"description":"Opt-out flag for the daily log report e-mail. False = receive (default), true = suppress. Critical-level errors are always delivered regardless of this flag.","type":"boolean"},"postDigestEnabled":{"description":"Master switch for automatic newsletter digest. When enabled, a cron job periodically sends a digest of recent blog posts to all contacts with active newsletter subscriptions.","type":"boolean"},"postDigestIntervalDays":{"nullable":true,"anyOf":[{"minimum":1,"maximum":365,"description":"Days between digest sends. Cron checks: if (now - lastSent) >= interval, send. Default 14.","type":"number"},{"type":"null"}]},"postDigestSubject":{"nullable":true,"anyOf":[{"description":"Handlebars subject template. Variables: {{ postCount }}, {{ intervalDays }}. Default: \"Nové články ({{ postCount }})\" → \"Nové články (5)\".","type":"string"},{"type":"null"}]},"postDigestIntroText":{"nullable":true,"anyOf":[{"description":"Custom HTML intro text before the article list in the digest email. Rendered as raw HTML. Null to omit.","type":"string"},{"type":"null"}]},"postDigestLocale":{"nullable":true,"anyOf":[{"minLength":2,"maxLength":2,"description":"Override locale for post selection (e.g. \"cs\"). Only posts in this locale are included. Falls back to primary locale.","type":"string"},{"type":"null"}]},"postDigestMaxPosts":{"nullable":true,"anyOf":[{"minimum":1,"maximum":100,"description":"Max posts per digest. Starred posts first, then by recency. Default 20.","type":"number"},{"type":"null"}]},"paymentRecurringEnabled":{"description":"Enable Comgate recurring payment charging. When true, allows card tokenization on first payment and automatic subsequent charges without customer re-auth. Required for subscription billing.","type":"boolean"},"customerCreditDefaultExpiration":{"nullable":true,"anyOf":[{"description":"Default expiration for new customer credit records, in days (e.g. \"365\"). Applied when credit is issued via refund or manual addition. Expired credit cannot be used. Null = no expiration.","type":"string"},{"type":"null"}]}}}}}}}},"/bff/organisation/timezones":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"All available timezones ordered by GMT offset.","type":"array","items":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"description":"Internal timezone ID. Use this value when setting timezoneId in update-profile.","type":"number"},"timezone":{"description":"IANA timezone identifier. Used to format dates in email notifications and calendar events.","examples":["Europe/Prague"],"type":"string"},"gmt":{"description":"GMT offset string for display purposes.","examples":["+01:00"],"type":"string"},"label":{"description":"Human-readable timezone label for picker display.","examples":["Central European Time - Prague"],"type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"All available timezones ordered by GMT offset.","type":"array","items":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"description":"Internal timezone ID. Use this value when setting timezoneId in update-profile.","type":"number"},"timezone":{"description":"IANA timezone identifier. Used to format dates in email notifications and calendar events.","examples":["Europe/Prague"],"type":"string"},"gmt":{"description":"GMT offset string for display purposes.","examples":["+01:00"],"type":"string"},"label":{"description":"Human-readable timezone label for picker display.","examples":["Central European Time - Prague"],"type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"All available timezones ordered by GMT offset.","type":"array","items":{"type":"object","required":["id","timezone","gmt","label"],"properties":{"id":{"description":"Internal timezone ID. Use this value when setting timezoneId in update-profile.","type":"number"},"timezone":{"description":"IANA timezone identifier. Used to format dates in email notifications and calendar events.","examples":["Europe/Prague"],"type":"string"},"gmt":{"description":"GMT offset string for display purposes.","examples":["+01:00"],"type":"string"},"label":{"description":"Human-readable timezone label for picker display.","examples":["Central European Time - Prague"],"type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffOrganisationTimezones","tags":["Organisation"],"description":"Returns all available timezones in the system. Use this to populate a timezone picker when configuring the organisation default timezone.","summary":"List available timezones"}},"/bff/organisation/available-locales":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"All system locales ordered by position.","type":"array","items":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Internal locale ID. Use this value when setting primaryLocaleId in update-profile.","type":"number"},"locale":{"description":"ISO 639-1 locale code. Determines default language for contacts, emails, and content selection.","examples":["cs"],"type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"All system locales ordered by position.","type":"array","items":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Internal locale ID. Use this value when setting primaryLocaleId in update-profile.","type":"number"},"locale":{"description":"ISO 639-1 locale code. Determines default language for contacts, emails, and content selection.","examples":["cs"],"type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"All system locales ordered by position.","type":"array","items":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Internal locale ID. Use this value when setting primaryLocaleId in update-profile.","type":"number"},"locale":{"description":"ISO 639-1 locale code. Determines default language for contacts, emails, and content selection.","examples":["cs"],"type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffOrganisationAvailable-locales","tags":["Organisation"],"description":"Returns all locales available in the system. Use this to populate a locale picker when configuring organisation locales or primary locale.","summary":"List all system locales"}},"/bff/organisation/available-currencies":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"All system currencies ordered by ISO code.","type":"array","items":{"type":"object","required":["id","code","symbol"],"properties":{"id":{"description":"Internal currency ID.","type":"number"},"code":{"description":"ISO 4217 currency code. Use this value to reference the currency across the API.","examples":["CZK"],"type":"string"},"symbol":{"description":"Display symbol of the currency (up to 3 characters).","examples":["Kč"],"type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"All system currencies ordered by ISO code.","type":"array","items":{"type":"object","required":["id","code","symbol"],"properties":{"id":{"description":"Internal currency ID.","type":"number"},"code":{"description":"ISO 4217 currency code. Use this value to reference the currency across the API.","examples":["CZK"],"type":"string"},"symbol":{"description":"Display symbol of the currency (up to 3 characters).","examples":["Kč"],"type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"All system currencies ordered by ISO code.","type":"array","items":{"type":"object","required":["id","code","symbol"],"properties":{"id":{"description":"Internal currency ID.","type":"number"},"code":{"description":"ISO 4217 currency code. Use this value to reference the currency across the API.","examples":["CZK"],"type":"string"},"symbol":{"description":"Display symbol of the currency (up to 3 characters).","examples":["Kč"],"type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffOrganisationAvailable-currencies","tags":["Organisation"],"description":"Returns all currencies available in the system with their ISO 4217 code and display symbol. Use this to populate a currency picker when configuring the organisation default currency.","summary":"List all system currencies"}},"/bff/organisation/available-countries":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"All countries ordered alphabetically by name.","type":"array","items":{"type":"object","required":["id","code","isoCode","name","isEu"],"properties":{"id":{"description":"Internal country ID. Use as accountingCountryId / companyCountryId.","type":"number"},"code":{"description":"ISO 3166-1 alpha-2 code.","examples":["CZ"],"type":"string"},"isoCode":{"description":"ISO 3166-1 alpha-3 code.","examples":["CZE"],"type":"string"},"name":{"description":"Country display name.","type":"string"},"isEu":{"description":"Whether this country is an EU member state (drives reverse-charge VAT logic).","type":"boolean"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"All countries ordered alphabetically by name.","type":"array","items":{"type":"object","required":["id","code","isoCode","name","isEu"],"properties":{"id":{"description":"Internal country ID. Use as accountingCountryId / companyCountryId.","type":"number"},"code":{"description":"ISO 3166-1 alpha-2 code.","examples":["CZ"],"type":"string"},"isoCode":{"description":"ISO 3166-1 alpha-3 code.","examples":["CZE"],"type":"string"},"name":{"description":"Country display name.","type":"string"},"isEu":{"description":"Whether this country is an EU member state (drives reverse-charge VAT logic).","type":"boolean"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"All countries ordered alphabetically by name.","type":"array","items":{"type":"object","required":["id","code","isoCode","name","isEu"],"properties":{"id":{"description":"Internal country ID. Use as accountingCountryId / companyCountryId.","type":"number"},"code":{"description":"ISO 3166-1 alpha-2 code.","examples":["CZ"],"type":"string"},"isoCode":{"description":"ISO 3166-1 alpha-3 code.","examples":["CZE"],"type":"string"},"name":{"description":"Country display name.","type":"string"},"isEu":{"description":"Whether this country is an EU member state (drives reverse-charge VAT logic).","type":"boolean"}}}}},"required":["items"]}}}}},"operationId":"getBffOrganisationAvailable-countries","tags":["Organisation"],"description":"Returns all countries available in the system. Use this to populate a country picker for accountingCountryId in update-profile, contact billing country, or address forms.","summary":"List all system countries"}},"/bff/organisation/legal-forms":{"get":{"parameters":[{"description":"Filter legal forms by country ID (from GET /organisation/available-countries). Strongly recommended — without it the response includes legal forms for all countries. Query params are always strings in Elysia; the value is parsed as a number server-side.","examples":["158"],"schema":{"type":"string"},"in":"query","name":"countryId","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Active legal forms ordered by country, then position.","type":"array","items":{"type":"object","required":["id","countryId","countryCode","code","slug","name","isLegalEntity","vatRegistrationDefault"],"properties":{"id":{"description":"Legal form ID. Use as legalFormId in update-profile / contact detail-edit.","type":"number"},"countryId":{"description":"Country this legal form belongs to.","type":"number"},"countryCode":{"description":"ISO 3166-1 alpha-2 code of the country.","examples":["CZ"],"type":"string"},"code":{"description":"Country-specific code (e.g. ARES \"pravniForma\").","examples":["112"],"type":"string"},"slug":{"description":"Cross-country slug (osvc/sro/as/vos/ks/druzstvo/po/fo_podnikatel/neziskovka...).","examples":["sro"],"type":"string"},"name":{"description":"Localized human-readable name.","type":"string"},"isLegalEntity":{"description":"true = legal entity (PO), false = natural person (FO). Drives accounting/invoice logic.","type":"boolean"},"vatRegistrationDefault":{"description":"Whether this legal form is typically a VAT payer by default (UI hint only — not auto-applied).","type":"boolean"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Active legal forms ordered by country, then position.","type":"array","items":{"type":"object","required":["id","countryId","countryCode","code","slug","name","isLegalEntity","vatRegistrationDefault"],"properties":{"id":{"description":"Legal form ID. Use as legalFormId in update-profile / contact detail-edit.","type":"number"},"countryId":{"description":"Country this legal form belongs to.","type":"number"},"countryCode":{"description":"ISO 3166-1 alpha-2 code of the country.","examples":["CZ"],"type":"string"},"code":{"description":"Country-specific code (e.g. ARES \"pravniForma\").","examples":["112"],"type":"string"},"slug":{"description":"Cross-country slug (osvc/sro/as/vos/ks/druzstvo/po/fo_podnikatel/neziskovka...).","examples":["sro"],"type":"string"},"name":{"description":"Localized human-readable name.","type":"string"},"isLegalEntity":{"description":"true = legal entity (PO), false = natural person (FO). Drives accounting/invoice logic.","type":"boolean"},"vatRegistrationDefault":{"description":"Whether this legal form is typically a VAT payer by default (UI hint only — not auto-applied).","type":"boolean"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Active legal forms ordered by country, then position.","type":"array","items":{"type":"object","required":["id","countryId","countryCode","code","slug","name","isLegalEntity","vatRegistrationDefault"],"properties":{"id":{"description":"Legal form ID. Use as legalFormId in update-profile / contact detail-edit.","type":"number"},"countryId":{"description":"Country this legal form belongs to.","type":"number"},"countryCode":{"description":"ISO 3166-1 alpha-2 code of the country.","examples":["CZ"],"type":"string"},"code":{"description":"Country-specific code (e.g. ARES \"pravniForma\").","examples":["112"],"type":"string"},"slug":{"description":"Cross-country slug (osvc/sro/as/vos/ks/druzstvo/po/fo_podnikatel/neziskovka...).","examples":["sro"],"type":"string"},"name":{"description":"Localized human-readable name.","type":"string"},"isLegalEntity":{"description":"true = legal entity (PO), false = natural person (FO). Drives accounting/invoice logic.","type":"boolean"},"vatRegistrationDefault":{"description":"Whether this legal form is typically a VAT payer by default (UI hint only — not auto-applied).","type":"boolean"}}}}},"required":["items"]}}}}},"operationId":"getBffOrganisationLegal-forms","tags":["Organisation"],"description":"Returns active legal forms from core__legal_form. Use to populate the legal form picker on the organisation profile and on contact detail. Pair with the contact/organisation accounting country.","summary":"List legal forms (optionally filtered by country)"}},"/bff/organisation/locales":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Configured locales ordered by position.","type":"array","items":{"type":"object","required":["locale","isDefault","position"],"properties":{"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"isDefault":{"description":"Whether this is the default locale for the organisation.","type":"boolean"},"position":{"description":"Display order position (0-based).","type":"number"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Configured locales ordered by position.","type":"array","items":{"type":"object","required":["locale","isDefault","position"],"properties":{"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"isDefault":{"description":"Whether this is the default locale for the organisation.","type":"boolean"},"position":{"description":"Display order position (0-based).","type":"number"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Configured locales ordered by position.","type":"array","items":{"type":"object","required":["locale","isDefault","position"],"properties":{"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"isDefault":{"description":"Whether this is the default locale for the organisation.","type":"boolean"},"position":{"description":"Display order position (0-based).","type":"number"}}}}},"required":["items"]}}}}},"operationId":"getBffOrganisationLocales","tags":["Organisation"],"description":"Returns the list of locales configured for the current organisation. Each locale includes its code, whether it is the default, and its display position.","summary":"Get organisation locales"}},"/bff/organisation/save-locales":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the locales were saved successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the locales were saved successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the locales were saved successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffOrganisationSave-locales","tags":["Organisation"],"description":"Replaces the entire locale configuration for the organisation. The array order determines position (0-based). Exactly one locale must be marked as default. At least one locale is required. Clears the locale cache after saving.","summary":"Save organisation locales","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["locales"],"properties":{"locales":{"minItems":1,"description":"New locale configuration. Replaces all existing locales for the organisation.","type":"array","items":{"type":"object","required":["locale","isDefault"],"properties":{"locale":{"minLength":2,"maxLength":2,"description":"Locale code (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"isDefault":{"description":"Whether this locale is the default. Exactly one must be true.","type":"boolean"}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["locales"],"properties":{"locales":{"minItems":1,"description":"New locale configuration. Replaces all existing locales for the organisation.","type":"array","items":{"type":"object","required":["locale","isDefault"],"properties":{"locale":{"minLength":2,"maxLength":2,"description":"Locale code (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"isDefault":{"description":"Whether this locale is the default. Exactly one must be true.","type":"boolean"}}}}}}},"text/plain":{"schema":{"type":"object","required":["locales"],"properties":{"locales":{"minItems":1,"description":"New locale configuration. Replaces all existing locales for the organisation.","type":"array","items":{"type":"object","required":["locale","isDefault"],"properties":{"locale":{"minLength":2,"maxLength":2,"description":"Locale code (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"isDefault":{"description":"Whether this locale is the default. Exactly one must be true.","type":"boolean"}}}}}}}}}}},"/bff/organisation/members":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Non-blocked organisation members.","type":"array","items":{"type":"object","required":["id","fullName"],"properties":{"id":{"description":"Internal member ID (use as supportPersonId).","type":"number"},"fullName":{"description":"Full name of the member.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Non-blocked organisation members.","type":"array","items":{"type":"object","required":["id","fullName"],"properties":{"id":{"description":"Internal member ID (use as supportPersonId).","type":"number"},"fullName":{"description":"Full name of the member.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Non-blocked organisation members.","type":"array","items":{"type":"object","required":["id","fullName"],"properties":{"id":{"description":"Internal member ID (use as supportPersonId).","type":"number"},"fullName":{"description":"Full name of the member.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffOrganisationMembers","tags":["Organisation"],"description":"Returns a lightweight list of non-blocked organisation members with internal member ID and full name. Use this for pickers (e.g. support person selection in organisation profile). The returned ID is the internal member ID used by supportPersonId in update-profile.","summary":"List organisation members (simple)"}},"/bff/organisation/vat-rates":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"rates":{"description":"Available VAT rates.","type":"array","items":{"type":"object","required":["rate"],"properties":{"rate":{"description":"VAT rate percentage (e.g. 21, 12, 0).","type":"number"}}}}},"required":["rates"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"rates":{"description":"Available VAT rates.","type":"array","items":{"type":"object","required":["rate"],"properties":{"rate":{"description":"VAT rate percentage (e.g. 21, 12, 0).","type":"number"}}}}},"required":["rates"]}},"text/plain":{"schema":{"type":"object","properties":{"rates":{"description":"Available VAT rates.","type":"array","items":{"type":"object","required":["rate"],"properties":{"rate":{"description":"VAT rate percentage (e.g. 21, 12, 0).","type":"number"}}}}},"required":["rates"]}}}}},"operationId":"getBffOrganisationVat-rates","tags":["Organisation"],"description":"Returns the list of available VAT rates for the organisation. Used for product and order forms.","summary":"Get VAT rates"}},"/bff/organisation/link-blob":{"get":{"parameters":[{"description":"Blob token of the uploaded file to link.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the blob was linked successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the blob was linked successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the blob was linked successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffOrganisationLink-blob","tags":["Organisation"],"description":"Links an uploaded blob to the organisation (e.g. logo, favicon).","summary":"Link blob to organisation"}},"/bff/organisation/link-print-logo-blob":{"get":{"parameters":[{"description":"Blob storage token of the image to use as print logo.","examples":["tok_abc123"],"schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the print logo was set successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the print logo was set successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the print logo was set successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffOrganisationLink-print-logo-blob","tags":["Organisation"],"description":"Links an uploaded image blob as the organisation print logo used in invoices, receipts, contracts, and PDF documents.","summary":"Set print logo from blob"}},"/bff/organisation/print-logo":{"delete":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the print logo was removed successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the print logo was removed successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the print logo was removed successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"deleteBffOrganisationPrint-logo","tags":["Organisation"],"description":"Removes the print logo from the organisation. Print documents will fall back to the standard organisation logo.","summary":"Remove print logo"}},"/bff/packeta/sync-branches":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the sync completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the sync completed successfully.","default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the sync completed successfully.","default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffPacketaSync-branches","tags":["Packeta"],"summary":"Sync Packeta branch points","description":"Fetches and synchronizes Packeta (Zasilkovna) pickup branch points from the Packeta API. Currently syncs Czech locale branches. Runs idempotently -- existing branches are updated, new ones inserted."}},"/bff/payment-gateway/list":{"get":{"responses":{"200":{"description":"List of payment gateway instances with usage statistics.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"List of configured payment gateways.","type":"array","items":{"description":"Payment gateway instance configuration and statistics.","type":"object","required":["code","description","environment","active","insertedDate","gatewayCode","gatewayName","paymentCount"],"properties":{"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description of the gateway configuration.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Whether the gateway is currently active and can process payments.","type":"boolean"},"insertedDate":{"description":"Date when the gateway was configured.","anyOf":[{"description":"Date when the gateway was configured.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"gatewayCode":{"description":"Provider code (e.g., \"gopay\", \"comgate\", \"stripe\").","type":"string"},"gatewayName":{"description":"Human-readable provider name.","type":"string"},"paymentCount":{"description":"Total number of payments processed through this gateway.","type":"number"},"lastUsedDate":{"description":"Date of the most recent payment attempt.","anyOf":[{"description":"Date of the most recent payment attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of gateway instances.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"List of configured payment gateways.","type":"array","items":{"description":"Payment gateway instance configuration and statistics.","type":"object","required":["code","description","environment","active","insertedDate","gatewayCode","gatewayName","paymentCount"],"properties":{"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description of the gateway configuration.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Whether the gateway is currently active and can process payments.","type":"boolean"},"insertedDate":{"description":"Date when the gateway was configured.","anyOf":[{"description":"Date when the gateway was configured.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"gatewayCode":{"description":"Provider code (e.g., \"gopay\", \"comgate\", \"stripe\").","type":"string"},"gatewayName":{"description":"Human-readable provider name.","type":"string"},"paymentCount":{"description":"Total number of payments processed through this gateway.","type":"number"},"lastUsedDate":{"description":"Date of the most recent payment attempt.","anyOf":[{"description":"Date of the most recent payment attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of gateway instances.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"List of configured payment gateways.","type":"array","items":{"description":"Payment gateway instance configuration and statistics.","type":"object","required":["code","description","environment","active","insertedDate","gatewayCode","gatewayName","paymentCount"],"properties":{"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description of the gateway configuration.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Whether the gateway is currently active and can process payments.","type":"boolean"},"insertedDate":{"description":"Date when the gateway was configured.","anyOf":[{"description":"Date when the gateway was configured.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"gatewayCode":{"description":"Provider code (e.g., \"gopay\", \"comgate\", \"stripe\").","type":"string"},"gatewayName":{"description":"Human-readable provider name.","type":"string"},"paymentCount":{"description":"Total number of payments processed through this gateway.","type":"number"},"lastUsedDate":{"description":"Date of the most recent payment attempt.","anyOf":[{"description":"Date of the most recent payment attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of gateway instances.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPayment-gatewayList","tags":["Payment Gateway"],"summary":"List payment gateways","description":"Returns a list of all configured payment gateway instances for the organisation. Each gateway includes basic configuration, usage statistics, and last activity date. Sensitive credentials (API keys, secrets) are NOT included - use the /keys endpoint for those."}},"/bff/payment-gateway/list-for-order-group":{"get":{"responses":{"200":{"description":"Merged list of selectable gateway instances.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Gateway instance eligible for selection as an order-group preference.","type":"object","required":["code","description","environment","active","gatewayCode","gatewayName","foreign"],"properties":{"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description of the gateway configuration.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Whether the gateway is currently active.","type":"boolean"},"gatewayCode":{"description":"Provider code (e.g., \"gopay\", \"comgate\", \"stripe\").","type":"string"},"gatewayName":{"description":"Human-readable provider name.","type":"string"},"foreign":{"description":"True when the gateway instance is owned by a different organisation but already referenced by one of this organisation's order groups (legacy binding).","type":"boolean"}}}},"itemCount":{"description":"Total number of items.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Gateway instance eligible for selection as an order-group preference.","type":"object","required":["code","description","environment","active","gatewayCode","gatewayName","foreign"],"properties":{"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description of the gateway configuration.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Whether the gateway is currently active.","type":"boolean"},"gatewayCode":{"description":"Provider code (e.g., \"gopay\", \"comgate\", \"stripe\").","type":"string"},"gatewayName":{"description":"Human-readable provider name.","type":"string"},"foreign":{"description":"True when the gateway instance is owned by a different organisation but already referenced by one of this organisation's order groups (legacy binding).","type":"boolean"}}}},"itemCount":{"description":"Total number of items.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Gateway instance eligible for selection as an order-group preference.","type":"object","required":["code","description","environment","active","gatewayCode","gatewayName","foreign"],"properties":{"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description of the gateway configuration.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Whether the gateway is currently active.","type":"boolean"},"gatewayCode":{"description":"Provider code (e.g., \"gopay\", \"comgate\", \"stripe\").","type":"string"},"gatewayName":{"description":"Human-readable provider name.","type":"string"},"foreign":{"description":"True when the gateway instance is owned by a different organisation but already referenced by one of this organisation's order groups (legacy binding).","type":"boolean"}}}},"itemCount":{"description":"Total number of items.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPayment-gatewayList-for-order-group","tags":["Payment Gateway"],"summary":"List gateways selectable for an order-group preference","description":"Returns the union of (a) all payment gateway instances owned by the organisation and (b) gateway instances owned by other organisations that are already referenced by at least one of this organisation's order groups via shop__order_payment_gateway_preference (legacy cross-organisation bindings). Used by the workflow \"Payment gateway for group\" modal so the operator can keep historical bindings consistent across groups."}},"/bff/payment-gateway/detail":{"get":{"parameters":[{"description":"Unique code/slug of the gateway instance.","examples":["gopay-production"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"description":"Detailed gateway information with statistics.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Internal database ID.","type":"string"},"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"environmentLabel":{"description":"Human-readable environment label.","type":"string"},"active":{"description":"Whether the gateway is active.","type":"boolean"},"insertedDate":{"description":"Date when the gateway was configured.","anyOf":[{"description":"Date when the gateway was configured.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"merchantId":{"description":"Merchant ID (if applicable for the provider).","type":"string"},"extra":{"description":"Additional provider-specific configuration.","type":"object","properties":{}},"providerId":{"description":"Internal provider ID.","type":"number"},"gatewayCode":{"description":"Provider code.","type":"string"},"gatewayName":{"description":"Provider name.","type":"string"},"paymentCount":{"description":"Total number of payments.","type":"number"},"paidPaymentCount":{"description":"Number of successful payments.","type":"number"},"totalAmount":{"description":"Total amount processed (successful payments only).","type":"number"},"lastUsedDate":{"description":"Date of most recent payment.","anyOf":[{"description":"Date of most recent payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"firstUsedDate":{"description":"Date of first payment.","anyOf":[{"description":"Date of first payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","code","description","environment","environmentLabel","active","insertedDate","extra","providerId","gatewayCode","gatewayName","paymentCount","paidPaymentCount","totalAmount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Internal database ID.","type":"string"},"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"environmentLabel":{"description":"Human-readable environment label.","type":"string"},"active":{"description":"Whether the gateway is active.","type":"boolean"},"insertedDate":{"description":"Date when the gateway was configured.","anyOf":[{"description":"Date when the gateway was configured.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"merchantId":{"description":"Merchant ID (if applicable for the provider).","type":"string"},"extra":{"description":"Additional provider-specific configuration.","type":"object","properties":{}},"providerId":{"description":"Internal provider ID.","type":"number"},"gatewayCode":{"description":"Provider code.","type":"string"},"gatewayName":{"description":"Provider name.","type":"string"},"paymentCount":{"description":"Total number of payments.","type":"number"},"paidPaymentCount":{"description":"Number of successful payments.","type":"number"},"totalAmount":{"description":"Total amount processed (successful payments only).","type":"number"},"lastUsedDate":{"description":"Date of most recent payment.","anyOf":[{"description":"Date of most recent payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"firstUsedDate":{"description":"Date of first payment.","anyOf":[{"description":"Date of first payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","code","description","environment","environmentLabel","active","insertedDate","extra","providerId","gatewayCode","gatewayName","paymentCount","paidPaymentCount","totalAmount"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Internal database ID.","type":"string"},"code":{"description":"Unique identifier/slug for this gateway instance.","type":"string"},"description":{"description":"Human-readable description.","type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"environmentLabel":{"description":"Human-readable environment label.","type":"string"},"active":{"description":"Whether the gateway is active.","type":"boolean"},"insertedDate":{"description":"Date when the gateway was configured.","anyOf":[{"description":"Date when the gateway was configured.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"merchantId":{"description":"Merchant ID (if applicable for the provider).","type":"string"},"extra":{"description":"Additional provider-specific configuration.","type":"object","properties":{}},"providerId":{"description":"Internal provider ID.","type":"number"},"gatewayCode":{"description":"Provider code.","type":"string"},"gatewayName":{"description":"Provider name.","type":"string"},"paymentCount":{"description":"Total number of payments.","type":"number"},"paidPaymentCount":{"description":"Number of successful payments.","type":"number"},"totalAmount":{"description":"Total amount processed (successful payments only).","type":"number"},"lastUsedDate":{"description":"Date of most recent payment.","anyOf":[{"description":"Date of most recent payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"firstUsedDate":{"description":"Date of first payment.","anyOf":[{"description":"Date of first payment.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","code","description","environment","environmentLabel","active","insertedDate","extra","providerId","gatewayCode","gatewayName","paymentCount","paidPaymentCount","totalAmount"]}}}}},"operationId":"getBffPayment-gatewayDetail","tags":["Payment Gateway"],"summary":"Get gateway detail","description":"Returns detailed information about a specific payment gateway instance, including configuration, extended statistics (success rate, total amount processed), and metadata. Sensitive credentials are NOT included - use the /keys endpoint for those."}},"/bff/payment-gateway/keys":{"get":{"parameters":[{"description":"Unique code/slug of the gateway instance.","examples":["gopay-production"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"description":"Gateway API credentials. Handle with care!","content":{"application/json":{"schema":{"type":"object","properties":{"publicKey":{"description":"Public API key (if applicable).","type":"string"},"secretKey":{"description":"Secret API key (if applicable).","type":"string"},"merchantId":{"description":"Merchant ID (if applicable).","type":"string"},"secureKey":{"description":"Additional secure key (if applicable).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"publicKey":{"description":"Public API key (if applicable).","type":"string"},"secretKey":{"description":"Secret API key (if applicable).","type":"string"},"merchantId":{"description":"Merchant ID (if applicable).","type":"string"},"secureKey":{"description":"Additional secure key (if applicable).","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"publicKey":{"description":"Public API key (if applicable).","type":"string"},"secretKey":{"description":"Secret API key (if applicable).","type":"string"},"merchantId":{"description":"Merchant ID (if applicable).","type":"string"},"secureKey":{"description":"Additional secure key (if applicable).","type":"string"}}}}}}},"operationId":"getBffPayment-gatewayKeys","tags":["Payment Gateway"],"summary":"Get gateway credentials","description":"Returns the sensitive API credentials for a payment gateway. This endpoint is separated from the detail endpoint for security reasons - credentials should only be fetched when explicitly needed (e.g., when editing gateway configuration). Requires elevated permissions."}},"/bff/payment-gateway/connection-status":{"get":{"parameters":[{"description":"Gateway instance code.","examples":["gopay-production"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"description":"Gateway connection status and masked credentials.","content":{"application/json":{"schema":{"type":"object","properties":{"configured":{"description":"Whether credentials are fully configured.","type":"boolean"},"connectionWorks":{"description":"Whether the connection test succeeded.","type":"boolean"},"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"credentials":{"description":"Masked credentials for UI display.","type":"object","properties":{"merchantId":{"description":"Merchant ID (if applicable).","type":"string"},"publicKey":{"description":"Public API key (if applicable).","type":"string"},"secretKey":{"description":"Masked secret API key.","type":"string"},"secureKey":{"description":"Masked secure key.","type":"string"}}}},"required":["configured","connectionWorks","provider","environment","credentials"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"configured":{"description":"Whether credentials are fully configured.","type":"boolean"},"connectionWorks":{"description":"Whether the connection test succeeded.","type":"boolean"},"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"credentials":{"description":"Masked credentials for UI display.","type":"object","properties":{"merchantId":{"description":"Merchant ID (if applicable).","type":"string"},"publicKey":{"description":"Public API key (if applicable).","type":"string"},"secretKey":{"description":"Masked secret API key.","type":"string"},"secureKey":{"description":"Masked secure key.","type":"string"}}}},"required":["configured","connectionWorks","provider","environment","credentials"]}},"text/plain":{"schema":{"type":"object","properties":{"configured":{"description":"Whether credentials are fully configured.","type":"boolean"},"connectionWorks":{"description":"Whether the connection test succeeded.","type":"boolean"},"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"credentials":{"description":"Masked credentials for UI display.","type":"object","properties":{"merchantId":{"description":"Merchant ID (if applicable).","type":"string"},"publicKey":{"description":"Public API key (if applicable).","type":"string"},"secretKey":{"description":"Masked secret API key.","type":"string"},"secureKey":{"description":"Masked secure key.","type":"string"}}}},"required":["configured","connectionWorks","provider","environment","credentials"]}}}}},"operationId":"getBffPayment-gatewayConnection-status","tags":["Payment Gateway"],"summary":"Check gateway connection status","description":"Checks if the gateway credentials are configured and tests the actual connection to the payment provider. Returns masked credentials for display in UI."}},"/bff/payment-gateway/test-connection":{"post":{"parameters":[],"responses":{"200":{"description":"Connection test result.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the connection test succeeded.","type":"boolean"},"errorMessage":{"description":"Error message if test failed.","type":"string"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the connection test succeeded.","type":"boolean"},"errorMessage":{"description":"Error message if test failed.","type":"string"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the connection test succeeded.","type":"boolean"},"errorMessage":{"description":"Error message if test failed.","type":"string"}},"required":["success"]}}}}},"operationId":"postBffPayment-gatewayTest-connection","tags":["Payment Gateway"],"summary":"Test gateway connection","description":"Tests the connection to a payment gateway with provided credentials. If a gateway code is provided, missing credentials will be loaded from the database, allowing you to test new credentials alongside existing ones.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["provider"],"properties":{"code":{"description":"Gateway code - if provided, missing credentials are loaded from DB.","examples":["gopay-production"],"type":"string"},"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"publicKey":{"description":"Public API key.","type":"string"},"secretKey":{"description":"Secret API key.","type":"string"},"merchantId":{"description":"Merchant ID.","type":"string"},"secureKey":{"description":"Secure key.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["provider"],"properties":{"code":{"description":"Gateway code - if provided, missing credentials are loaded from DB.","examples":["gopay-production"],"type":"string"},"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"publicKey":{"description":"Public API key.","type":"string"},"secretKey":{"description":"Secret API key.","type":"string"},"merchantId":{"description":"Merchant ID.","type":"string"},"secureKey":{"description":"Secure key.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["provider"],"properties":{"code":{"description":"Gateway code - if provided, missing credentials are loaded from DB.","examples":["gopay-production"],"type":"string"},"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox, \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"publicKey":{"description":"Public API key.","type":"string"},"secretKey":{"description":"Secret API key.","type":"string"},"merchantId":{"description":"Merchant ID.","type":"string"},"secureKey":{"description":"Secure key.","type":"string"}}}}}}}},"/bff/payment-gateway/stats":{"get":{"responses":{"200":{"description":"Aggregated payment statistics.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Statistics grouped by gateway.","type":"array","items":{"description":"Statistics for a single gateway.","type":"object","required":["gatewayCode","gatewayName","totalPayments","paidPayments","failedPayments","pendingPayments","totalAmount","successRate"],"properties":{"gatewayCode":{"description":"Gateway instance code.","type":"string"},"gatewayName":{"description":"Provider name.","type":"string"},"totalPayments":{"description":"Total number of payment attempts.","type":"number"},"paidPayments":{"description":"Number of successful payments.","type":"number"},"failedPayments":{"description":"Number of failed/cancelled payments.","type":"number"},"pendingPayments":{"description":"Number of pending payments.","type":"number"},"totalAmount":{"description":"Total amount from successful payments.","type":"number"},"successRate":{"description":"Success rate as percentage (0-100).","type":"number"}}}},"itemCount":{"description":"Number of gateways with statistics.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Statistics grouped by gateway.","type":"array","items":{"description":"Statistics for a single gateway.","type":"object","required":["gatewayCode","gatewayName","totalPayments","paidPayments","failedPayments","pendingPayments","totalAmount","successRate"],"properties":{"gatewayCode":{"description":"Gateway instance code.","type":"string"},"gatewayName":{"description":"Provider name.","type":"string"},"totalPayments":{"description":"Total number of payment attempts.","type":"number"},"paidPayments":{"description":"Number of successful payments.","type":"number"},"failedPayments":{"description":"Number of failed/cancelled payments.","type":"number"},"pendingPayments":{"description":"Number of pending payments.","type":"number"},"totalAmount":{"description":"Total amount from successful payments.","type":"number"},"successRate":{"description":"Success rate as percentage (0-100).","type":"number"}}}},"itemCount":{"description":"Number of gateways with statistics.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Statistics grouped by gateway.","type":"array","items":{"description":"Statistics for a single gateway.","type":"object","required":["gatewayCode","gatewayName","totalPayments","paidPayments","failedPayments","pendingPayments","totalAmount","successRate"],"properties":{"gatewayCode":{"description":"Gateway instance code.","type":"string"},"gatewayName":{"description":"Provider name.","type":"string"},"totalPayments":{"description":"Total number of payment attempts.","type":"number"},"paidPayments":{"description":"Number of successful payments.","type":"number"},"failedPayments":{"description":"Number of failed/cancelled payments.","type":"number"},"pendingPayments":{"description":"Number of pending payments.","type":"number"},"totalAmount":{"description":"Total amount from successful payments.","type":"number"},"successRate":{"description":"Success rate as percentage (0-100).","type":"number"}}}},"itemCount":{"description":"Number of gateways with statistics.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPayment-gatewayStats","tags":["Payment Gateway"],"summary":"Get payment statistics","description":"Returns aggregated payment statistics grouped by gateway. Includes success rates, payment counts by status, and total amounts processed. Useful for analytics dashboards."}},"/bff/payment-gateway/payment-list":{"get":{"parameters":[{"description":"Filter by order hash. Returns payments for specific order.","examples":["abc123def"],"schema":{"type":"string"},"in":"query","name":"orderHash","required":false},{"description":"Filter by gateway code. Returns payments for specific gateway.","examples":["gopay-production"],"schema":{"type":"string"},"in":"query","name":"gatewayCode","required":false},{"description":"Filter by payment status (e.g., \"PAID\", \"PENDING\", \"CANCELLED\").","examples":["PAID"],"schema":{"type":"string"},"in":"query","name":"status","required":false}],"responses":{"200":{"description":"Paginated list of payment transactions.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"List of payment transactions.","type":"array","items":{"description":"Payment transaction record.","type":"object","required":["id","internal_id","gateway_id","provider_id","gateway_name","price","currency_code","status","inserted_date","label"],"properties":{"id":{"description":"Composite payment identifier.","type":"string"},"internal_id":{"description":"Internal database ID.","type":"number"},"gateway_id":{"description":"Provider-specific transaction ID.","type":"string"},"gateway_code":{"description":"Gateway instance code.","type":"string"},"provider_id":{"description":"Payment provider ID.","type":"number"},"gateway_description":{"description":"Gateway description.","type":"string"},"gateway_name":{"description":"Provider name.","type":"string"},"price":{"description":"Payment amount.","type":"number"},"currency_code":{"description":"Currency code (e.g., \"CZK\", \"EUR\").","type":"string"},"status":{"description":"Current payment status.","type":"string"},"inserted_date":{"description":"Date when payment was created.","anyOf":[{"description":"Date when payment was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"last_checked_date":{"description":"Date of last status check.","anyOf":[{"description":"Date of last status check.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"label":{"description":"Human-readable payment label with status.","type":"string"},"order_number":{"description":"Associated order number.","type":"string"},"order_hash":{"description":"Associated order hash for linking.","type":"string"}}}},"itemCount":{"description":"Total number of payments matching the filter (for pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"List of payment transactions.","type":"array","items":{"description":"Payment transaction record.","type":"object","required":["id","internal_id","gateway_id","provider_id","gateway_name","price","currency_code","status","inserted_date","label"],"properties":{"id":{"description":"Composite payment identifier.","type":"string"},"internal_id":{"description":"Internal database ID.","type":"number"},"gateway_id":{"description":"Provider-specific transaction ID.","type":"string"},"gateway_code":{"description":"Gateway instance code.","type":"string"},"provider_id":{"description":"Payment provider ID.","type":"number"},"gateway_description":{"description":"Gateway description.","type":"string"},"gateway_name":{"description":"Provider name.","type":"string"},"price":{"description":"Payment amount.","type":"number"},"currency_code":{"description":"Currency code (e.g., \"CZK\", \"EUR\").","type":"string"},"status":{"description":"Current payment status.","type":"string"},"inserted_date":{"description":"Date when payment was created.","anyOf":[{"description":"Date when payment was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"last_checked_date":{"description":"Date of last status check.","anyOf":[{"description":"Date of last status check.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"label":{"description":"Human-readable payment label with status.","type":"string"},"order_number":{"description":"Associated order number.","type":"string"},"order_hash":{"description":"Associated order hash for linking.","type":"string"}}}},"itemCount":{"description":"Total number of payments matching the filter (for pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"List of payment transactions.","type":"array","items":{"description":"Payment transaction record.","type":"object","required":["id","internal_id","gateway_id","provider_id","gateway_name","price","currency_code","status","inserted_date","label"],"properties":{"id":{"description":"Composite payment identifier.","type":"string"},"internal_id":{"description":"Internal database ID.","type":"number"},"gateway_id":{"description":"Provider-specific transaction ID.","type":"string"},"gateway_code":{"description":"Gateway instance code.","type":"string"},"provider_id":{"description":"Payment provider ID.","type":"number"},"gateway_description":{"description":"Gateway description.","type":"string"},"gateway_name":{"description":"Provider name.","type":"string"},"price":{"description":"Payment amount.","type":"number"},"currency_code":{"description":"Currency code (e.g., \"CZK\", \"EUR\").","type":"string"},"status":{"description":"Current payment status.","type":"string"},"inserted_date":{"description":"Date when payment was created.","anyOf":[{"description":"Date when payment was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"last_checked_date":{"description":"Date of last status check.","anyOf":[{"description":"Date of last status check.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"label":{"description":"Human-readable payment label with status.","type":"string"},"order_number":{"description":"Associated order number.","type":"string"},"order_hash":{"description":"Associated order hash for linking.","type":"string"}}}},"itemCount":{"description":"Total number of payments matching the filter (for pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPayment-gatewayPayment-list","tags":["Payment Gateway"],"summary":"List payments","description":"Returns a paginated list of online payment transactions. Supports filtering by order, gateway, and status. Use query params `page` and `limit` for pagination."}},"/bff/payment-gateway/add":{"post":{"parameters":[],"responses":{"200":{"description":"Gateway created successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"description":"The code/slug assigned to the new gateway.","type":"string"}},"required":["success","code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"description":"The code/slug assigned to the new gateway.","type":"string"}},"required":["success","code"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"description":"The code/slug assigned to the new gateway.","type":"string"}},"required":["success","code"]}}}}},"operationId":"postBffPayment-gatewayAdd","tags":["Payment Gateway"],"summary":"Add new gateway","description":"Creates a new payment gateway instance. The provider must be one of the supported types. Credentials can be provided during creation or added later via the update endpoint.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["provider"],"properties":{"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"code":{"description":"Custom code/slug. Auto-generated if not provided.","examples":["gopay-production"],"type":"string"},"description":{"description":"Human-readable description.","examples":["GoPay production gateway"],"type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox (default), \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"publicKey":{"description":"Public API key.","type":"string"},"secretKey":{"description":"Secret API key.","type":"string"},"merchantId":{"description":"Merchant ID.","type":"string"},"secureKey":{"description":"Additional secure key.","type":"string"},"extra":{"description":"Additional provider-specific settings.","type":"object","properties":{}}}}},"multipart/form-data":{"schema":{"type":"object","required":["provider"],"properties":{"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"code":{"description":"Custom code/slug. Auto-generated if not provided.","examples":["gopay-production"],"type":"string"},"description":{"description":"Human-readable description.","examples":["GoPay production gateway"],"type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox (default), \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"publicKey":{"description":"Public API key.","type":"string"},"secretKey":{"description":"Secret API key.","type":"string"},"merchantId":{"description":"Merchant ID.","type":"string"},"secureKey":{"description":"Additional secure key.","type":"string"},"extra":{"description":"Additional provider-specific settings.","type":"object","properties":{}}}}},"text/plain":{"schema":{"type":"object","required":["provider"],"properties":{"provider":{"description":"Payment provider type.","anyOf":[{"const":"gopay","type":"string"},{"const":"comgate","type":"string"},{"const":"stripe","type":"string"}]},"code":{"description":"Custom code/slug. Auto-generated if not provided.","examples":["gopay-production"],"type":"string"},"description":{"description":"Human-readable description.","examples":["GoPay production gateway"],"type":"string"},"environment":{"description":"Environment: \"p\" = Production, \"s\" = Sandbox (default), \"t\" = Test.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"publicKey":{"description":"Public API key.","type":"string"},"secretKey":{"description":"Secret API key.","type":"string"},"merchantId":{"description":"Merchant ID.","type":"string"},"secureKey":{"description":"Additional secure key.","type":"string"},"extra":{"description":"Additional provider-specific settings.","type":"object","properties":{}}}}}}}}},"/bff/payment-gateway/update":{"post":{"parameters":[],"responses":{"200":{"description":"Gateway updated successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffPayment-gatewayUpdate","tags":["Payment Gateway"],"summary":"Update gateway","description":"Updates an existing payment gateway instance. Only provided fields will be updated. To clear a field, pass an empty string. To change credentials, provide new values.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Gateway code to update.","examples":["gopay-production"],"type":"string"},"description":{"description":"New description.","type":"string"},"environment":{"description":"New environment setting.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Enable or disable the gateway.","type":"boolean"},"publicKey":{"description":"New public API key.","type":"string"},"secretKey":{"description":"New secret API key.","type":"string"},"merchantId":{"description":"New merchant ID.","type":"string"},"secureKey":{"description":"New secure key.","type":"string"},"extra":{"description":"New extra configuration.","type":"object","properties":{}}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Gateway code to update.","examples":["gopay-production"],"type":"string"},"description":{"description":"New description.","type":"string"},"environment":{"description":"New environment setting.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Enable or disable the gateway.","type":"boolean"},"publicKey":{"description":"New public API key.","type":"string"},"secretKey":{"description":"New secret API key.","type":"string"},"merchantId":{"description":"New merchant ID.","type":"string"},"secureKey":{"description":"New secure key.","type":"string"},"extra":{"description":"New extra configuration.","type":"object","properties":{}}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Gateway code to update.","examples":["gopay-production"],"type":"string"},"description":{"description":"New description.","type":"string"},"environment":{"description":"New environment setting.","anyOf":[{"const":"p","type":"string"},{"const":"s","type":"string"},{"const":"t","type":"string"}]},"active":{"description":"Enable or disable the gateway.","type":"boolean"},"publicKey":{"description":"New public API key.","type":"string"},"secretKey":{"description":"New secret API key.","type":"string"},"merchantId":{"description":"New merchant ID.","type":"string"},"secureKey":{"description":"New secure key.","type":"string"},"extra":{"description":"New extra configuration.","type":"object","properties":{}}}}}}}}},"/bff/payment-gateway/toggle-active":{"post":{"parameters":[],"responses":{"200":{"description":"Status toggled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffPayment-gatewayToggle-active","tags":["Payment Gateway"],"summary":"Toggle gateway active status","description":"Quickly enable or disable a payment gateway. Disabled gateways cannot process new payments but existing payments can still be checked/synced.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","active"],"properties":{"code":{"description":"Gateway code.","examples":["gopay-production"],"type":"string"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","active"],"properties":{"code":{"description":"Gateway code.","examples":["gopay-production"],"type":"string"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["code","active"],"properties":{"code":{"description":"Gateway code.","examples":["gopay-production"],"type":"string"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}}}}}},"/bff/payment-gateway/delete":{"post":{"parameters":[],"responses":{"200":{"description":"Gateway deleted successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffPayment-gatewayDelete","tags":["Payment Gateway"],"summary":"Delete gateway","description":"Permanently deletes a payment gateway instance. This operation is only allowed if the gateway has no associated payments. If payments exist, deactivate the gateway instead.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Gateway code to delete.","examples":["gopay-sandbox"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Gateway code to delete.","examples":["gopay-sandbox"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Gateway code to delete.","examples":["gopay-sandbox"],"type":"string"}}}}}}}},"/bff/payment-gateway/sync-payment":{"post":{"parameters":[],"responses":{"200":{"description":"Sync result.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"message":{"description":"Error message if sync failed.","type":"string"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"message":{"description":"Error message if sync failed.","type":"string"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"message":{"description":"Error message if sync failed.","type":"string"}},"required":["success"]}}}}},"operationId":"postBffPayment-gatewaySync-payment","tags":["Payment Gateway"],"summary":"Sync payment status","description":"Fetches the current payment status from the payment provider and updates the local record. Useful for checking if a payment has been completed or for troubleshooting.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Payment ID to sync.","examples":["pay_12345"],"type":"string"},"orderHash":{"description":"Order hash - syncs all payments for this order.","examples":["abc123def"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Payment ID to sync.","examples":["pay_12345"],"type":"string"},"orderHash":{"description":"Order hash - syncs all payments for this order.","examples":["abc123def"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Payment ID to sync.","examples":["pay_12345"],"type":"string"},"orderHash":{"description":"Order hash - syncs all payments for this order.","examples":["abc123def"],"type":"string"}}}}}}}},"/bff/permission/shareable-entities":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"string"}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"string"}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"string"}}},"required":["items"]}}}}},"operationId":"getBffPermissionShareable-entities","tags":["Permission"],"summary":"List entity types that support per-entity sharing"}},"/bff/permission/entity-share-list":{"get":{"parameters":[{"description":"Entity code (e.g. \"calendar\").","schema":{"type":"string"},"in":"query","name":"entity","required":true},{"description":"Public code/slug identifying the specific entity.","schema":{"type":"string"},"in":"query","name":"entityCode","required":true}],"operationId":"getBffPermissionEntity-share-list","tags":["Permission"],"summary":"List members with access to an entity","description":"Returns members who can see the entity: those with an explicit grant in `cas__organisation_entity_permission`, plus members with the `root` permission (implicit access). Used by the admin sharing dialog.","responses":{"200":{}}}},"/bff/permission/entity-share-add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffPermissionEntity-share-add","tags":["Permission"],"summary":"Grant a member direct access to an entity","description":"Idempotent — if an active grant already exists, validTo / permissionCode are updated in place.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entity","entityCode","memberId"],"properties":{"entity":{"type":"string"},"entityCode":{"type":"string"},"memberId":{"description":"External member id (shop__contact.external_id).","type":"string"},"permissionCode":{"description":"Optional fine-grained permission code attached to the grant.","type":"string"},"validTo":{"description":"ISO timestamp; access expires at this date. Omit for indefinite access.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["entity","entityCode","memberId"],"properties":{"entity":{"type":"string"},"entityCode":{"type":"string"},"memberId":{"description":"External member id (shop__contact.external_id).","type":"string"},"permissionCode":{"description":"Optional fine-grained permission code attached to the grant.","type":"string"},"validTo":{"description":"ISO timestamp; access expires at this date. Omit for indefinite access.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["entity","entityCode","memberId"],"properties":{"entity":{"type":"string"},"entityCode":{"type":"string"},"memberId":{"description":"External member id (shop__contact.external_id).","type":"string"},"permissionCode":{"description":"Optional fine-grained permission code attached to the grant.","type":"string"},"validTo":{"description":"ISO timestamp; access expires at this date. Omit for indefinite access.","type":"string"}}}}}}}},"/bff/permission/member-entity-summary":{"get":{"parameters":[{"description":"External member id (shop__contact.external_id).","schema":{"type":"string"},"in":"query","name":"memberId","required":true}],"operationId":"getBffPermissionMember-entity-summary","tags":["Permission"],"summary":"Summarise per-entity-type access for one member","description":"For every shareable entity type returns: the count of entities the member can see, the total available in the organisation, whether visibility comes from `root`, and up to 3 example names. Powers the reverse-axis \"what does this member see\" UI block in admin.","responses":{"200":{}}}},"/bff/permission/member-entity-picker":{"get":{"parameters":[{"description":"External member id whose access is being managed.","schema":{"type":"string"},"in":"query","name":"memberId","required":true},{"description":"Shareable entity type code (e.g. \"calendar\").","schema":{"type":"string"},"in":"query","name":"entity","required":true},{"description":"Free-text filter — matches name/code/email.","schema":{"type":"string"},"in":"query","name":"search","required":false},{"description":"1-indexed page number.","schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Page size (default 30, max 200).","schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffPermissionMember-entity-picker","tags":["Permission"],"summary":"List entities of a type with per-row \"isShared\" flag for one member","description":"Backs the reverse-axis picker modal in admin (member detail → pick which entities of a given type they can access). Pair with /permission/entity-share-add and -remove to toggle individual entries.","responses":{"200":{}}}},"/bff/permission/entity-share-remove":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffPermissionEntity-share-remove","tags":["Permission"],"summary":"Revoke a member’s direct access to an entity","description":"Soft-revoke (sets valid_to=NOW()). Root members keep access through the `root` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entity","entityCode","memberId"],"properties":{"entity":{"type":"string"},"entityCode":{"type":"string"},"memberId":{"description":"External member id of the member whose access to revoke.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["entity","entityCode","memberId"],"properties":{"entity":{"type":"string"},"entityCode":{"type":"string"},"memberId":{"description":"External member id of the member whose access to revoke.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["entity","entityCode","memberId"],"properties":{"entity":{"type":"string"},"entityCode":{"type":"string"},"memberId":{"description":"External member id of the member whose access to revoke.","type":"string"}}}}}}}},"/bff/person/search":{"get":{"parameters":[{"description":"Free-text search query (name, email, or phone).","examples":["jan"],"schema":{"type":"string"},"in":"query","name":"query","required":false},{"description":"Comma-separated list of cuRefNo IDs used to resolve persons.","examples":["1cGIHvFoQDGLAbcA,1cGshrhn5DGLAbcA"],"schema":{"type":"string"},"in":"query","name":"ids","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"description":"Customer external ID (cuRefNo).","type":"string"},"name":{"description":"Full name of the person.","examples":["Jan Barášek"],"type":"string"},"memberId":{"description":"Organisation member ID, if the person is a member.","type":"number"},"customerId":{"description":"Customer record ID, if the person is a customer.","type":"number"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"avatarInfo":{"type":"object","properties":{"fullName":{"description":"Display name for the avatar.","examples":["Jan Barášek"],"type":"string"},"avatarUrl":{"description":"URL of the avatar image.","examples":["https://storage.xhp.cz/brj%2Favatar%2Fha70t7we3kvkkby5wcdv16m0r9fhjt24.jpg"],"type":"string"},"activityInfo":{"type":"object","properties":{"status":{"description":"Online status flag (\"t\" = online, \"f\" = offline).","examples":["f"],"type":"string"},"inActiveMinutes":{"description":"Minutes since last activity.","examples":[28.12595],"type":"number"},"lastActivity":{"description":"Timestamp of last recorded activity.","examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"description":"Timestamp of last recorded activity.","examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"description":"Customer external ID (cuRefNo).","type":"string"},"name":{"description":"Full name of the person.","examples":["Jan Barášek"],"type":"string"},"memberId":{"description":"Organisation member ID, if the person is a member.","type":"number"},"customerId":{"description":"Customer record ID, if the person is a customer.","type":"number"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"avatarInfo":{"type":"object","properties":{"fullName":{"description":"Display name for the avatar.","examples":["Jan Barášek"],"type":"string"},"avatarUrl":{"description":"URL of the avatar image.","examples":["https://storage.xhp.cz/brj%2Favatar%2Fha70t7we3kvkkby5wcdv16m0r9fhjt24.jpg"],"type":"string"},"activityInfo":{"type":"object","properties":{"status":{"description":"Online status flag (\"t\" = online, \"f\" = offline).","examples":["f"],"type":"string"},"inActiveMinutes":{"description":"Minutes since last activity.","examples":[28.12595],"type":"number"},"lastActivity":{"description":"Timestamp of last recorded activity.","examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"description":"Timestamp of last recorded activity.","examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"description":"Customer external ID (cuRefNo).","type":"string"},"name":{"description":"Full name of the person.","examples":["Jan Barášek"],"type":"string"},"memberId":{"description":"Organisation member ID, if the person is a member.","type":"number"},"customerId":{"description":"Customer record ID, if the person is a customer.","type":"number"},"email":{"examples":["jan@barasek.com"],"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","type":"string"},"phone":{"examples":["+420 777123456"],"description":"Contact phone number in international (national) format.\n\n**Preferred format:** `+<country_code> <local_number>`  \n- Leading plus sign (`+`) is required\n- Followed by the country calling code (e.g. `420`)\n- One space after the country code\n- Full local number **without spaces**\n\n**Example:** `+420 777123456`  \nThis format ensures unambiguous storage, validation, and compatibility with SMS, calling, and third-party integrations (e.g. Twilio, WhatsApp, CRM systems).","type":"string"},"avatarInfo":{"type":"object","properties":{"fullName":{"description":"Display name for the avatar.","examples":["Jan Barášek"],"type":"string"},"avatarUrl":{"description":"URL of the avatar image.","examples":["https://storage.xhp.cz/brj%2Favatar%2Fha70t7we3kvkkby5wcdv16m0r9fhjt24.jpg"],"type":"string"},"activityInfo":{"type":"object","properties":{"status":{"description":"Online status flag (\"t\" = online, \"f\" = offline).","examples":["f"],"type":"string"},"inActiveMinutes":{"description":"Minutes since last activity.","examples":[28.12595],"type":"number"},"lastActivity":{"description":"Timestamp of last recorded activity.","examples":["2025-01-10T16:19:40.150Z"],"anyOf":[{"description":"Timestamp of last recorded activity.","examples":["2025-01-10T16:19:40.150Z"],"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}}}}}},"required":["items"]}}}}},"operationId":"getBffPersonSearch","tags":["Person"],"summary":"Search contacts / persons","description":"Searches organisation contacts by name, email, or phone. Alternatively resolves specific contacts by their external IDs. Returns matching persons with avatar and activity information when available."}},"/bff/post/list":{"get":{"parameters":[{"description":"Filter posts by main category code. If not provided, all posts are returned.","schema":{"type":"string"},"in":"query","name":"mainCategoryCode","required":false},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false},{"description":"Filter by computed publication status (draft, scheduled, published, private, archived).","schema":{"anyOf":[{"const":"draft","type":"string"},{"const":"scheduled","type":"string"},{"const":"published","type":"string"},{"const":"private","type":"string"},{"const":"archived","type":"string"}]},"in":"query","name":"status","required":false},{"description":"Filter by raw visibility column.","schema":{"anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"in":"query","name":"visibility","required":false},{"description":"\"true\" to keep only posts with a main image, \"false\" to keep only those without.","schema":{"type":"string"},"in":"query","name":"hasMainImage","required":false},{"description":"\"true\" to keep only posts missing a translation in at least one of the org's configured locales.","schema":{"type":"string"},"in":"query","name":"missingTranslation","required":false},{"description":"Sort spec `<field>:<asc|desc>`. Allowed fields: publishedDate, updatedDate, insertedDate, title, wordCount, commentsCount, viewsCount.","examples":["publishedDate:desc","wordCount:asc","viewsCount:desc"],"schema":{"type":"string"},"in":"query","name":"orderBy","required":false},{"description":"Alias for orderBy (legacy).","schema":{"type":"string"},"in":"query","name":"sortBy","required":false}],"responses":{"200":{"description":"Paginated list of posts with metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of post items matching the query criteria.","type":"array","items":{"description":"Single post item in the list.","type":"object","required":["id","title","commentsCount","insertedDate","updatedDate","visibility","status","isStar","isDeleted","wordCount","readingTimeMinutes","hasPerex","tags","translatedLocales","viewsCount"],"properties":{"id":{"description":"Unique external identifier of the post (UUID format).","type":"string"},"title":{"description":"Post title, truncated to 140 characters for list view.","type":"string"},"mainCategoryId":{"description":"External ID of the main category this post belongs to.","type":"string"},"mainCategoryName":{"description":"Localized name of the main category.","type":"string"},"mainAuthorId":{"description":"External ID of the main author (customer/contact).","type":"string"},"mainAuthorName":{"description":"Full name of the main author.","type":"string"},"commentsCount":{"description":"Total number of comments on this post.","type":"number"},"publishedDate":{"description":"Date when the post was published. Null if not yet published.","anyOf":[{"description":"Date when the post was published. Null if not yet published.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the post was created in the system.","anyOf":[{"description":"Date when the post was created in the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when `content__post.*` was last updated. Useful for an \"edited recently\" sort.","anyOf":[{"description":"Date when `content__post.*` was last updated. Useful for an \"edited recently\" sort.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"visibility":{"description":"Post visibility level. \"public\" = visible to everyone, \"private\" = visible only to author and admins, \"unlisted\" = accessible via direct link but not listed, \"subscribe\" = visible only to subscribers.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"status":{"description":"Computed publication status derived from (visibility, publishedDate, deletedDate). See `resolvePostStatus` in core for the precedence rules.","anyOf":[{"const":"draft","type":"string"},{"const":"scheduled","type":"string"},{"const":"published","type":"string"},{"const":"private","type":"string"},{"const":"archived","type":"string"}]},"mainImageUrl":{"description":"URL of the main/featured image for the post.","type":"string"},"isStar":{"description":"Whether the post is starred/featured. Starred posts appear first in the list.","type":"boolean"},"isDeleted":{"description":"Whether the post has been soft-deleted.","type":"boolean"},"wordCount":{"description":"Approximate word count of the displayed locale's content (HTML stripped).","type":"number"},"readingTimeMinutes":{"description":"Approximate reading time in minutes (200 wpm). 0 when the post has no content.","type":"number"},"hasPerex":{"description":"Whether the displayed locale has a non-empty perex (used by SEO health indicator).","type":"boolean"},"tags":{"description":"Array of tags assigned to this post. Can be empty if no tags are assigned.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["id","name","code"],"properties":{"id":{"description":"Unique identifier of the tag.","type":"number"},"name":{"description":"Display name of the tag.","type":"string"},"code":{"description":"URL-friendly code/slug of the tag.","type":"string"},"color":{"description":"Hex color code for the tag (e.g., \"#FF5733\").","type":"string"}}}},"translatedLocales":{"description":"Locales for which a translation exists in content__post_locale.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"viewsCount":{"description":"Cumulative number of times the post was served by /api/v1/post. Buffered in Redis and flushed into content__post.views_count every 5 min, so values may briefly lag.","type":"number"}}}},"itemCount":{"description":"Total number of posts matching the query (before pagination). Useful for pagination controls.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of post items matching the query criteria.","type":"array","items":{"description":"Single post item in the list.","type":"object","required":["id","title","commentsCount","insertedDate","updatedDate","visibility","status","isStar","isDeleted","wordCount","readingTimeMinutes","hasPerex","tags","translatedLocales","viewsCount"],"properties":{"id":{"description":"Unique external identifier of the post (UUID format).","type":"string"},"title":{"description":"Post title, truncated to 140 characters for list view.","type":"string"},"mainCategoryId":{"description":"External ID of the main category this post belongs to.","type":"string"},"mainCategoryName":{"description":"Localized name of the main category.","type":"string"},"mainAuthorId":{"description":"External ID of the main author (customer/contact).","type":"string"},"mainAuthorName":{"description":"Full name of the main author.","type":"string"},"commentsCount":{"description":"Total number of comments on this post.","type":"number"},"publishedDate":{"description":"Date when the post was published. Null if not yet published.","anyOf":[{"description":"Date when the post was published. Null if not yet published.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the post was created in the system.","anyOf":[{"description":"Date when the post was created in the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when `content__post.*` was last updated. Useful for an \"edited recently\" sort.","anyOf":[{"description":"Date when `content__post.*` was last updated. Useful for an \"edited recently\" sort.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"visibility":{"description":"Post visibility level. \"public\" = visible to everyone, \"private\" = visible only to author and admins, \"unlisted\" = accessible via direct link but not listed, \"subscribe\" = visible only to subscribers.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"status":{"description":"Computed publication status derived from (visibility, publishedDate, deletedDate). See `resolvePostStatus` in core for the precedence rules.","anyOf":[{"const":"draft","type":"string"},{"const":"scheduled","type":"string"},{"const":"published","type":"string"},{"const":"private","type":"string"},{"const":"archived","type":"string"}]},"mainImageUrl":{"description":"URL of the main/featured image for the post.","type":"string"},"isStar":{"description":"Whether the post is starred/featured. Starred posts appear first in the list.","type":"boolean"},"isDeleted":{"description":"Whether the post has been soft-deleted.","type":"boolean"},"wordCount":{"description":"Approximate word count of the displayed locale's content (HTML stripped).","type":"number"},"readingTimeMinutes":{"description":"Approximate reading time in minutes (200 wpm). 0 when the post has no content.","type":"number"},"hasPerex":{"description":"Whether the displayed locale has a non-empty perex (used by SEO health indicator).","type":"boolean"},"tags":{"description":"Array of tags assigned to this post. Can be empty if no tags are assigned.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["id","name","code"],"properties":{"id":{"description":"Unique identifier of the tag.","type":"number"},"name":{"description":"Display name of the tag.","type":"string"},"code":{"description":"URL-friendly code/slug of the tag.","type":"string"},"color":{"description":"Hex color code for the tag (e.g., \"#FF5733\").","type":"string"}}}},"translatedLocales":{"description":"Locales for which a translation exists in content__post_locale.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"viewsCount":{"description":"Cumulative number of times the post was served by /api/v1/post. Buffered in Redis and flushed into content__post.views_count every 5 min, so values may briefly lag.","type":"number"}}}},"itemCount":{"description":"Total number of posts matching the query (before pagination). Useful for pagination controls.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of post items matching the query criteria.","type":"array","items":{"description":"Single post item in the list.","type":"object","required":["id","title","commentsCount","insertedDate","updatedDate","visibility","status","isStar","isDeleted","wordCount","readingTimeMinutes","hasPerex","tags","translatedLocales","viewsCount"],"properties":{"id":{"description":"Unique external identifier of the post (UUID format).","type":"string"},"title":{"description":"Post title, truncated to 140 characters for list view.","type":"string"},"mainCategoryId":{"description":"External ID of the main category this post belongs to.","type":"string"},"mainCategoryName":{"description":"Localized name of the main category.","type":"string"},"mainAuthorId":{"description":"External ID of the main author (customer/contact).","type":"string"},"mainAuthorName":{"description":"Full name of the main author.","type":"string"},"commentsCount":{"description":"Total number of comments on this post.","type":"number"},"publishedDate":{"description":"Date when the post was published. Null if not yet published.","anyOf":[{"description":"Date when the post was published. Null if not yet published.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the post was created in the system.","anyOf":[{"description":"Date when the post was created in the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when `content__post.*` was last updated. Useful for an \"edited recently\" sort.","anyOf":[{"description":"Date when `content__post.*` was last updated. Useful for an \"edited recently\" sort.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"visibility":{"description":"Post visibility level. \"public\" = visible to everyone, \"private\" = visible only to author and admins, \"unlisted\" = accessible via direct link but not listed, \"subscribe\" = visible only to subscribers.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"status":{"description":"Computed publication status derived from (visibility, publishedDate, deletedDate). See `resolvePostStatus` in core for the precedence rules.","anyOf":[{"const":"draft","type":"string"},{"const":"scheduled","type":"string"},{"const":"published","type":"string"},{"const":"private","type":"string"},{"const":"archived","type":"string"}]},"mainImageUrl":{"description":"URL of the main/featured image for the post.","type":"string"},"isStar":{"description":"Whether the post is starred/featured. Starred posts appear first in the list.","type":"boolean"},"isDeleted":{"description":"Whether the post has been soft-deleted.","type":"boolean"},"wordCount":{"description":"Approximate word count of the displayed locale's content (HTML stripped).","type":"number"},"readingTimeMinutes":{"description":"Approximate reading time in minutes (200 wpm). 0 when the post has no content.","type":"number"},"hasPerex":{"description":"Whether the displayed locale has a non-empty perex (used by SEO health indicator).","type":"boolean"},"tags":{"description":"Array of tags assigned to this post. Can be empty if no tags are assigned.","type":"array","items":{"description":"Tag associated with the post.","type":"object","required":["id","name","code"],"properties":{"id":{"description":"Unique identifier of the tag.","type":"number"},"name":{"description":"Display name of the tag.","type":"string"},"code":{"description":"URL-friendly code/slug of the tag.","type":"string"},"color":{"description":"Hex color code for the tag (e.g., \"#FF5733\").","type":"string"}}}},"translatedLocales":{"description":"Locales for which a translation exists in content__post_locale.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"viewsCount":{"description":"Cumulative number of times the post was served by /api/v1/post. Buffered in Redis and flushed into content__post.views_count every 5 min, so values may briefly lag.","type":"number"}}}},"itemCount":{"description":"Total number of posts matching the query (before pagination). Useful for pagination controls.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPostList","tags":["Post"],"summary":"List posts","description":"Returns a paginated list of posts for the authenticated organisation. Default ordering: starred-first, archived-last, then newest published. Each post includes basic metadata, derived publication status, word count, reading time, main image URL, and associated tags."}},"/bff/post/detail":{"get":{"parameters":[{"description":"Post external ID.","examples":["aBcDeFgH12345678"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Post external ID.","type":"string"},"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"metaTitle":{"description":"SEO `<title>` for the displayed locale. Empty string when not set.","type":"string"},"metaDescription":{"description":"SEO `<meta description>` for the displayed locale. Empty string when not set.","type":"string"},"visibility":{"description":"Post visibility level.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"status":{"description":"Computed publication status (draft/scheduled/published/private/archived).","anyOf":[{"const":"draft","type":"string"},{"const":"scheduled","type":"string"},{"const":"published","type":"string"},{"const":"private","type":"string"},{"const":"archived","type":"string"}]},"mainCategoryId":{"description":"External ID of the main category.","type":"string"},"authorIds":{"description":"Ordered list of author IDs. First is the main author.","type":"array","items":{"description":"Author external ID (customer/contact CU reference).","type":"string"}},"isStar":{"description":"Whether the post is starred/featured.","type":"boolean"},"publishedDate":{"description":"Date when the post was published.","anyOf":[{"description":"Date when the post was published.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the post was created.","anyOf":[{"description":"Date when the post was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when the post was last updated.","anyOf":[{"description":"Date when the post was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"wordCount":{"description":"Approximate word count of the displayed locale's content.","type":"number"},"readingTimeMinutes":{"description":"Approximate reading time in minutes (200 wpm). 0 when the post has no content.","type":"number"},"translatedLocales":{"description":"Locales for which a translation exists in content__post_locale.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"viewsCount":{"description":"Cumulative number of times the post was served by /api/v1/post. Buffered in Redis and flushed into content__post.views_count every 5 min, so values may briefly lag.","type":"number"}},"required":["id","title","content","perex","metaTitle","metaDescription","visibility","status","authorIds","isStar","insertedDate","updatedDate","wordCount","readingTimeMinutes","translatedLocales","viewsCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Post external ID.","type":"string"},"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"metaTitle":{"description":"SEO `<title>` for the displayed locale. Empty string when not set.","type":"string"},"metaDescription":{"description":"SEO `<meta description>` for the displayed locale. Empty string when not set.","type":"string"},"visibility":{"description":"Post visibility level.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"status":{"description":"Computed publication status (draft/scheduled/published/private/archived).","anyOf":[{"const":"draft","type":"string"},{"const":"scheduled","type":"string"},{"const":"published","type":"string"},{"const":"private","type":"string"},{"const":"archived","type":"string"}]},"mainCategoryId":{"description":"External ID of the main category.","type":"string"},"authorIds":{"description":"Ordered list of author IDs. First is the main author.","type":"array","items":{"description":"Author external ID (customer/contact CU reference).","type":"string"}},"isStar":{"description":"Whether the post is starred/featured.","type":"boolean"},"publishedDate":{"description":"Date when the post was published.","anyOf":[{"description":"Date when the post was published.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the post was created.","anyOf":[{"description":"Date when the post was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when the post was last updated.","anyOf":[{"description":"Date when the post was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"wordCount":{"description":"Approximate word count of the displayed locale's content.","type":"number"},"readingTimeMinutes":{"description":"Approximate reading time in minutes (200 wpm). 0 when the post has no content.","type":"number"},"translatedLocales":{"description":"Locales for which a translation exists in content__post_locale.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"viewsCount":{"description":"Cumulative number of times the post was served by /api/v1/post. Buffered in Redis and flushed into content__post.views_count every 5 min, so values may briefly lag.","type":"number"}},"required":["id","title","content","perex","metaTitle","metaDescription","visibility","status","authorIds","isStar","insertedDate","updatedDate","wordCount","readingTimeMinutes","translatedLocales","viewsCount"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Post external ID.","type":"string"},"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"metaTitle":{"description":"SEO `<title>` for the displayed locale. Empty string when not set.","type":"string"},"metaDescription":{"description":"SEO `<meta description>` for the displayed locale. Empty string when not set.","type":"string"},"visibility":{"description":"Post visibility level.","anyOf":[{"const":"public","type":"string"},{"const":"private","type":"string"},{"const":"unlisted","type":"string"},{"const":"subscribe","type":"string"}]},"status":{"description":"Computed publication status (draft/scheduled/published/private/archived).","anyOf":[{"const":"draft","type":"string"},{"const":"scheduled","type":"string"},{"const":"published","type":"string"},{"const":"private","type":"string"},{"const":"archived","type":"string"}]},"mainCategoryId":{"description":"External ID of the main category.","type":"string"},"authorIds":{"description":"Ordered list of author IDs. First is the main author.","type":"array","items":{"description":"Author external ID (customer/contact CU reference).","type":"string"}},"isStar":{"description":"Whether the post is starred/featured.","type":"boolean"},"publishedDate":{"description":"Date when the post was published.","anyOf":[{"description":"Date when the post was published.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when the post was created.","anyOf":[{"description":"Date when the post was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when the post was last updated.","anyOf":[{"description":"Date when the post was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"wordCount":{"description":"Approximate word count of the displayed locale's content.","type":"number"},"readingTimeMinutes":{"description":"Approximate reading time in minutes (200 wpm). 0 when the post has no content.","type":"number"},"translatedLocales":{"description":"Locales for which a translation exists in content__post_locale.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"viewsCount":{"description":"Cumulative number of times the post was served by /api/v1/post. Buffered in Redis and flushed into content__post.views_count every 5 min, so values may briefly lag.","type":"number"}},"required":["id","title","content","perex","metaTitle","metaDescription","visibility","status","authorIds","isStar","insertedDate","updatedDate","wordCount","readingTimeMinutes","translatedLocales","viewsCount"]}}}}},"operationId":"getBffPostDetail","tags":["Post"],"summary":"Get post detail","description":"Returns full post detail including title, content, visibility, authors, and available translations. Content is returned in the default locale (or first available translation)."}},"/bff/post/export-pdf":{"get":{"parameters":[{"description":"Post external ID.","examples":["aBcDeFgH12345678"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"operationId":"getBffPostExport-pdf","tags":["Post"],"summary":"Export post as PDF","description":"Renders the post as a printable A4 PDF (title, perex, metadata, HTML body and external-id reference) and returns the binary inline so the browser displays it in a new tab. Not persisted to blob storage.","responses":{"200":{}}}},"/bff/post/add":{"post":{"parameters":[],"operationId":"postBffPostAdd","tags":["Post"],"summary":"Create a new post","description":"Creates a new post for the authenticated organisation. The authenticated member is set as the main author. Returns the external ID of the created post.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content","visibility","locale"],"properties":{"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"visibility":{"description":"Post visibility level: public, private, unlisted, or subscribe.","type":"string"},"mainCategory":{"description":"Code of the main category to assign.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["title","content","visibility","locale"],"properties":{"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"visibility":{"description":"Post visibility level: public, private, unlisted, or subscribe.","type":"string"},"mainCategory":{"description":"Code of the main category to assign.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["title","content","visibility","locale"],"properties":{"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"visibility":{"description":"Post visibility level: public, private, unlisted, or subscribe.","type":"string"},"mainCategory":{"description":"Code of the main category to assign.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/post/save":{"post":{"parameters":[],"operationId":"postBffPostSave","tags":["Post"],"summary":"Update an existing post","description":"Saves changes to an existing post including title, content, visibility, category, authors, and publish date. The content is saved for the specified locale.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["locale","id","title","content","visibility","authorIds"],"properties":{"locale":{"description":"Locale code for the content being saved (e.g. \"cs\", \"en\").","type":"string"},"id":{"description":"Post external ID.","type":"string"},"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"metaTitle":{"description":"SEO <title> for the locale. Empty string clears it. Omit to leave unchanged.","type":"string"},"metaDescription":{"description":"SEO <meta description> for the locale. Empty string clears it. Omit to leave unchanged.","type":"string"},"visibility":{"description":"Post visibility level: public, private, unlisted, or subscribe.","type":"string"},"mainCategoryId":{"description":"External ID of the main category to assign.","type":"string"},"authorIds":{"description":"Ordered list of author external IDs. First is the main author.","type":"array","items":{"description":"Author external ID.","type":"string"}},"publishedDate":{"description":"ISO date string for the publish date. Omit or null to leave unpublished.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["locale","id","title","content","visibility","authorIds"],"properties":{"locale":{"description":"Locale code for the content being saved (e.g. \"cs\", \"en\").","type":"string"},"id":{"description":"Post external ID.","type":"string"},"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"metaTitle":{"description":"SEO <title> for the locale. Empty string clears it. Omit to leave unchanged.","type":"string"},"metaDescription":{"description":"SEO <meta description> for the locale. Empty string clears it. Omit to leave unchanged.","type":"string"},"visibility":{"description":"Post visibility level: public, private, unlisted, or subscribe.","type":"string"},"mainCategoryId":{"description":"External ID of the main category to assign.","type":"string"},"authorIds":{"description":"Ordered list of author external IDs. First is the main author.","type":"array","items":{"description":"Author external ID.","type":"string"}},"publishedDate":{"description":"ISO date string for the publish date. Omit or null to leave unpublished.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["locale","id","title","content","visibility","authorIds"],"properties":{"locale":{"description":"Locale code for the content being saved (e.g. \"cs\", \"en\").","type":"string"},"id":{"description":"Post external ID.","type":"string"},"title":{"description":"Post title.","type":"string"},"content":{"description":"Post content (HTML).","type":"string"},"perex":{"description":"Short summary/teaser of the post.","type":"string"},"metaTitle":{"description":"SEO <title> for the locale. Empty string clears it. Omit to leave unchanged.","type":"string"},"metaDescription":{"description":"SEO <meta description> for the locale. Empty string clears it. Omit to leave unchanged.","type":"string"},"visibility":{"description":"Post visibility level: public, private, unlisted, or subscribe.","type":"string"},"mainCategoryId":{"description":"External ID of the main category to assign.","type":"string"},"authorIds":{"description":"Ordered list of author external IDs. First is the main author.","type":"array","items":{"description":"Author external ID.","type":"string"}},"publishedDate":{"description":"ISO date string for the publish date. Omit or null to leave unpublished.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/post/post-gallery-link-blob":{"get":{"parameters":[{"description":"Post external ID.","examples":["a1b2c3d4-e5f6-7890"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Blob token of the uploaded file to link.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the image was linked successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the image was linked successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the image was linked successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffPostPost-gallery-link-blob","tags":["Post"],"summary":"Add image to post gallery","description":"Links an uploaded blob to the post gallery. The image is appended at the end of the gallery. If the post has no main image yet, this image is automatically set as main."}},"/bff/post/post-gallery-list":{"get":{"parameters":[{"description":"Post external ID.","examples":["a1b2c3d4-e5f6-7890"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Gallery images sorted by active status then position.","type":"array","items":{"type":"object","required":["blob","title","position","deleted","active"],"properties":{"id":{"description":"Blob token (used as image identifier in other endpoints).","type":"string"},"url":{"description":"External URL if the media is not a blob.","type":"string"},"blob":{"description":"Blob file metadata (filename, URL, dimensions, size)."},"title":{"description":"Image alt text / title.","type":"string"},"position":{"description":"Display order position (1-based).","type":"number"},"deleted":{"description":"Whether the image is soft-deleted.","type":"boolean"},"active":{"description":"Whether the image is active (visible on the public site).","type":"boolean"}}}},"mainImageId":{"description":"Blob token of the current main/featured image.","type":"string"},"itemCount":{"description":"Total number of non-deleted images in the gallery.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Gallery images sorted by active status then position.","type":"array","items":{"type":"object","required":["blob","title","position","deleted","active"],"properties":{"id":{"description":"Blob token (used as image identifier in other endpoints).","type":"string"},"url":{"description":"External URL if the media is not a blob.","type":"string"},"blob":{"description":"Blob file metadata (filename, URL, dimensions, size)."},"title":{"description":"Image alt text / title.","type":"string"},"position":{"description":"Display order position (1-based).","type":"number"},"deleted":{"description":"Whether the image is soft-deleted.","type":"boolean"},"active":{"description":"Whether the image is active (visible on the public site).","type":"boolean"}}}},"mainImageId":{"description":"Blob token of the current main/featured image.","type":"string"},"itemCount":{"description":"Total number of non-deleted images in the gallery.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Gallery images sorted by active status then position.","type":"array","items":{"type":"object","required":["blob","title","position","deleted","active"],"properties":{"id":{"description":"Blob token (used as image identifier in other endpoints).","type":"string"},"url":{"description":"External URL if the media is not a blob.","type":"string"},"blob":{"description":"Blob file metadata (filename, URL, dimensions, size)."},"title":{"description":"Image alt text / title.","type":"string"},"position":{"description":"Display order position (1-based).","type":"number"},"deleted":{"description":"Whether the image is soft-deleted.","type":"boolean"},"active":{"description":"Whether the image is active (visible on the public site).","type":"boolean"}}}},"mainImageId":{"description":"Blob token of the current main/featured image.","type":"string"},"itemCount":{"description":"Total number of non-deleted images in the gallery.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPostPost-gallery-list","tags":["Post"],"summary":"List post gallery images","description":"Returns all non-deleted images in the post gallery sorted by active status and position. Includes blob metadata (URL, dimensions) and identifies the main/featured image."}},"/bff/post/post-image-active-toggle":{"get":{"parameters":[{"description":"Post external ID.","examples":["a1b2c3d4-e5f6-7890"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Blob token of the image to toggle.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"imageId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the toggle was successful.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the toggle was successful.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the toggle was successful.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffPostPost-image-active-toggle","tags":["Post"],"summary":"Toggle image active status","description":"Toggles the active/inactive status of a gallery image. Inactive images are hidden on the public site but remain in the gallery for re-activation. If the main image is deactivated, the first remaining active image becomes the new main."}},"/bff/post/post-image-delete":{"get":{"parameters":[{"description":"Post external ID.","examples":["a1b2c3d4-e5f6-7890"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Blob token of the image to delete.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"imageId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the deletion was successful.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the deletion was successful.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the deletion was successful.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffPostPost-image-delete","tags":["Post"],"summary":"Delete gallery image","description":"Soft-deletes an image from the post gallery (sets deleted flag, does not remove the blob). If the deleted image was the main image, the first remaining active image becomes the new main."}},"/bff/post/post-image-mark-main":{"get":{"parameters":[{"description":"Post external ID.","examples":["a1b2c3d4-e5f6-7890"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Blob token of the image to set as main.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"imageId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffPostPost-image-mark-main","tags":["Post"],"summary":"Set main post image","description":"Sets the specified image as the main/featured image for the post. The main image is used as the post thumbnail in lists and social sharing."}},"/bff/post/post-image-update-meta":{"get":{"parameters":[{"description":"Post external ID.","examples":["a1b2c3d4-e5f6-7890"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Blob token of the image to update.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"imageId","required":true},{"description":"New alt text / title for the image (used for SEO and accessibility).","examples":["Sunset over Prague Castle"],"schema":{"type":"string"},"in":"query","name":"title","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the metadata was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the metadata was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the metadata was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffPostPost-image-update-meta","tags":["Post"],"summary":"Update image metadata","description":"Updates the alt text / title of a gallery image. Alt text is important for SEO and accessibility. Pass an empty string to clear it."}},"/bff/post/post-toggle-star":{"post":{"parameters":[],"operationId":"postBffPostPost-toggle-star","tags":["Post"],"summary":"Toggle post star status","description":"Sets or clears the starred/featured flag on a post. Starred posts appear first in the post list.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","value"],"properties":{"id":{"description":"Post external ID.","type":"string"},"value":{"description":"True to star the post, false to unstar it.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","value"],"properties":{"id":{"description":"Post external ID.","type":"string"},"value":{"description":"True to star the post, false to unstar it.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id","value"],"properties":{"id":{"description":"Post external ID.","type":"string"},"value":{"description":"True to star the post, false to unstar it.","type":"boolean"}}}}}},"responses":{"200":{}}}},"/bff/post/post-auto-translate":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"translatedLocales":{"description":"List of locale codes that were translated. Empty if all locales already had translations.","type":"array","items":{"description":"Locale code that was translated (e.g. \"en\", \"de\").","type":"string"}}},"required":["translatedLocales"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"translatedLocales":{"description":"List of locale codes that were translated. Empty if all locales already had translations.","type":"array","items":{"description":"Locale code that was translated (e.g. \"en\", \"de\").","type":"string"}}},"required":["translatedLocales"]}},"text/plain":{"schema":{"type":"object","properties":{"translatedLocales":{"description":"List of locale codes that were translated. Empty if all locales already had translations.","type":"array","items":{"description":"Locale code that was translated (e.g. \"en\", \"de\").","type":"string"}}},"required":["translatedLocales"]}}}}},"operationId":"postBffPostPost-auto-translate","tags":["Post"],"summary":"Auto-translate post","description":"Automatically translates the post title and content from the organisation default locale to all other configured organisation locales that do not have a translation yet. Each locale is translated individually. Canonical routes are created for locales that do not have one, using the translated title as slug.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["postId"],"properties":{"postId":{"description":"Post external ID to auto-translate.","examples":["aBcDeFgH12345678"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["postId"],"properties":{"postId":{"description":"Post external ID to auto-translate.","examples":["aBcDeFgH12345678"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["postId"],"properties":{"postId":{"description":"Post external ID to auto-translate.","examples":["aBcDeFgH12345678"],"type":"string"}}}}}}}},"/bff/post/resolve-category-by-ai":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"changed":{"description":"Whether the category was changed.","type":"boolean"},"category":{"nullable":true,"anyOf":[{"type":"object","required":["categoryId","categoryName"],"properties":{"categoryId":{"description":"Internal ID of the selected category.","type":"number"},"categoryName":{"description":"Name of the selected category.","type":"string"}}},{"type":"null"}]}},"required":["success","changed","category"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"changed":{"description":"Whether the category was changed.","type":"boolean"},"category":{"nullable":true,"anyOf":[{"type":"object","required":["categoryId","categoryName"],"properties":{"categoryId":{"description":"Internal ID of the selected category.","type":"number"},"categoryName":{"description":"Name of the selected category.","type":"string"}}},{"type":"null"}]}},"required":["success","changed","category"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"changed":{"description":"Whether the category was changed.","type":"boolean"},"category":{"nullable":true,"anyOf":[{"type":"object","required":["categoryId","categoryName"],"properties":{"categoryId":{"description":"Internal ID of the selected category.","type":"number"},"categoryName":{"description":"Name of the selected category.","type":"string"}}},{"type":"null"}]}},"required":["success","changed","category"]}}}}},"operationId":"postBffPostResolve-category-by-ai","tags":["Post"],"summary":"Auto-categorize post by AI","description":"Uses AI to analyze the post title and content and select the best matching category from all active categories in the organisation. If no category is a good fit, the current category remains unchanged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["postId"],"properties":{"postId":{"description":"Post external ID.","examples":["aBcDeFgH12345678"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["postId"],"properties":{"postId":{"description":"Post external ID.","examples":["aBcDeFgH12345678"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["postId"],"properties":{"postId":{"description":"Post external ID.","examples":["aBcDeFgH12345678"],"type":"string"}}}}}}}},"/bff/post/delete":{"post":{"parameters":[],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}}}}},"operationId":"postBffPostDelete","tags":["Post"],"summary":"Soft-delete a post","description":"Sets deleted_date on the post. The post is hidden from all public views but remains in the admin list.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Post external ID to soft-delete.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Post external ID to soft-delete.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Post external ID to soft-delete.","type":"string"}}}}}}}},"/bff/post/restore":{"post":{"parameters":[],"responses":{"200":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}],"content":{"application/json":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"multipart/form-data":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}},"text/plain":{"schema":{"anyOf":[{"type":"object","required":["success"],"properties":{"success":{"const":true,"type":"boolean"}}},{"type":"object","required":["success","message"],"properties":{"success":{"const":false,"type":"boolean"},"message":{"type":"string"}}}]}}}}},"operationId":"postBffPostRestore","tags":["Post"],"summary":"Restore a soft-deleted post","description":"Clears deleted_date on the post, making it visible again in public views.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Post external ID to restore.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Post external ID to restore.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Post external ID to restore.","type":"string"}}}}}}}},"/bff/post/history-list":{"get":{"parameters":[{"description":"Post external ID.","examples":["aBcDeFgH12345678"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Optional locale filter (e.g. \"cs\", \"en\"). When omitted, the response mixes all languages. Each entry always carries its own `locale` field regardless.","examples":["cs"],"schema":{"type":"string"},"in":"query","name":"locale","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"postId":{"description":"Echo of the post external id the history belongs to.","type":"string"},"locale":{"nullable":true,"anyOf":[{"description":"Echo of the locale filter, or null when none was applied.","type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["id","insertedDate","locale","title","commitMessage","contentSize","author"],"properties":{"id":{"description":"History version handle (16 chars). Pass to /history-detail.","type":"string"},"insertedDate":{"description":"When this revision was recorded.","anyOf":[{"description":"When this revision was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locale":{"description":"Locale code of this revision (e.g. \"cs\", \"en\").","type":"string"},"title":{"description":"Snapshot of the post title at this revision.","type":"string"},"commitMessage":{"nullable":true,"anyOf":[{"description":"Optional human commit message; null for auto-versions.","type":"string"},{"type":"null"}]},"contentSize":{"description":"Byte size of the content blob.","type":"number"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"description":"cuRefNo of the author contact.","type":"string"},{"type":"null"}]},"name":{"description":"Display name of the author.","type":"string"}}}}}}},"required":["postId","locale","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"postId":{"description":"Echo of the post external id the history belongs to.","type":"string"},"locale":{"nullable":true,"anyOf":[{"description":"Echo of the locale filter, or null when none was applied.","type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["id","insertedDate","locale","title","commitMessage","contentSize","author"],"properties":{"id":{"description":"History version handle (16 chars). Pass to /history-detail.","type":"string"},"insertedDate":{"description":"When this revision was recorded.","anyOf":[{"description":"When this revision was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locale":{"description":"Locale code of this revision (e.g. \"cs\", \"en\").","type":"string"},"title":{"description":"Snapshot of the post title at this revision.","type":"string"},"commitMessage":{"nullable":true,"anyOf":[{"description":"Optional human commit message; null for auto-versions.","type":"string"},{"type":"null"}]},"contentSize":{"description":"Byte size of the content blob.","type":"number"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"description":"cuRefNo of the author contact.","type":"string"},{"type":"null"}]},"name":{"description":"Display name of the author.","type":"string"}}}}}}},"required":["postId","locale","items"]}},"text/plain":{"schema":{"type":"object","properties":{"postId":{"description":"Echo of the post external id the history belongs to.","type":"string"},"locale":{"nullable":true,"anyOf":[{"description":"Echo of the locale filter, or null when none was applied.","type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["id","insertedDate","locale","title","commitMessage","contentSize","author"],"properties":{"id":{"description":"History version handle (16 chars). Pass to /history-detail.","type":"string"},"insertedDate":{"description":"When this revision was recorded.","anyOf":[{"description":"When this revision was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"locale":{"description":"Locale code of this revision (e.g. \"cs\", \"en\").","type":"string"},"title":{"description":"Snapshot of the post title at this revision.","type":"string"},"commitMessage":{"nullable":true,"anyOf":[{"description":"Optional human commit message; null for auto-versions.","type":"string"},{"type":"null"}]},"contentSize":{"description":"Byte size of the content blob.","type":"number"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"description":"cuRefNo of the author contact.","type":"string"},{"type":"null"}]},"name":{"description":"Display name of the author.","type":"string"}}}}}}},"required":["postId","locale","items"]}}}}},"operationId":"getBffPostHistory-list","tags":["Post"],"summary":"List post version history","description":"Returns the commit log for a post: every revision recorded in content__post_history, newest first. Each item carries the version handle, timestamp, locale, author, optional commit message, snapshot title and the byte size of the stored content blob (so the UI can render \"1.2 MB\" without fetching the body). The actual HTML body lives in blob storage and is only loaded by /history-detail. Pass `?locale=cs` to scope to one language."}},"/bff/post/history-detail":{"get":{"parameters":[{"description":"History version handle returned by /history-list.","examples":["vErSiOnHaNdLe123"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"History version handle (echo).","type":"string"},"postId":{"description":"External id of the parent post.","type":"string"},"locale":{"description":"Locale code of this revision.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"content":{"description":"Full HTML content snapshot at this revision.","type":"string"},"contentSize":{"type":"number"},"commitMessage":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}},"required":["id","postId","locale","insertedDate","title","content","contentSize","commitMessage","author"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"History version handle (echo).","type":"string"},"postId":{"description":"External id of the parent post.","type":"string"},"locale":{"description":"Locale code of this revision.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"content":{"description":"Full HTML content snapshot at this revision.","type":"string"},"contentSize":{"type":"number"},"commitMessage":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}},"required":["id","postId","locale","insertedDate","title","content","contentSize","commitMessage","author"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"History version handle (echo).","type":"string"},"postId":{"description":"External id of the parent post.","type":"string"},"locale":{"description":"Locale code of this revision.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"content":{"description":"Full HTML content snapshot at this revision.","type":"string"},"contentSize":{"type":"number"},"commitMessage":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}},"required":["id","postId","locale","insertedDate","title","content","contentSize","commitMessage","author"]}}}}},"operationId":"getBffPostHistory-detail","tags":["Post"],"summary":"Get post history version detail","description":"Returns one specific revision in full, with the title and HTML content snapshot (content body is fetched from blob storage on demand)."}},"/bff/post/history-restore":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"postId":{"description":"External id of the post that was restored.","type":"string"},"locale":{"description":"Locale code that was restored.","type":"string"},"restoredFromVersionId":{"description":"External id of the source revision (the snapshot put back live).","type":"string"},"newVersionId":{"description":"External id of the new history entry created by the restore. Use this to roll the restore back via another /history-restore call.","type":"string"}},"required":["success","postId","locale","restoredFromVersionId","newVersionId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"postId":{"description":"External id of the post that was restored.","type":"string"},"locale":{"description":"Locale code that was restored.","type":"string"},"restoredFromVersionId":{"description":"External id of the source revision (the snapshot put back live).","type":"string"},"newVersionId":{"description":"External id of the new history entry created by the restore. Use this to roll the restore back via another /history-restore call.","type":"string"}},"required":["success","postId","locale","restoredFromVersionId","newVersionId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"postId":{"description":"External id of the post that was restored.","type":"string"},"locale":{"description":"Locale code that was restored.","type":"string"},"restoredFromVersionId":{"description":"External id of the source revision (the snapshot put back live).","type":"string"},"newVersionId":{"description":"External id of the new history entry created by the restore. Use this to roll the restore back via another /history-restore call.","type":"string"}},"required":["success","postId","locale","restoredFromVersionId","newVersionId"]}}}}},"operationId":"postBffPostHistory-restore","tags":["Post"],"summary":"Restore a post to a historical revision","description":"Overwrites the live `content__post_locale` row for the post + locale of the source revision with that revision's title and content body, then writes a new history entry (\"Restored from version X\") authored by the caller.\n\nThe restore is itself a versioned act — the new history entry it produces can be the target of a later restore, so an \"undo my undo\" is just another /history-restore call. Coalescing is disabled for restore writes so they always land as distinct landmarks in the commit log even if the same author was editing seconds before.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"History version handle to restore (16 chars).","examples":["vErSiOnHaNdLe123"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"History version handle to restore (16 chars).","examples":["vErSiOnHaNdLe123"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"History version handle to restore (16 chars).","examples":["vErSiOnHaNdLe123"],"type":"string"}}}}}}}},"/bff/post/history-diff":{"get":{"parameters":[{"description":"Older revision handle (left side of the diff).","examples":["vErSiOnHaNdLe123"],"schema":{"type":"string"},"in":"query","name":"from","required":true},{"description":"Newer revision handle (right side of the diff).","examples":["vErSiOnHaNdLe456"],"schema":{"type":"string"},"in":"query","name":"to","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"description":"Version handle.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"to":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"description":"Version handle.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"titleDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"description":"context = unchanged region, add = present only in `to`, remove = present only in `from`.","anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"description":"Verbatim slice of the document. Whitespace preserved.","type":"string"}}}},"contentDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"description":"context = unchanged region, add = present only in `to`, remove = present only in `from`.","anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"description":"Verbatim slice of the document. Whitespace preserved.","type":"string"}}}},"stats":{"type":"object","required":["titleAdded","titleRemoved","contentAddedLines","contentRemovedLines"],"properties":{"titleAdded":{"description":"Words added to the title.","type":"number"},"titleRemoved":{"description":"Words removed from the title.","type":"number"},"contentAddedLines":{"description":"Lines added to the content.","type":"number"},"contentRemovedLines":{"description":"Lines removed from the content.","type":"number"}}}},"required":["from","to","titleDiff","contentDiff","stats"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"from":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"description":"Version handle.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"to":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"description":"Version handle.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"titleDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"description":"context = unchanged region, add = present only in `to`, remove = present only in `from`.","anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"description":"Verbatim slice of the document. Whitespace preserved.","type":"string"}}}},"contentDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"description":"context = unchanged region, add = present only in `to`, remove = present only in `from`.","anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"description":"Verbatim slice of the document. Whitespace preserved.","type":"string"}}}},"stats":{"type":"object","required":["titleAdded","titleRemoved","contentAddedLines","contentRemovedLines"],"properties":{"titleAdded":{"description":"Words added to the title.","type":"number"},"titleRemoved":{"description":"Words removed from the title.","type":"number"},"contentAddedLines":{"description":"Lines added to the content.","type":"number"},"contentRemovedLines":{"description":"Lines removed from the content.","type":"number"}}}},"required":["from","to","titleDiff","contentDiff","stats"]}},"text/plain":{"schema":{"type":"object","properties":{"from":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"description":"Version handle.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"to":{"type":"object","required":["id","insertedDate","title","contentSize","locale","author"],"properties":{"id":{"description":"Version handle.","type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"title":{"type":"string"},"contentSize":{"type":"number"},"locale":{"type":"string"},"author":{"type":"object","required":["id","name"],"properties":{"id":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}}}}},"titleDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"description":"context = unchanged region, add = present only in `to`, remove = present only in `from`.","anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"description":"Verbatim slice of the document. Whitespace preserved.","type":"string"}}}},"contentDiff":{"type":"array","items":{"type":"object","required":["type","value"],"properties":{"type":{"description":"context = unchanged region, add = present only in `to`, remove = present only in `from`.","anyOf":[{"const":"context","type":"string"},{"const":"add","type":"string"},{"const":"remove","type":"string"}]},"value":{"description":"Verbatim slice of the document. Whitespace preserved.","type":"string"}}}},"stats":{"type":"object","required":["titleAdded","titleRemoved","contentAddedLines","contentRemovedLines"],"properties":{"titleAdded":{"description":"Words added to the title.","type":"number"},"titleRemoved":{"description":"Words removed from the title.","type":"number"},"contentAddedLines":{"description":"Lines added to the content.","type":"number"},"contentRemovedLines":{"description":"Lines removed from the content.","type":"number"}}}},"required":["from","to","titleDiff","contentDiff","stats"]}}}}},"operationId":"getBffPostHistory-diff","tags":["Post"],"summary":"Diff two post revisions","description":"Returns a structured diff between two revisions of the same post + locale. Title is word-grain (titles are short, word grain reads naturally), content is line-grain (HTML/markdown bodies — line grain keeps block edits readable). Both revisions must belong to the same post and locale; cross-post or cross-locale diffs are rejected as caller errors."}},"/bff/post/comment-list":{"get":{"parameters":[{"description":"Optional post external_id. When set, only comments under that post are returned. Used by the post-detail \"Comments\" tab.","examples":["aBcDeFgH12345678"],"schema":{"type":"string"},"in":"query","name":"postId","required":false}],"responses":{"200":{"description":"Paginated list of comments.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","postId","postTitle","authorId","authorName","authorEmail","content","insertedDate","isDeleted"],"properties":{"id":{"description":"Comment ID.","type":"string"},"postId":{"description":"External ID of the post this comment belongs to.","type":"string"},"postTitle":{"description":"Title of the post.","type":"string"},"authorId":{"description":"External ID of the comment author (customer/contact).","type":"string"},"authorName":{"description":"Display name of the author.","type":"string"},"authorEmail":{"description":"Email of the author.","type":"string"},"content":{"description":"Comment text content.","type":"string"},"insertedDate":{"description":"ISO timestamp when the comment was created.","type":"string"},"isDeleted":{"description":"Whether the comment has been soft-deleted.","type":"boolean"}}}},"itemCount":{"description":"Total number of comments matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","postId","postTitle","authorId","authorName","authorEmail","content","insertedDate","isDeleted"],"properties":{"id":{"description":"Comment ID.","type":"string"},"postId":{"description":"External ID of the post this comment belongs to.","type":"string"},"postTitle":{"description":"Title of the post.","type":"string"},"authorId":{"description":"External ID of the comment author (customer/contact).","type":"string"},"authorName":{"description":"Display name of the author.","type":"string"},"authorEmail":{"description":"Email of the author.","type":"string"},"content":{"description":"Comment text content.","type":"string"},"insertedDate":{"description":"ISO timestamp when the comment was created.","type":"string"},"isDeleted":{"description":"Whether the comment has been soft-deleted.","type":"boolean"}}}},"itemCount":{"description":"Total number of comments matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","postId","postTitle","authorId","authorName","authorEmail","content","insertedDate","isDeleted"],"properties":{"id":{"description":"Comment ID.","type":"string"},"postId":{"description":"External ID of the post this comment belongs to.","type":"string"},"postTitle":{"description":"Title of the post.","type":"string"},"authorId":{"description":"External ID of the comment author (customer/contact).","type":"string"},"authorName":{"description":"Display name of the author.","type":"string"},"authorEmail":{"description":"Email of the author.","type":"string"},"content":{"description":"Comment text content.","type":"string"},"insertedDate":{"description":"ISO timestamp when the comment was created.","type":"string"},"isDeleted":{"description":"Whether the comment has been soft-deleted.","type":"boolean"}}}},"itemCount":{"description":"Total number of comments matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPostComment-list","tags":["Post"],"summary":"List post comments","description":"Returns a paginated list of comments for the authenticated organisation. Without `postId`, returns comments across all posts. With `postId`, scopes to one post. Comments are ordered by inserted date (newest first). Supports standard datagrid pagination via ?page= and ?limit= query params."}},"/bff/post/comment-delete":{"post":{"parameters":[],"operationId":"postBffPostComment-delete","tags":["Post"],"summary":"Delete a post comment","description":"Soft-deletes a comment by setting its deleted_date. The comment must exist and not be already deleted.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External ID of the comment to soft-delete.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External ID of the comment to soft-delete.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"External ID of the comment to soft-delete.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/post/category-opportunities":{"get":{"parameters":[{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"categories":{"type":"array","items":{"type":"object","required":["externalId","name","description","totalPublished","daysSinceLastPost","opportunityScore","recommended"],"properties":{"externalId":{"type":"string"},"name":{"type":"string"},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"totalPublished":{"type":"number"},"daysSinceLastPost":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"opportunityScore":{"type":"number"},"recommended":{"type":"boolean"}}}}},"required":["success","categories"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"categories":{"type":"array","items":{"type":"object","required":["externalId","name","description","totalPublished","daysSinceLastPost","opportunityScore","recommended"],"properties":{"externalId":{"type":"string"},"name":{"type":"string"},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"totalPublished":{"type":"number"},"daysSinceLastPost":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"opportunityScore":{"type":"number"},"recommended":{"type":"boolean"}}}}},"required":["success","categories"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"categories":{"type":"array","items":{"type":"object","required":["externalId","name","description","totalPublished","daysSinceLastPost","opportunityScore","recommended"],"properties":{"externalId":{"type":"string"},"name":{"type":"string"},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"totalPublished":{"type":"number"},"daysSinceLastPost":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"opportunityScore":{"type":"number"},"recommended":{"type":"boolean"}}}}},"required":["success","categories"]}}}}},"operationId":"getBffPostCategory-opportunities","tags":["Post"],"summary":"Per-category opportunity score for AI topic brainstorming","description":"Returns all active categories with totalPublished, daysSinceLastPost, opportunityScore and a recommended flag. Pure DB heuristic (no AI call). Used by the admin AI topic modal to pre-select categories with the biggest content gaps when the user clicks \"Recommend\"."}},"/bff/post/ai-suggest-topics":{"post":{"parameters":[],"operationId":"postBffPostAi-suggest-topics","tags":["Post"],"summary":"AI-suggest blog topics from existing categories and recent titles","description":"Reads the active categories (optionally restricted to a subset) and the most recent public article titles per category, then asks the AI to brainstorm fresh topic ideas that fill content gaps. Synchronous: typical response time 5-15s. Token usage is logged automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["locale"],"properties":{"categoryExternalIds":{"description":"Restrict brainstorming to these category externalIds. Omit for all active categories.","type":"array","items":{"minLength":1,"maxLength":32,"type":"string"}},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"count":{"minimum":3,"maximum":12,"description":"How many topic ideas the AI should return (default 6).","anyOf":[{"format":"integer","default":0,"type":"string"},{"minimum":3,"maximum":12,"description":"How many topic ideas the AI should return (default 6).","type":"integer"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["locale"],"properties":{"categoryExternalIds":{"description":"Restrict brainstorming to these category externalIds. Omit for all active categories.","type":"array","items":{"minLength":1,"maxLength":32,"type":"string"}},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"count":{"minimum":3,"maximum":12,"description":"How many topic ideas the AI should return (default 6).","anyOf":[{"format":"integer","default":0,"type":"string"},{"minimum":3,"maximum":12,"description":"How many topic ideas the AI should return (default 6).","type":"integer"}]}}}},"text/plain":{"schema":{"type":"object","required":["locale"],"properties":{"categoryExternalIds":{"description":"Restrict brainstorming to these category externalIds. Omit for all active categories.","type":"array","items":{"minLength":1,"maxLength":32,"type":"string"}},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"count":{"minimum":3,"maximum":12,"description":"How many topic ideas the AI should return (default 6).","anyOf":[{"format":"integer","default":0,"type":"string"},{"minimum":3,"maximum":12,"description":"How many topic ideas the AI should return (default 6).","type":"integer"}]}}}}}},"responses":{"200":{}}}},"/bff/post/ai-create-from-topic":{"post":{"parameters":[],"operationId":"postBffPostAi-create-from-topic","tags":["Post"],"summary":"AI-generate a private draft article from a suggested topic","description":"Drafts the full article body via AI (title, perex, content as Markdown), saves it as a private draft (visibility=private, published_date=NULL) via the existing addPost() pipeline. Returns the new post externalId so the caller can redirect to /post/<id>. Synchronous: typical 15-40s.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["topicTitle","topicAngle","categoryExternalId","locale"],"properties":{"topicTitle":{"minLength":3,"maxLength":300,"description":"Selected topic title from /ai-suggest-topics.","type":"string"},"topicAngle":{"minLength":3,"maxLength":500,"description":"Editorial angle/hook for the topic.","type":"string"},"categoryExternalId":{"minLength":1,"maxLength":32,"description":"External ID of the category the article belongs to.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["topicTitle","topicAngle","categoryExternalId","locale"],"properties":{"topicTitle":{"minLength":3,"maxLength":300,"description":"Selected topic title from /ai-suggest-topics.","type":"string"},"topicAngle":{"minLength":3,"maxLength":500,"description":"Editorial angle/hook for the topic.","type":"string"},"categoryExternalId":{"minLength":1,"maxLength":32,"description":"External ID of the category the article belongs to.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["topicTitle","topicAngle","categoryExternalId","locale"],"properties":{"topicTitle":{"minLength":3,"maxLength":300,"description":"Selected topic title from /ai-suggest-topics.","type":"string"},"topicAngle":{"minLength":3,"maxLength":500,"description":"Editorial angle/hook for the topic.","type":"string"},"categoryExternalId":{"minLength":1,"maxLength":32,"description":"External ID of the category the article belongs to.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/post/ai-fact-check":{"post":{"parameters":[],"operationId":"postBffPostAi-fact-check","tags":["Post"],"summary":"AI fact-check of an existing post","description":"Reads the post body for the given locale and asks AI to flag major factual errors, fake news, and improvement recommendations. Each finding is grouped by category, scored by severity and carries a one-sentence justification (so the editor sees *why*, not just *what*). The endpoint never rewrites the post — admin decides what to apply. Synchronous, ~15-40s. No response schema.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["postId","locale"],"properties":{"postId":{"description":"Post external ID.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["postId","locale"],"properties":{"postId":{"description":"Post external ID.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["postId","locale"],"properties":{"postId":{"description":"Post external ID.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/post/ai-apply-fact-check-fix":{"post":{"parameters":[],"operationId":"postBffPostAi-apply-fact-check-fix","tags":["Post"],"summary":"AI-apply a single fact-check finding to a post body","description":"Reads the full current article (title, perex, content) for the given locale, asks the AI to produce the **smallest possible** edit that addresses the supplied fact-check finding, and commits the result through the existing savePost() pipeline (so a normal version-history entry is created). The AI may decline to apply (sets applied=false) when the suggested fix is unsafe or ambiguous; in that case no DB write happens. Synchronous, ~15-30s. No response schema — hand-rolls the Response to dodge Elysia's auto-serialization edge cases on AI endpoints.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["postId","locale","finding"],"properties":{"postId":{"description":"Post external ID.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"finding":{"type":"object","required":["category","severity","issue","justification"],"properties":{"category":{"description":"\"error\" | \"falsehood\" | \"recommendation\"","type":"string"},"severity":{"description":"\"low\" | \"medium\" | \"high\"","type":"string"},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"issue":{"minLength":1,"maxLength":2000,"type":"string"},"justification":{"minLength":1,"maxLength":2000,"type":"string"},"suggestedFix":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["postId","locale","finding"],"properties":{"postId":{"description":"Post external ID.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"finding":{"type":"object","required":["category","severity","issue","justification"],"properties":{"category":{"description":"\"error\" | \"falsehood\" | \"recommendation\"","type":"string"},"severity":{"description":"\"low\" | \"medium\" | \"high\"","type":"string"},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"issue":{"minLength":1,"maxLength":2000,"type":"string"},"justification":{"minLength":1,"maxLength":2000,"type":"string"},"suggestedFix":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"text/plain":{"schema":{"type":"object","required":["postId","locale","finding"],"properties":{"postId":{"description":"Post external ID.","type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"finding":{"type":"object","required":["category","severity","issue","justification"],"properties":{"category":{"description":"\"error\" | \"falsehood\" | \"recommendation\"","type":"string"},"severity":{"description":"\"low\" | \"medium\" | \"high\"","type":"string"},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"issue":{"minLength":1,"maxLength":2000,"type":"string"},"justification":{"minLength":1,"maxLength":2000,"type":"string"},"suggestedFix":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"responses":{"200":{}}}},"/bff/post-category/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Filter by main category code.","examples":["blog"],"schema":{"type":"string"},"in":"query","name":"mainCategoryCode","required":false}],"responses":{"200":{"description":"Paginated list of post categories.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of category items matching the query criteria.","type":"array","items":{"description":"Single category item in the list.","type":"object","required":["id","title","insertedDate","active","postCount"],"properties":{"id":{"description":"Category external ID (16-char unique identifier).","examples":["abc123def456ghij"],"type":"string"},"parentId":{"description":"External ID of the parent category. Omitted for top-level categories.","examples":["abc123def456ghij"],"type":"string"},"title":{"description":"Localized category name, truncated to 140 characters for list view.","examples":["Tech News"],"type":"string"},"insertedDate":{"description":"Date when the category was created.","anyOf":[{"description":"Date when the category was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the category is currently active.","examples":[true],"type":"boolean"},"postCount":{"description":"Total number of posts in this category and all its descendant categories (recursive count).","examples":[42],"type":"number"}}}},"itemCount":{"description":"Total number of categories matching the query (before pagination).","examples":[15],"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of category items matching the query criteria.","type":"array","items":{"description":"Single category item in the list.","type":"object","required":["id","title","insertedDate","active","postCount"],"properties":{"id":{"description":"Category external ID (16-char unique identifier).","examples":["abc123def456ghij"],"type":"string"},"parentId":{"description":"External ID of the parent category. Omitted for top-level categories.","examples":["abc123def456ghij"],"type":"string"},"title":{"description":"Localized category name, truncated to 140 characters for list view.","examples":["Tech News"],"type":"string"},"insertedDate":{"description":"Date when the category was created.","anyOf":[{"description":"Date when the category was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the category is currently active.","examples":[true],"type":"boolean"},"postCount":{"description":"Total number of posts in this category and all its descendant categories (recursive count).","examples":[42],"type":"number"}}}},"itemCount":{"description":"Total number of categories matching the query (before pagination).","examples":[15],"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of category items matching the query criteria.","type":"array","items":{"description":"Single category item in the list.","type":"object","required":["id","title","insertedDate","active","postCount"],"properties":{"id":{"description":"Category external ID (16-char unique identifier).","examples":["abc123def456ghij"],"type":"string"},"parentId":{"description":"External ID of the parent category. Omitted for top-level categories.","examples":["abc123def456ghij"],"type":"string"},"title":{"description":"Localized category name, truncated to 140 characters for list view.","examples":["Tech News"],"type":"string"},"insertedDate":{"description":"Date when the category was created.","anyOf":[{"description":"Date when the category was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"active":{"description":"Whether the category is currently active.","examples":[true],"type":"boolean"},"postCount":{"description":"Total number of posts in this category and all its descendant categories (recursive count).","examples":[42],"type":"number"}}}},"itemCount":{"description":"Total number of categories matching the query (before pagination).","examples":[15],"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPost-categoryList","tags":["Post Category"],"summary":"List all post categories","description":"Returns a paginated list of all post categories for the organisation. Supports data grid query parameters for filtering and pagination."}},"/bff/post-category/list-selector":{"get":{"parameters":[{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":true}],"responses":{"200":{"description":"Simplified category list for selector components.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of active categories with localized labels.","type":"array","items":{"description":"Category option for selectbox/dropdown.","type":"object","required":["id","label"],"properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"},"label":{"description":"Localized category name suitable for display in a selectbox.","examples":["Tech News"],"type":"string"}}}},"itemCount":{"description":"Total number of active categories.","examples":[8],"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of active categories with localized labels.","type":"array","items":{"description":"Category option for selectbox/dropdown.","type":"object","required":["id","label"],"properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"},"label":{"description":"Localized category name suitable for display in a selectbox.","examples":["Tech News"],"type":"string"}}}},"itemCount":{"description":"Total number of active categories.","examples":[8],"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of active categories with localized labels.","type":"array","items":{"description":"Category option for selectbox/dropdown.","type":"object","required":["id","label"],"properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"},"label":{"description":"Localized category name suitable for display in a selectbox.","examples":["Tech News"],"type":"string"}}}},"itemCount":{"description":"Total number of active categories.","examples":[8],"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffPost-categoryList-selector","tags":["Post Category"],"summary":"List categories for selector","description":"Returns a simplified list of categories suitable for selectbox/dropdown components. Includes only active categories with their localized names."}},"/bff/post-category/tree":{"get":{"parameters":[{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"description":"Nested tree structure of all post categories.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Top-level category nodes. Each node contains a nested children array forming the full tree.","type":"array","items":{"description":"Recursive tree node. Each node has: id (external ID), title (localized name), slug (URL slug), active (boolean), postCount (number of posts), children (array of child nodes with the same shape)."}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Top-level category nodes. Each node contains a nested children array forming the full tree.","type":"array","items":{"description":"Recursive tree node. Each node has: id (external ID), title (localized name), slug (URL slug), active (boolean), postCount (number of posts), children (array of child nodes with the same shape)."}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Top-level category nodes. Each node contains a nested children array forming the full tree.","type":"array","items":{"description":"Recursive tree node. Each node has: id (external ID), title (localized name), slug (URL slug), active (boolean), postCount (number of posts), children (array of child nodes with the same shape)."}}},"required":["items"]}}}}},"operationId":"getBffPost-categoryTree","tags":["Post Category"],"summary":"Get category tree","description":"Returns all post categories as a nested tree structure. Each node includes its children, post count, and localized title/slug. Node shape: { id: string, title: string, slug: string, active: boolean, postCount: number, children: Node[] }."}},"/bff/post-category/detail":{"get":{"parameters":[{"description":"Category external ID.","examples":["abc123def456ghij"],"schema":{"type":"string"},"in":"query","name":"id","required":true},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"},"title":{"description":"Localized category name.","examples":["Tech News"],"type":"string"},"description":{"description":"Category description.","examples":["Latest technology news and updates."],"type":"string"},"metaDescription":{"description":"SEO meta description.","examples":["Tech news, tutorials, and insights."],"type":"string"},"slug":{"description":"URL slug.","examples":["tech-news"],"type":"string"},"parentId":{"description":"Parent category external ID.","examples":["abc123def456ghij"],"type":"string"},"parentTitle":{"description":"Parent category name.","examples":["Technology"],"type":"string"},"active":{"description":"Whether the category is active.","examples":[true],"type":"boolean"},"insertedDate":{"description":"When the category was created.","anyOf":[{"description":"When the category was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Number of posts in this category.","examples":[42],"type":"number"},"translations":{"description":"All available locale translations for this category.","type":"array","items":{"type":"object","required":["locale","name"],"properties":{"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","examples":["en"],"type":"string"},"name":{"description":"Category name in this locale.","examples":["Tech News"],"type":"string"}}}}},"required":["id","title","description","metaDescription","slug","active","insertedDate","postCount","translations"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"},"title":{"description":"Localized category name.","examples":["Tech News"],"type":"string"},"description":{"description":"Category description.","examples":["Latest technology news and updates."],"type":"string"},"metaDescription":{"description":"SEO meta description.","examples":["Tech news, tutorials, and insights."],"type":"string"},"slug":{"description":"URL slug.","examples":["tech-news"],"type":"string"},"parentId":{"description":"Parent category external ID.","examples":["abc123def456ghij"],"type":"string"},"parentTitle":{"description":"Parent category name.","examples":["Technology"],"type":"string"},"active":{"description":"Whether the category is active.","examples":[true],"type":"boolean"},"insertedDate":{"description":"When the category was created.","anyOf":[{"description":"When the category was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Number of posts in this category.","examples":[42],"type":"number"},"translations":{"description":"All available locale translations for this category.","type":"array","items":{"type":"object","required":["locale","name"],"properties":{"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","examples":["en"],"type":"string"},"name":{"description":"Category name in this locale.","examples":["Tech News"],"type":"string"}}}}},"required":["id","title","description","metaDescription","slug","active","insertedDate","postCount","translations"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"},"title":{"description":"Localized category name.","examples":["Tech News"],"type":"string"},"description":{"description":"Category description.","examples":["Latest technology news and updates."],"type":"string"},"metaDescription":{"description":"SEO meta description.","examples":["Tech news, tutorials, and insights."],"type":"string"},"slug":{"description":"URL slug.","examples":["tech-news"],"type":"string"},"parentId":{"description":"Parent category external ID.","examples":["abc123def456ghij"],"type":"string"},"parentTitle":{"description":"Parent category name.","examples":["Technology"],"type":"string"},"active":{"description":"Whether the category is active.","examples":[true],"type":"boolean"},"insertedDate":{"description":"When the category was created.","anyOf":[{"description":"When the category was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Number of posts in this category.","examples":[42],"type":"number"},"translations":{"description":"All available locale translations for this category.","type":"array","items":{"type":"object","required":["locale","name"],"properties":{"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","examples":["en"],"type":"string"},"name":{"description":"Category name in this locale.","examples":["Tech News"],"type":"string"}}}}},"required":["id","title","description","metaDescription","slug","active","insertedDate","postCount","translations"]}}}}},"operationId":"getBffPost-categoryDetail","tags":["Post Category"],"summary":"Get category detail","description":"Returns full detail of a post category including title, description, meta description, slug, parent info, post count, and all available translations."}},"/bff/post-category/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"},"id":{"description":"External ID of the newly created category.","examples":["abc123def456ghij"],"type":"string"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"},"id":{"description":"External ID of the newly created category.","examples":["abc123def456ghij"],"type":"string"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"},"id":{"description":"External ID of the newly created category.","examples":["abc123def456ghij"],"type":"string"}},"required":["success","id"]}}}}},"operationId":"postBffPost-categoryCreate","tags":["Post Category"],"summary":"Create new post category","description":"Creates a new post category with localization and route. Automatically generates a unique external ID and URL slug from the name.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","locale"],"properties":{"name":{"minLength":1,"maxLength":255,"description":"Category name.","examples":["Tech News"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"parentId":{"description":"Parent category external ID. If not provided, creates a top-level category.","examples":["abc123def456ghij"],"type":"string"},"description":{"description":"Category description.","examples":["Latest technology news and updates."],"type":"string"},"metaDescription":{"maxLength":500,"description":"SEO meta description (max 500 characters).","examples":["Tech news, tutorials, and insights."],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name","locale"],"properties":{"name":{"minLength":1,"maxLength":255,"description":"Category name.","examples":["Tech News"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"parentId":{"description":"Parent category external ID. If not provided, creates a top-level category.","examples":["abc123def456ghij"],"type":"string"},"description":{"description":"Category description.","examples":["Latest technology news and updates."],"type":"string"},"metaDescription":{"maxLength":500,"description":"SEO meta description (max 500 characters).","examples":["Tech news, tutorials, and insights."],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["name","locale"],"properties":{"name":{"minLength":1,"maxLength":255,"description":"Category name.","examples":["Tech News"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"parentId":{"description":"Parent category external ID. If not provided, creates a top-level category.","examples":["abc123def456ghij"],"type":"string"},"description":{"description":"Category description.","examples":["Latest technology news and updates."],"type":"string"},"metaDescription":{"maxLength":500,"description":"SEO meta description (max 500 characters).","examples":["Tech news, tutorials, and insights."],"type":"string"}}}}}}}},"/bff/post-category/save":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffPost-categorySave","tags":["Post Category"],"summary":"Edit post category","description":"Updates an existing post category. All fields except id and locale are optional — only provided fields are changed. Supports renaming, changing slug, description, and re-parenting (moving under a different parent or to top-level).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Category external ID to edit.","examples":["abc123def456ghij"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"name":{"minLength":1,"maxLength":255,"description":"New category name.","examples":["Tech News"],"type":"string"},"description":{"description":"New category description.","examples":["Latest technology news."],"type":"string"},"slug":{"description":"New URL slug for the category route. If empty string, auto-generated from name. Only applied when name is also provided.","examples":["tech-news"],"type":"string"},"parentId":{"nullable":true,"anyOf":[{"description":"External ID of the new parent category. Pass null to make it a top-level category. Omit to keep unchanged.","examples":["abc123def456ghij"],"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Category external ID to edit.","examples":["abc123def456ghij"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"name":{"minLength":1,"maxLength":255,"description":"New category name.","examples":["Tech News"],"type":"string"},"description":{"description":"New category description.","examples":["Latest technology news."],"type":"string"},"slug":{"description":"New URL slug for the category route. If empty string, auto-generated from name. Only applied when name is also provided.","examples":["tech-news"],"type":"string"},"parentId":{"nullable":true,"anyOf":[{"description":"External ID of the new parent category. Pass null to make it a top-level category. Omit to keep unchanged.","examples":["abc123def456ghij"],"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["id","locale"],"properties":{"id":{"description":"Category external ID to edit.","examples":["abc123def456ghij"],"type":"string"},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"name":{"minLength":1,"maxLength":255,"description":"New category name.","examples":["Tech News"],"type":"string"},"description":{"description":"New category description.","examples":["Latest technology news."],"type":"string"},"slug":{"description":"New URL slug for the category route. If empty string, auto-generated from name. Only applied when name is also provided.","examples":["tech-news"],"type":"string"},"parentId":{"nullable":true,"anyOf":[{"description":"External ID of the new parent category. Pass null to make it a top-level category. Omit to keep unchanged.","examples":["abc123def456ghij"],"type":"string"},{"type":"null"}]}}}}}}}},"/bff/post-category/toggle-active":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"},"active":{"description":"New active status after toggle.","examples":[true],"type":"boolean"}},"required":["success","active"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"},"active":{"description":"New active status after toggle.","examples":[true],"type":"boolean"}},"required":["success","active"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"},"active":{"description":"New active status after toggle.","examples":[true],"type":"boolean"}},"required":["success","active"]}}}}},"operationId":"postBffPost-categoryToggle-active","tags":["Post Category"],"summary":"Toggle category active status","description":"Toggles the active/inactive status of a post category.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Category external ID.","examples":["abc123def456ghij"],"type":"string"}}}}}}}},"/bff/post-category/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Always true on success.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffPost-categoryDelete","tags":["Post Category"],"summary":"Delete post category","description":"Soft-deletes a post category by setting deleted_date. The category disappears from all listings. Fails if the category has non-deleted child categories or assigned posts — these must be moved or deleted first. This is different from toggle-active, which only hides the category without removing it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Category external ID to delete.","examples":["abc123def456ghij"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Category external ID to delete.","examples":["abc123def456ghij"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Category external ID to delete.","examples":["abc123def456ghij"],"type":"string"}}}}}}}},"/bff/post-tag/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Internal tag ID.","type":"number"},"code":{"description":"Tag code (URL-friendly).","type":"string"},"label":{"description":"Tag display name.","type":"string"},"color":{"nullable":true,"anyOf":[{"description":"Tag color in #RRGGBB format.","type":"string"},{"type":"null"}]}},"required":["id","code","label","color"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Internal tag ID.","type":"number"},"code":{"description":"Tag code (URL-friendly).","type":"string"},"label":{"description":"Tag display name.","type":"string"},"color":{"nullable":true,"anyOf":[{"description":"Tag color in #RRGGBB format.","type":"string"},{"type":"null"}]}},"required":["id","code","label","color"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Internal tag ID.","type":"number"},"code":{"description":"Tag code (URL-friendly).","type":"string"},"label":{"description":"Tag display name.","type":"string"},"color":{"nullable":true,"anyOf":[{"description":"Tag color in #RRGGBB format.","type":"string"},{"type":"null"}]}},"required":["id","code","label","color"]}}}}},"operationId":"postBffPost-tagCreate","tags":["Post Tags"],"summary":"Create new tag","description":"Creates a new tag for posts including route. Tag code is automatically normalized to URL-friendly format. Tag must have a unique code within the organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","label","locale"],"properties":{"code":{"minLength":1,"maxLength":100,"description":"Unique tag code (URL-friendly, automatically normalized)","type":"string"},"label":{"minLength":1,"maxLength":200,"description":"Display name of the tag","type":"string"},"color":{"pattern":"^#[0-9A-Fa-f]{6}$","description":"Tag color in #RRGGBB format (optional)","type":"string"},"locale":{"minLength":2,"maxLength":2,"description":"Locale code for route creation (e.g., cs, en, sk)","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","label","locale"],"properties":{"code":{"minLength":1,"maxLength":100,"description":"Unique tag code (URL-friendly, automatically normalized)","type":"string"},"label":{"minLength":1,"maxLength":200,"description":"Display name of the tag","type":"string"},"color":{"pattern":"^#[0-9A-Fa-f]{6}$","description":"Tag color in #RRGGBB format (optional)","type":"string"},"locale":{"minLength":2,"maxLength":2,"description":"Locale code for route creation (e.g., cs, en, sk)","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code","label","locale"],"properties":{"code":{"minLength":1,"maxLength":100,"description":"Unique tag code (URL-friendly, automatically normalized)","type":"string"},"label":{"minLength":1,"maxLength":200,"description":"Display name of the tag","type":"string"},"color":{"pattern":"^#[0-9A-Fa-f]{6}$","description":"Tag color in #RRGGBB format (optional)","type":"string"},"locale":{"minLength":2,"maxLength":2,"description":"Locale code for route creation (e.g., cs, en, sk)","type":"string"}}}}}}}},"/bff/post-tag/list":{"get":{"operationId":"getBffPost-tagList","tags":["Post Tags"],"summary":"List all organisation tags","description":"Returns a list of all tags including their usage count in posts. Contains both active and inactive tags.","responses":{"200":{}}}},"/bff/post-tag/detail":{"get":{"parameters":[{"description":"Tag ID","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffPost-tagDetail","tags":["Post Tags"],"summary":"Tag detail","description":"Returns detail of a specific tag including its settings.","responses":{"200":{}}}},"/bff/post-tag/post-tags":{"get":{"parameters":[{"description":"Post external ID","schema":{"type":"string"},"in":"query","name":"postId","required":true}],"operationId":"getBffPost-tagPost-tags","tags":["Post Tags"],"summary":"List post tags","description":"Returns a list of all active tags assigned to the given post.","responses":{"200":{}}}},"/bff/post-tag/sync":{"post":{"parameters":[],"operationId":"postBffPost-tagSync","tags":["Post Tags"],"summary":"Sync post tags","description":"Sets post tags according to the provided array. Removes all previous tags and adds only those in the array. All IDs must be valid and belong to the same organisation as the post.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["postId","tagIds"],"properties":{"postId":{"description":"Post external ID","type":"string"},"tagIds":{"description":"Array of tag IDs to be assigned to the post. All previous associations will be removed and replaced with this list. Empty array removes all tags from the post.","type":"array","items":{"type":"number"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["postId","tagIds"],"properties":{"postId":{"description":"Post external ID","type":"string"},"tagIds":{"description":"Array of tag IDs to be assigned to the post. All previous associations will be removed and replaced with this list. Empty array removes all tags from the post.","type":"array","items":{"type":"number"}}}}},"text/plain":{"schema":{"type":"object","required":["postId","tagIds"],"properties":{"postId":{"description":"Post external ID","type":"string"},"tagIds":{"description":"Array of tag IDs to be assigned to the post. All previous associations will be removed and replaced with this list. Empty array removes all tags from the post.","type":"array","items":{"type":"number"}}}}}}},"responses":{"200":{}}}},"/bff/post-tag/update":{"put":{"parameters":[],"operationId":"putBffPost-tagUpdate","tags":["Post Tags"],"summary":"Update tag","description":"Updates properties of an existing tag. Can update name, color or active status. Tag code cannot be changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Tag ID","type":"number"},"label":{"minLength":1,"maxLength":200,"description":"New tag name","type":"string"},"color":{"pattern":"^#[0-9A-Fa-f]{6}$","description":"New tag color in #RRGGBB format","type":"string"},"active":{"description":"Tag status (active/inactive)","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Tag ID","type":"number"},"label":{"minLength":1,"maxLength":200,"description":"New tag name","type":"string"},"color":{"pattern":"^#[0-9A-Fa-f]{6}$","description":"New tag color in #RRGGBB format","type":"string"},"active":{"description":"Tag status (active/inactive)","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Tag ID","type":"number"},"label":{"minLength":1,"maxLength":200,"description":"New tag name","type":"string"},"color":{"pattern":"^#[0-9A-Fa-f]{6}$","description":"New tag color in #RRGGBB format","type":"string"},"active":{"description":"Tag status (active/inactive)","type":"boolean"}}}}}},"responses":{"200":{}}}},"/bff/post-tag/delete":{"delete":{"parameters":[{"description":"Tag ID","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"deleteBffPost-tagDelete","tags":["Post Tags"],"summary":"Deactivate tag","description":"Deactivates a tag (sets active = false). Tag remains in the database but will not appear in lists. Associations with posts are preserved.","responses":{"200":{}}}},"/bff/product/list":{"get":{"parameters":[{"description":"Filter products by main category code, or pass the literal \"__none__\" to return products that have no main category. Omit for all products.","examples":["electronics","__none__"],"schema":{"type":"string"},"in":"query","name":"mainCategoryCode","required":false},{"description":"Locale code for translated product names and descriptions (e.g. \"cs\", \"en\").","examples":["cs"],"schema":{"type":"string"},"in":"query","name":"locale","required":false},{"description":"\"true\" → active products only, \"false\" → inactive only. Omit for both.","examples":["true","false"],"schema":{"type":"string"},"in":"query","name":"active","required":false},{"description":"\"available\" = in stock & not sold-out (NULL qty = unlimited); \"lowStock\" = qty > 0 AND qty ≤ warehouse_limit (limit required); \"soldOut\" = sold_out flag set OR qty = 0.","examples":["available","lowStock","soldOut"],"schema":{"type":"string"},"in":"query","name":"stockStatus","required":false},{"description":"\"inFeed\" = show_in_feed=true; \"notInFeed\" = show_in_feed=false; \"b2bOnly\" = b2b=true.","examples":["inFeed","notInFeed","b2bOnly"],"schema":{"type":"string"},"in":"query","name":"visibility","required":false},{"description":"\"missingImage\" = no main image; \"missingEan\" = empty EAN.","examples":["missingImage","missingEan"],"schema":{"type":"string"},"in":"query","name":"dataQuality","required":false},{"description":"Soft-delete view: \"hide\" (default) = live only, \"only\" = soft-deleted only (recycle bin), \"include\" = both. Anything else is treated as \"hide\".","examples":["hide","only","include"],"schema":{"type":"string"},"in":"query","name":"deletedView","required":false}],"responses":{"200":{"description":"Paginated list of products.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of products matching the query criteria.","type":"array","items":{"description":"Single product item in the list.","type":"object","required":["id","code","name","slug","position","active","b2b","showInFeed","soldOut","translatedLocales"],"properties":{"id":{"description":"Product code (used as unique identifier).","type":"string"},"code":{"description":"URL-friendly unique product code.","type":"string"},"name":{"description":"Product name (translated if locale is specified).","type":"string"},"slug":{"description":"URL slug for the product.","type":"string"},"ean":{"description":"EAN barcode (13 digits).","type":"string"},"description":{"description":"Short plain-text description, truncated to 200 characters.","type":"string"},"internalNote":{"description":"Internal note visible only in admin.","type":"string"},"mainCategory":{"description":"Main category the product belongs to.","type":"object","required":["code","name"],"properties":{"code":{"description":"Category code.","type":"string"},"name":{"description":"Category display name.","type":"string"}}},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"position":{"description":"Display order position.","type":"number"},"active":{"description":"Whether the product is active and visible.","type":"boolean"},"deletedDate":{"description":"ISO timestamp when the product was soft-deleted. Absent on live products.","type":"string"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds (e.g. Google Shopping).","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"price":{"description":"Price object with priceWithVat, priceWithoutVat, vat, currency."},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","type":"number"},"statistic":{"description":"Order statistics aggregated by status type."},"translatedLocales":{"description":"Locales for which a translation exists.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}}}}},"itemCount":{"description":"Total number of products matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of products matching the query criteria.","type":"array","items":{"description":"Single product item in the list.","type":"object","required":["id","code","name","slug","position","active","b2b","showInFeed","soldOut","translatedLocales"],"properties":{"id":{"description":"Product code (used as unique identifier).","type":"string"},"code":{"description":"URL-friendly unique product code.","type":"string"},"name":{"description":"Product name (translated if locale is specified).","type":"string"},"slug":{"description":"URL slug for the product.","type":"string"},"ean":{"description":"EAN barcode (13 digits).","type":"string"},"description":{"description":"Short plain-text description, truncated to 200 characters.","type":"string"},"internalNote":{"description":"Internal note visible only in admin.","type":"string"},"mainCategory":{"description":"Main category the product belongs to.","type":"object","required":["code","name"],"properties":{"code":{"description":"Category code.","type":"string"},"name":{"description":"Category display name.","type":"string"}}},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"position":{"description":"Display order position.","type":"number"},"active":{"description":"Whether the product is active and visible.","type":"boolean"},"deletedDate":{"description":"ISO timestamp when the product was soft-deleted. Absent on live products.","type":"string"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds (e.g. Google Shopping).","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"price":{"description":"Price object with priceWithVat, priceWithoutVat, vat, currency."},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","type":"number"},"statistic":{"description":"Order statistics aggregated by status type."},"translatedLocales":{"description":"Locales for which a translation exists.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}}}}},"itemCount":{"description":"Total number of products matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of products matching the query criteria.","type":"array","items":{"description":"Single product item in the list.","type":"object","required":["id","code","name","slug","position","active","b2b","showInFeed","soldOut","translatedLocales"],"properties":{"id":{"description":"Product code (used as unique identifier).","type":"string"},"code":{"description":"URL-friendly unique product code.","type":"string"},"name":{"description":"Product name (translated if locale is specified).","type":"string"},"slug":{"description":"URL slug for the product.","type":"string"},"ean":{"description":"EAN barcode (13 digits).","type":"string"},"description":{"description":"Short plain-text description, truncated to 200 characters.","type":"string"},"internalNote":{"description":"Internal note visible only in admin.","type":"string"},"mainCategory":{"description":"Main category the product belongs to.","type":"object","required":["code","name"],"properties":{"code":{"description":"Category code.","type":"string"},"name":{"description":"Category display name.","type":"string"}}},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"position":{"description":"Display order position.","type":"number"},"active":{"description":"Whether the product is active and visible.","type":"boolean"},"deletedDate":{"description":"ISO timestamp when the product was soft-deleted. Absent on live products.","type":"string"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds (e.g. Google Shopping).","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"price":{"description":"Price object with priceWithVat, priceWithoutVat, vat, currency."},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","type":"number"},"statistic":{"description":"Order statistics aggregated by status type."},"translatedLocales":{"description":"Locales for which a translation exists.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}}}}},"itemCount":{"description":"Total number of products matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProductList","tags":["Product"],"summary":"List products","description":"Returns a list of products for the authenticated organisation. Products are ordered by active status (active first) and then by position. Each product includes basic metadata, main image URL, category, price, and order statistics."}},"/bff/product/product-detail":{"get":{"parameters":[{"description":"Unique product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true},{"description":"Locale code for translated fields. Falls back to primary locale if not provided.","examples":["cs"],"schema":{"type":"string"},"in":"query","name":"locale","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Product code (used as identifier).","type":"string"},"code":{"description":"Unique product code.","type":"string"},"name":{"description":"Product name (translated if locale is specified).","type":"string"},"slug":{"description":"URL slug.","type":"string"},"ean":{"description":"EAN barcode.","type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"longDescription":{"description":"Long HTML description.","type":"string"},"internalNote":{"description":"Internal note (admin only).","type":"string"},"active":{"description":"Whether the product is active.","type":"boolean"},"deleted":{"description":"Whether the product is soft-deleted (legacy boolean — prefer `deletedDate`).","type":"boolean"},"deletedDate":{"description":"ISO timestamp when the product was soft-deleted. Canonical signal for soft-delete; absent on live products.","type":"string"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"mainCategoryId":{"description":"Internal ID of the main category.","type":"number"},"brandId":{"description":"Internal ID of the brand.","type":"number"},"defaultCurrency":{"description":"Default currency code (e.g. \"CZK\").","type":"string"},"price":{"description":"Price with VAT as a number.","type":"number"},"standardPricePercentage":{"description":"Standard price percentage for discount calculation.","type":"number"},"vat":{"description":"VAT rate percentage.","type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","type":"number"},"weightGrams":{"description":"Product weight in grams.","type":"number"},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","type":"number"},"isVariantProduct":{"description":"Whether the product has variants.","type":"boolean"},"variantCount":{"description":"Number of product variants.","type":"number"},"customFields":{"description":"Custom fields attached to the product.","type":"array","items":{"type":"object","required":["key","value","active","insertedDate"],"properties":{"key":{"description":"Custom field key identifier.","type":"string"},"value":{"description":"Custom field value.","type":"string"},"active":{"description":"Whether the field is active.","type":"boolean"},"insertedDate":{"description":"Date when the field was created/updated.","anyOf":[{"description":"Date when the field was created/updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"customFieldsDefinition":{"description":"Available custom field definitions for the product category.","type":"array","items":{"type":"object","required":["key","type","label","required"],"properties":{"key":{"description":"Field key identifier.","type":"string"},"type":{"description":"Field type: text, textarea, number, or boolean.","type":"string"},"label":{"description":"Display label for the field.","type":"string"},"helperText":{"description":"Helper text shown below the field.","type":"string"},"placeholder":{"description":"Placeholder text for the input.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"validationPattern":{"description":"Regex pattern for validation.","type":"string"}}}},"eventList":{"description":"Calendar events linked to this product.","type":"array","items":{"type":"object","required":["id","type","title","isStorno","startTime","endTime"],"properties":{"id":{"description":"Event code.","type":"string"},"type":{"description":"How the event is linked: directly or via event type.","anyOf":[{"const":"direct","type":"string"},{"const":"eventType","type":"string"}]},"title":{"description":"Event title.","type":"string"},"isStorno":{"description":"Whether the event is cancelled.","type":"boolean"},"startTime":{"description":"Event start time.","anyOf":[{"description":"Event start time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time.","anyOf":[{"description":"Event end time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"typeCode":{"description":"Event type code.","type":"string"},"typeLabel":{"description":"Event type label.","type":"string"},"typeColor":{"description":"Event type color (hex, e.g. \"#FF5733\").","type":"string"}}}},"translatedLocales":{"description":"Locales for which a translation exists in shop__product_translation.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"voucherTemplateCount":{"description":"Number of voucher templates linked to this product.","type":"number"},"subscriptionPlanCount":{"description":"Number of subscription plans linked to this product.","type":"number"}},"required":["id","code","name","slug","shortDescription","longDescription","internalNote","active","deleted","b2b","showInFeed","soldOut","defaultCurrency","price","isVariantProduct","variantCount","customFields","customFieldsDefinition","eventList","translatedLocales","voucherTemplateCount","subscriptionPlanCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Product code (used as identifier).","type":"string"},"code":{"description":"Unique product code.","type":"string"},"name":{"description":"Product name (translated if locale is specified).","type":"string"},"slug":{"description":"URL slug.","type":"string"},"ean":{"description":"EAN barcode.","type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"longDescription":{"description":"Long HTML description.","type":"string"},"internalNote":{"description":"Internal note (admin only).","type":"string"},"active":{"description":"Whether the product is active.","type":"boolean"},"deleted":{"description":"Whether the product is soft-deleted (legacy boolean — prefer `deletedDate`).","type":"boolean"},"deletedDate":{"description":"ISO timestamp when the product was soft-deleted. Canonical signal for soft-delete; absent on live products.","type":"string"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"mainCategoryId":{"description":"Internal ID of the main category.","type":"number"},"brandId":{"description":"Internal ID of the brand.","type":"number"},"defaultCurrency":{"description":"Default currency code (e.g. \"CZK\").","type":"string"},"price":{"description":"Price with VAT as a number.","type":"number"},"standardPricePercentage":{"description":"Standard price percentage for discount calculation.","type":"number"},"vat":{"description":"VAT rate percentage.","type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","type":"number"},"weightGrams":{"description":"Product weight in grams.","type":"number"},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","type":"number"},"isVariantProduct":{"description":"Whether the product has variants.","type":"boolean"},"variantCount":{"description":"Number of product variants.","type":"number"},"customFields":{"description":"Custom fields attached to the product.","type":"array","items":{"type":"object","required":["key","value","active","insertedDate"],"properties":{"key":{"description":"Custom field key identifier.","type":"string"},"value":{"description":"Custom field value.","type":"string"},"active":{"description":"Whether the field is active.","type":"boolean"},"insertedDate":{"description":"Date when the field was created/updated.","anyOf":[{"description":"Date when the field was created/updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"customFieldsDefinition":{"description":"Available custom field definitions for the product category.","type":"array","items":{"type":"object","required":["key","type","label","required"],"properties":{"key":{"description":"Field key identifier.","type":"string"},"type":{"description":"Field type: text, textarea, number, or boolean.","type":"string"},"label":{"description":"Display label for the field.","type":"string"},"helperText":{"description":"Helper text shown below the field.","type":"string"},"placeholder":{"description":"Placeholder text for the input.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"validationPattern":{"description":"Regex pattern for validation.","type":"string"}}}},"eventList":{"description":"Calendar events linked to this product.","type":"array","items":{"type":"object","required":["id","type","title","isStorno","startTime","endTime"],"properties":{"id":{"description":"Event code.","type":"string"},"type":{"description":"How the event is linked: directly or via event type.","anyOf":[{"const":"direct","type":"string"},{"const":"eventType","type":"string"}]},"title":{"description":"Event title.","type":"string"},"isStorno":{"description":"Whether the event is cancelled.","type":"boolean"},"startTime":{"description":"Event start time.","anyOf":[{"description":"Event start time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time.","anyOf":[{"description":"Event end time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"typeCode":{"description":"Event type code.","type":"string"},"typeLabel":{"description":"Event type label.","type":"string"},"typeColor":{"description":"Event type color (hex, e.g. \"#FF5733\").","type":"string"}}}},"translatedLocales":{"description":"Locales for which a translation exists in shop__product_translation.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"voucherTemplateCount":{"description":"Number of voucher templates linked to this product.","type":"number"},"subscriptionPlanCount":{"description":"Number of subscription plans linked to this product.","type":"number"}},"required":["id","code","name","slug","shortDescription","longDescription","internalNote","active","deleted","b2b","showInFeed","soldOut","defaultCurrency","price","isVariantProduct","variantCount","customFields","customFieldsDefinition","eventList","translatedLocales","voucherTemplateCount","subscriptionPlanCount"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Product code (used as identifier).","type":"string"},"code":{"description":"Unique product code.","type":"string"},"name":{"description":"Product name (translated if locale is specified).","type":"string"},"slug":{"description":"URL slug.","type":"string"},"ean":{"description":"EAN barcode.","type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"longDescription":{"description":"Long HTML description.","type":"string"},"internalNote":{"description":"Internal note (admin only).","type":"string"},"active":{"description":"Whether the product is active.","type":"boolean"},"deleted":{"description":"Whether the product is soft-deleted (legacy boolean — prefer `deletedDate`).","type":"boolean"},"deletedDate":{"description":"ISO timestamp when the product was soft-deleted. Canonical signal for soft-delete; absent on live products.","type":"string"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"mainImageUrl":{"description":"URL of the main product image.","type":"string"},"mainCategoryId":{"description":"Internal ID of the main category.","type":"number"},"brandId":{"description":"Internal ID of the brand.","type":"number"},"defaultCurrency":{"description":"Default currency code (e.g. \"CZK\").","type":"string"},"price":{"description":"Price with VAT as a number.","type":"number"},"standardPricePercentage":{"description":"Standard price percentage for discount calculation.","type":"number"},"vat":{"description":"VAT rate percentage.","type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","type":"number"},"weightGrams":{"description":"Product weight in grams.","type":"number"},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","type":"number"},"isVariantProduct":{"description":"Whether the product has variants.","type":"boolean"},"variantCount":{"description":"Number of product variants.","type":"number"},"customFields":{"description":"Custom fields attached to the product.","type":"array","items":{"type":"object","required":["key","value","active","insertedDate"],"properties":{"key":{"description":"Custom field key identifier.","type":"string"},"value":{"description":"Custom field value.","type":"string"},"active":{"description":"Whether the field is active.","type":"boolean"},"insertedDate":{"description":"Date when the field was created/updated.","anyOf":[{"description":"Date when the field was created/updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"customFieldsDefinition":{"description":"Available custom field definitions for the product category.","type":"array","items":{"type":"object","required":["key","type","label","required"],"properties":{"key":{"description":"Field key identifier.","type":"string"},"type":{"description":"Field type: text, textarea, number, or boolean.","type":"string"},"label":{"description":"Display label for the field.","type":"string"},"helperText":{"description":"Helper text shown below the field.","type":"string"},"placeholder":{"description":"Placeholder text for the input.","type":"string"},"required":{"description":"Whether the field is required.","type":"boolean"},"validationPattern":{"description":"Regex pattern for validation.","type":"string"}}}},"eventList":{"description":"Calendar events linked to this product.","type":"array","items":{"type":"object","required":["id","type","title","isStorno","startTime","endTime"],"properties":{"id":{"description":"Event code.","type":"string"},"type":{"description":"How the event is linked: directly or via event type.","anyOf":[{"const":"direct","type":"string"},{"const":"eventType","type":"string"}]},"title":{"description":"Event title.","type":"string"},"isStorno":{"description":"Whether the event is cancelled.","type":"boolean"},"startTime":{"description":"Event start time.","anyOf":[{"description":"Event start time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"endTime":{"description":"Event end time.","anyOf":[{"description":"Event end time.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"typeCode":{"description":"Event type code.","type":"string"},"typeLabel":{"description":"Event type label.","type":"string"},"typeColor":{"description":"Event type color (hex, e.g. \"#FF5733\").","type":"string"}}}},"translatedLocales":{"description":"Locales for which a translation exists in shop__product_translation.","type":"array","items":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"}},"voucherTemplateCount":{"description":"Number of voucher templates linked to this product.","type":"number"},"subscriptionPlanCount":{"description":"Number of subscription plans linked to this product.","type":"number"}},"required":["id","code","name","slug","shortDescription","longDescription","internalNote","active","deleted","b2b","showInFeed","soldOut","defaultCurrency","price","isVariantProduct","variantCount","customFields","customFieldsDefinition","eventList","translatedLocales","voucherTemplateCount","subscriptionPlanCount"]}}}}},"operationId":"getBffProductProduct-detail","tags":["Product"],"summary":"Get product detail","description":"Returns full product detail including all editable fields, custom fields, field definitions, and linked events. Translatable fields (name, descriptions) are resolved from the translation table with locale fallback."}},"/bff/product/price-history":{"get":{"parameters":[{"description":"Product code to get price history for.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"priceItems":{"description":"Price history entries ordered by date descending.","type":"array","items":{"type":"object","required":["price","inserted_date"],"properties":{"price":{"description":"Price with VAT at that point in time.","type":"number"},"inserted_date":{"description":"Date when the price was recorded.","anyOf":[{"description":"Date when the price was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["priceItems"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"priceItems":{"description":"Price history entries ordered by date descending.","type":"array","items":{"type":"object","required":["price","inserted_date"],"properties":{"price":{"description":"Price with VAT at that point in time.","type":"number"},"inserted_date":{"description":"Date when the price was recorded.","anyOf":[{"description":"Date when the price was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["priceItems"]}},"text/plain":{"schema":{"type":"object","properties":{"priceItems":{"description":"Price history entries ordered by date descending.","type":"array","items":{"type":"object","required":["price","inserted_date"],"properties":{"price":{"description":"Price with VAT at that point in time.","type":"number"},"inserted_date":{"description":"Date when the price was recorded.","anyOf":[{"description":"Date when the price was recorded.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}}},"required":["priceItems"]}}}}},"operationId":"getBffProductPrice-history","tags":["Product"],"summary":"Get product price history","description":"Returns a chronological list of price changes for the product, ordered by most recent first."}},"/bff/product/search-related-products":{"get":{"parameters":[{"description":"Product code to search related products for.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true},{"description":"Search query to filter potential related products by name, code, EAN, or description.","schema":{"type":"string"},"in":"query","name":"query","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Matching products (same structure as product list items).","type":"array","items":{}},"itemCount":{"description":"Total matching products.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Matching products (same structure as product list items).","type":"array","items":{}},"itemCount":{"description":"Total matching products.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Matching products (same structure as product list items).","type":"array","items":{}},"itemCount":{"description":"Total matching products.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProductSearch-related-products","tags":["Product"],"summary":"Search products for relating","description":"Searches for products that can be added as related to the given product. Excludes the product itself. Returns up to 20 matching products."}},"/bff/product/product-detail-related":{"get":{"parameters":[{"description":"Product code to list related products for.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Related products (same structure as product list items).","type":"array","items":{}},"itemCount":{"description":"Total number of related products.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Related products (same structure as product list items).","type":"array","items":{}},"itemCount":{"description":"Total number of related products.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Related products (same structure as product list items).","type":"array","items":{}},"itemCount":{"description":"Total number of related products.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProductProduct-detail-related","tags":["Product"],"summary":"List related products","description":"Returns all products related to the given product (bidirectional relation). Related products are shown as recommendations on the product page."}},"/bff/product/connect-related-product":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the relation was created successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the relation was created successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the relation was created successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductConnect-related-product","tags":["Product"],"summary":"Connect related product","description":"Creates a bidirectional relation between two products. Both products will show each other as related. Regenerates read models for both products.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","relatedCode"],"properties":{"productCode":{"description":"Product code to add a relation to.","examples":["my-product"],"type":"string"},"relatedCode":{"description":"Product code of the related product.","examples":["related-product"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","relatedCode"],"properties":{"productCode":{"description":"Product code to add a relation to.","examples":["my-product"],"type":"string"},"relatedCode":{"description":"Product code of the related product.","examples":["related-product"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","relatedCode"],"properties":{"productCode":{"description":"Product code to add a relation to.","examples":["my-product"],"type":"string"},"relatedCode":{"description":"Product code of the related product.","examples":["related-product"],"type":"string"}}}}}}}},"/bff/product/disconnect-related-product":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the relation was removed successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the relation was removed successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the relation was removed successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductDisconnect-related-product","tags":["Product"],"summary":"Disconnect related product","description":"Removes the bidirectional relation between two products.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","relatedCode"],"properties":{"productCode":{"description":"Product code to remove the relation from.","examples":["my-product"],"type":"string"},"relatedCode":{"description":"Product code of the related product to disconnect.","examples":["related-product"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","relatedCode"],"properties":{"productCode":{"description":"Product code to remove the relation from.","examples":["my-product"],"type":"string"},"relatedCode":{"description":"Product code of the related product to disconnect.","examples":["related-product"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","relatedCode"],"properties":{"productCode":{"description":"Product code to remove the relation from.","examples":["my-product"],"type":"string"},"relatedCode":{"description":"Product code of the related product to disconnect.","examples":["related-product"],"type":"string"}}}}}}}},"/bff/product/search-product-list-autocomplete":{"get":{"parameters":[{"description":"Search query to filter products by name or description.","examples":["blue shirt"],"schema":{"type":"string"},"in":"query","name":"searchQuery","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Products matching the autocomplete query.","type":"array","items":{"type":"object","required":["code","name","price","vat"],"properties":{"code":{"description":"Product code.","type":"string"},"name":{"description":"Product name.","type":"string"},"shortDescription":{"description":"Short description, truncated to 150 characters.","type":"string"},"mainImageUrl":{"description":"Main product image URL.","type":"string"},"price":{"description":"Price with VAT.","type":"number"},"vat":{"description":"VAT rate percentage.","type":"number"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Products matching the autocomplete query.","type":"array","items":{"type":"object","required":["code","name","price","vat"],"properties":{"code":{"description":"Product code.","type":"string"},"name":{"description":"Product name.","type":"string"},"shortDescription":{"description":"Short description, truncated to 150 characters.","type":"string"},"mainImageUrl":{"description":"Main product image URL.","type":"string"},"price":{"description":"Price with VAT.","type":"number"},"vat":{"description":"VAT rate percentage.","type":"number"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Products matching the autocomplete query.","type":"array","items":{"type":"object","required":["code","name","price","vat"],"properties":{"code":{"description":"Product code.","type":"string"},"name":{"description":"Product name.","type":"string"},"shortDescription":{"description":"Short description, truncated to 150 characters.","type":"string"},"mainImageUrl":{"description":"Main product image URL.","type":"string"},"price":{"description":"Price with VAT.","type":"number"},"vat":{"description":"VAT rate percentage.","type":"number"}}}}},"required":["items"]}}}}},"operationId":"getBffProductSearch-product-list-autocomplete","tags":["Product"],"summary":"Autocomplete product search","description":"Returns up to 20 products matching the search query for autocomplete purposes. Searches by product name and short description. Includes thumbnail image and price."}},"/bff/product/connect-event":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was linked successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was linked successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was linked successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductConnect-event","tags":["Product"],"summary":"Connect calendar event","description":"Links a calendar event directly to a product. The event will appear in the product detail event list with type \"direct\".","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","eventCode"],"properties":{"productCode":{"description":"Product code to link the event to.","examples":["my-product"],"type":"string"},"eventCode":{"description":"Calendar event code to link.","examples":["event-2024-01"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","eventCode"],"properties":{"productCode":{"description":"Product code to link the event to.","examples":["my-product"],"type":"string"},"eventCode":{"description":"Calendar event code to link.","examples":["event-2024-01"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","eventCode"],"properties":{"productCode":{"description":"Product code to link the event to.","examples":["my-product"],"type":"string"},"eventCode":{"description":"Calendar event code to link.","examples":["event-2024-01"],"type":"string"}}}}}}}},"/bff/product/disconnect-event":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was unlinked successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was unlinked successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the event was unlinked successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductDisconnect-event","tags":["Product"],"summary":"Disconnect calendar event","description":"Removes the direct event link from a product. Events linked via event type are not affected.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code to unlink the event from.","examples":["my-product"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code to unlink the event from.","examples":["my-product"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code to unlink the event from.","examples":["my-product"],"type":"string"}}}}}}}},"/bff/product/connect-contact":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contact was linked successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contact was linked successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the contact was linked successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductConnect-contact","tags":["Product"],"summary":"Connect contact to product","description":"Links a customer/contact to a product. Used for tracking product-customer relationships.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","contactId"],"properties":{"productCode":{"description":"Product code to link the contact to.","examples":["my-product"],"type":"string"},"contactId":{"description":"Contact CU reference number.","examples":["CU-00123"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","contactId"],"properties":{"productCode":{"description":"Product code to link the contact to.","examples":["my-product"],"type":"string"},"contactId":{"description":"Contact CU reference number.","examples":["CU-00123"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","contactId"],"properties":{"productCode":{"description":"Product code to link the contact to.","examples":["my-product"],"type":"string"},"contactId":{"description":"Contact CU reference number.","examples":["CU-00123"],"type":"string"}}}}}}}},"/bff/product/detail-change-code":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"description":"The final product code after slugification and deduplication.","type":"string"}},"required":["code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"code":{"description":"The final product code after slugification and deduplication.","type":"string"}},"required":["code"]}},"text/plain":{"schema":{"type":"object","properties":{"code":{"description":"The final product code after slugification and deduplication.","type":"string"}},"required":["code"]}}}}},"operationId":"postBffProductDetail-change-code","tags":["Product"],"summary":"Change product code","description":"Changes the unique code of a product. The new code is automatically slugified and deduplicated. Includes an optimistic concurrency check: currentCode must match the actual code.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","currentCode","newCode"],"properties":{"id":{"description":"Current product code (used to look up the product).","examples":["my-product"],"type":"string"},"currentCode":{"description":"Expected current code (optimistic concurrency check).","examples":["my-product"],"type":"string"},"newCode":{"description":"New product code. Will be slugified and deduplicated.","examples":["my-new-product"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","currentCode","newCode"],"properties":{"id":{"description":"Current product code (used to look up the product).","examples":["my-product"],"type":"string"},"currentCode":{"description":"Expected current code (optimistic concurrency check).","examples":["my-product"],"type":"string"},"newCode":{"description":"New product code. Will be slugified and deduplicated.","examples":["my-new-product"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","currentCode","newCode"],"properties":{"id":{"description":"Current product code (used to look up the product).","examples":["my-product"],"type":"string"},"currentCode":{"description":"Expected current code (optimistic concurrency check).","examples":["my-product"],"type":"string"},"newCode":{"description":"New product code. Will be slugified and deduplicated.","examples":["my-new-product"],"type":"string"}}}}}}}},"/bff/product/product-reorder":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the reorder completed.","type":"boolean"},"reordered":{"description":"Number of products whose positions were swapped.","type":"number"},"totalProducts":{"description":"Total non-deleted products in the organisation.","type":"number"},"repacked":{"description":"Whether a global 1..N repack pass was applied (true if a gap was detected).","type":"boolean"}},"required":["success","reordered","totalProducts","repacked"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the reorder completed.","type":"boolean"},"reordered":{"description":"Number of products whose positions were swapped.","type":"number"},"totalProducts":{"description":"Total non-deleted products in the organisation.","type":"number"},"repacked":{"description":"Whether a global 1..N repack pass was applied (true if a gap was detected).","type":"boolean"}},"required":["success","reordered","totalProducts","repacked"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the reorder completed.","type":"boolean"},"reordered":{"description":"Number of products whose positions were swapped.","type":"number"},"totalProducts":{"description":"Total non-deleted products in the organisation.","type":"number"},"repacked":{"description":"Whether a global 1..N repack pass was applied (true if a gap was detected).","type":"boolean"}},"required":["success","reordered","totalProducts","repacked"]}}}}},"operationId":"postBffProductProduct-reorder","tags":["Product"],"summary":"Reorder products by swapping positions","description":"Atomically redistributes existing `position` values among the listed products according to the new order. Verifies global density (positions 1..N without gaps) with a cheap aggregate query and runs a window-function repack only if needed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orderedCodes"],"properties":{"orderedCodes":{"minItems":2,"description":"Product codes in their new visual order. Their existing `position` values are redistributed among them (swapped mutually); products outside this list keep their absolute positions. A global 1..N repack runs only if a position gap is detected after the swap.","examples":[["product-a","product-c","product-b"]],"type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["orderedCodes"],"properties":{"orderedCodes":{"minItems":2,"description":"Product codes in their new visual order. Their existing `position` values are redistributed among them (swapped mutually); products outside this list keep their absolute positions. A global 1..N repack runs only if a position gap is detected after the swap.","examples":[["product-a","product-c","product-b"]],"type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["orderedCodes"],"properties":{"orderedCodes":{"minItems":2,"description":"Product codes in their new visual order. Their existing `position` values are redistributed among them (swapped mutually); products outside this list keep their absolute positions. A global 1..N repack runs only if a position gap is detected after the swap.","examples":[["product-a","product-c","product-b"]],"type":"array","items":{"type":"string"}}}}}}}}},"/bff/product/product-soft-delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"code":{"description":"Product code (echoed back for client refetch).","type":"string"},"deletedDate":{"description":"ISO timestamp the deletion was stamped with.","type":"string"}},"required":["success","code","deletedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"code":{"description":"Product code (echoed back for client refetch).","type":"string"},"deletedDate":{"description":"ISO timestamp the deletion was stamped with.","type":"string"}},"required":["success","code","deletedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"code":{"description":"Product code (echoed back for client refetch).","type":"string"},"deletedDate":{"description":"ISO timestamp the deletion was stamped with.","type":"string"}},"required":["success","code","deletedDate"]}}}}},"operationId":"postBffProductProduct-soft-delete","tags":["Product"],"summary":"Soft-delete product","description":"Stamps `deleted_date = NOW()`, flips the legacy `deleted` boolean, and turns `active = false`. The product disappears from the default product list, public storefront, feeds and search. Idempotent at the DB layer — but the BFF returns 410 Gone if you call this on an already-deleted product (the resolver refuses to load it). Use `/product-restore` to undo.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"minLength":1,"description":"Product code to soft-delete.","examples":["my-product"],"type":"string"},"reason":{"description":"Free-form reason recorded in the activity log (no validation).","examples":["Removed from catalogue per supplier request"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"minLength":1,"description":"Product code to soft-delete.","examples":["my-product"],"type":"string"},"reason":{"description":"Free-form reason recorded in the activity log (no validation).","examples":["Removed from catalogue per supplier request"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"minLength":1,"description":"Product code to soft-delete.","examples":["my-product"],"type":"string"},"reason":{"description":"Free-form reason recorded in the activity log (no validation).","examples":["Removed from catalogue per supplier request"],"type":"string"}}}}}}}},"/bff/product/product-restore":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"code":{"description":"Product code (echoed back for client refetch).","type":"string"},"alreadyLive":{"description":"true if the product was not soft-deleted (no-op restore).","type":"boolean"}},"required":["success","code","alreadyLive"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"code":{"description":"Product code (echoed back for client refetch).","type":"string"},"alreadyLive":{"description":"true if the product was not soft-deleted (no-op restore).","type":"boolean"}},"required":["success","code","alreadyLive"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"code":{"description":"Product code (echoed back for client refetch).","type":"string"},"alreadyLive":{"description":"true if the product was not soft-deleted (no-op restore).","type":"boolean"}},"required":["success","code","alreadyLive"]}}}}},"operationId":"postBffProductProduct-restore","tags":["Product"],"summary":"Restore soft-deleted product","description":"Clears `deleted_date` and the legacy `deleted` boolean. `active` is intentionally NOT flipped back to true — the operator should re-publish explicitly so a stale catalogue does not silently come back online.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"minLength":1,"description":"Product code to restore.","examples":["my-product"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"minLength":1,"description":"Product code to restore.","examples":["my-product"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"minLength":1,"description":"Product code to restore.","examples":["my-product"],"type":"string"}}}}}}}},"/bff/product/product-category-set-main":{"get":{"parameters":[{"description":"Product code to set the main category for.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true},{"description":"Category code to set as main. Pass empty string to unset.","examples":["electronics"],"schema":{"type":"string"},"in":"query","name":"categoryCode","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main category was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main category was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main category was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffProductProduct-category-set-main","tags":["Product"],"summary":"Set main product category","description":"Sets or changes the main category for a product. The main category determines which custom field definitions apply and affects product feed categorization."}},"/bff/product/product-copy":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was copied.","type":"boolean"},"code":{"description":"Code of the new product.","type":"string"},"slug":{"description":"URL slug of the new product.","type":"string"}},"required":["success","code","slug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was copied.","type":"boolean"},"code":{"description":"Code of the new product.","type":"string"},"slug":{"description":"URL slug of the new product.","type":"string"}},"required":["success","code","slug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was copied.","type":"boolean"},"code":{"description":"Code of the new product.","type":"string"},"slug":{"description":"URL slug of the new product.","type":"string"}},"required":["success","code","slug"]}}}}},"operationId":"postBffProductProduct-copy","tags":["Product"],"summary":"Copy product","description":"Creates a copy of an existing product with a new name, code, and optional EAN. Copies all properties, custom fields, variants, gallery images, category relations, and translations.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","name","code"],"properties":{"productCode":{"description":"Source product code to copy from.","examples":["my-product"],"type":"string"},"name":{"minLength":1,"description":"Name for the new product.","examples":["My Product Copy"],"type":"string"},"code":{"minLength":1,"description":"Code for the new product (must be unique).","examples":["my-product-copy"],"type":"string"},"ean":{"description":"EAN barcode for the new product.","examples":["8594000000123"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","name","code"],"properties":{"productCode":{"description":"Source product code to copy from.","examples":["my-product"],"type":"string"},"name":{"minLength":1,"description":"Name for the new product.","examples":["My Product Copy"],"type":"string"},"code":{"minLength":1,"description":"Code for the new product (must be unique).","examples":["my-product-copy"],"type":"string"},"ean":{"description":"EAN barcode for the new product.","examples":["8594000000123"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","name","code"],"properties":{"productCode":{"description":"Source product code to copy from.","examples":["my-product"],"type":"string"},"name":{"minLength":1,"description":"Name for the new product.","examples":["My Product Copy"],"type":"string"},"code":{"minLength":1,"description":"Code for the new product (must be unique).","examples":["my-product-copy"],"type":"string"},"ean":{"description":"EAN barcode for the new product.","examples":["8594000000123"],"type":"string"}}}}}}}},"/bff/product/product-create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was created.","type":"boolean"},"code":{"description":"Generated product code.","type":"string"},"slug":{"description":"Generated URL slug.","type":"string"}},"required":["success","code","slug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was created.","type":"boolean"},"code":{"description":"Generated product code.","type":"string"},"slug":{"description":"Generated URL slug.","type":"string"}},"required":["success","code","slug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was created.","type":"boolean"},"code":{"description":"Generated product code.","type":"string"},"slug":{"description":"Generated URL slug.","type":"string"}},"required":["success","code","slug"]}}}}},"operationId":"postBffProductProduct-create","tags":["Product"],"summary":"Create product","description":"Creates a new product with default values (inactive, price 0, not sold out). Generates a unique code and slug, creates an initial price history entry, and writes the first translation row for the specified locale.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","locale"],"properties":{"name":{"minLength":1,"description":"Product name (will be normalized and capitalized).","examples":["My New Product"],"type":"string"},"code":{"minLength":1,"description":"Product code. If not provided, generated from name.","examples":["my-new-product"],"type":"string"},"slug":{"description":"URL slug. If not provided, generated from code or name.","examples":["my-new-product"],"type":"string"},"ean":{"description":"EAN barcode (validated, ignored if invalid).","examples":["8594000000123"],"type":"string"},"locale":{"description":"Locale code for the initial translation (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"mainCategoryCode":{"description":"Main category code to assign.","examples":["electronics"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name","locale"],"properties":{"name":{"minLength":1,"description":"Product name (will be normalized and capitalized).","examples":["My New Product"],"type":"string"},"code":{"minLength":1,"description":"Product code. If not provided, generated from name.","examples":["my-new-product"],"type":"string"},"slug":{"description":"URL slug. If not provided, generated from code or name.","examples":["my-new-product"],"type":"string"},"ean":{"description":"EAN barcode (validated, ignored if invalid).","examples":["8594000000123"],"type":"string"},"locale":{"description":"Locale code for the initial translation (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"mainCategoryCode":{"description":"Main category code to assign.","examples":["electronics"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["name","locale"],"properties":{"name":{"minLength":1,"description":"Product name (will be normalized and capitalized).","examples":["My New Product"],"type":"string"},"code":{"minLength":1,"description":"Product code. If not provided, generated from name.","examples":["my-new-product"],"type":"string"},"slug":{"description":"URL slug. If not provided, generated from code or name.","examples":["my-new-product"],"type":"string"},"ean":{"description":"EAN barcode (validated, ignored if invalid).","examples":["8594000000123"],"type":"string"},"locale":{"description":"Locale code for the initial translation (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"mainCategoryCode":{"description":"Main category code to assign.","examples":["electronics"],"type":"string"}}}}}}}},"/bff/product/product-custom-field-create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the field was created.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the field was created.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the field was created.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-custom-field-create","tags":["Product"],"summary":"Create custom field","description":"Adds a new custom field to a product. Custom fields store additional structured data (e.g. material, color).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","key"],"properties":{"productCode":{"description":"Product code to add the custom field to.","examples":["my-product"],"type":"string"},"key":{"minLength":1,"maxLength":32,"description":"Custom field key (unique per product).","examples":["material"],"type":"string"},"value":{"description":"Custom field value.","examples":["cotton"],"type":"string"},"active":{"description":"Whether the field is active. Defaults to false.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","key"],"properties":{"productCode":{"description":"Product code to add the custom field to.","examples":["my-product"],"type":"string"},"key":{"minLength":1,"maxLength":32,"description":"Custom field key (unique per product).","examples":["material"],"type":"string"},"value":{"description":"Custom field value.","examples":["cotton"],"type":"string"},"active":{"description":"Whether the field is active. Defaults to false.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","key"],"properties":{"productCode":{"description":"Product code to add the custom field to.","examples":["my-product"],"type":"string"},"key":{"minLength":1,"maxLength":32,"description":"Custom field key (unique per product).","examples":["material"],"type":"string"},"value":{"description":"Custom field value.","examples":["cotton"],"type":"string"},"active":{"description":"Whether the field is active. Defaults to false.","type":"boolean"}}}}}}}},"/bff/product/product-custom-field-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the field was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the field was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the field was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-custom-field-update","tags":["Product"],"summary":"Update custom field","description":"Updates an existing custom field on a product. Any combination of key, value, and active can be changed. Fields not provided retain their current values.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","productCode"],"properties":{"id":{"description":"Current custom field key (used to find the field).","examples":["material"],"type":"string"},"productCode":{"description":"Product code the field belongs to.","examples":["my-product"],"type":"string"},"key":{"minLength":1,"maxLength":32,"description":"New key (to rename the field).","examples":["fabric"],"type":"string"},"value":{"description":"New value for the field.","examples":["silk"],"type":"string"},"active":{"description":"New active status.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","productCode"],"properties":{"id":{"description":"Current custom field key (used to find the field).","examples":["material"],"type":"string"},"productCode":{"description":"Product code the field belongs to.","examples":["my-product"],"type":"string"},"key":{"minLength":1,"maxLength":32,"description":"New key (to rename the field).","examples":["fabric"],"type":"string"},"value":{"description":"New value for the field.","examples":["silk"],"type":"string"},"active":{"description":"New active status.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id","productCode"],"properties":{"id":{"description":"Current custom field key (used to find the field).","examples":["material"],"type":"string"},"productCode":{"description":"Product code the field belongs to.","examples":["my-product"],"type":"string"},"key":{"minLength":1,"maxLength":32,"description":"New key (to rename the field).","examples":["fabric"],"type":"string"},"value":{"description":"New value for the field.","examples":["silk"],"type":"string"},"active":{"description":"New active status.","type":"boolean"}}}}}}}},"/bff/product/product-detail-category":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"mainCategoryCode":{"description":"Code of the main category, if set.","type":"string"},"subCategories":{"description":"All categories the product belongs to.","type":"array","items":{"type":"object","required":["code","name"],"properties":{"code":{"description":"Category code.","type":"string"},"name":{"description":"Category display name.","type":"string"}}}}},"required":["subCategories"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"mainCategoryCode":{"description":"Code of the main category, if set.","type":"string"},"subCategories":{"description":"All categories the product belongs to.","type":"array","items":{"type":"object","required":["code","name"],"properties":{"code":{"description":"Category code.","type":"string"},"name":{"description":"Category display name.","type":"string"}}}}},"required":["subCategories"]}},"text/plain":{"schema":{"type":"object","properties":{"mainCategoryCode":{"description":"Code of the main category, if set.","type":"string"},"subCategories":{"description":"All categories the product belongs to.","type":"array","items":{"type":"object","required":["code","name"],"properties":{"code":{"description":"Category code.","type":"string"},"name":{"description":"Category display name.","type":"string"}}}}},"required":["subCategories"]}}}}},"operationId":"getBffProductProduct-detail-category","tags":["Product"],"summary":"Get product categories","description":"Returns the main category and all sub-categories associated with a product. Includes both the directly assigned main category and categories linked via the relation table."}},"/bff/product/product-gallery-link-blob":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"Blob token of the uploaded file to link.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"blobToken","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the image was linked successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the image was linked successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the image was linked successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffProductProduct-gallery-link-blob","tags":["Product"],"summary":"Add image to product gallery","description":"Links an uploaded blob to the product gallery. The image is appended at the end of the gallery. If the product has no main image yet, this image is automatically set as main."}},"/bff/product/product-gallery-list":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Gallery images sorted by active status then position.","type":"array","items":{"type":"object","required":["blob","title","position","deleted","active"],"properties":{"id":{"description":"Blob token (used as image identifier in other endpoints).","type":"string"},"url":{"description":"External URL if the media is not a blob.","type":"string"},"blob":{"description":"Blob file metadata (filename, URL, dimensions, size)."},"title":{"description":"Image alt text / title.","type":"string"},"position":{"description":"Display order position (1-based).","type":"number"},"deleted":{"description":"Whether the image is soft-deleted.","type":"boolean"},"active":{"description":"Whether the image is active (visible on the public site).","type":"boolean"}}}},"mainImageId":{"description":"Blob token of the current main/featured image.","type":"string"},"itemCount":{"description":"Total number of non-deleted images in the gallery.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Gallery images sorted by active status then position.","type":"array","items":{"type":"object","required":["blob","title","position","deleted","active"],"properties":{"id":{"description":"Blob token (used as image identifier in other endpoints).","type":"string"},"url":{"description":"External URL if the media is not a blob.","type":"string"},"blob":{"description":"Blob file metadata (filename, URL, dimensions, size)."},"title":{"description":"Image alt text / title.","type":"string"},"position":{"description":"Display order position (1-based).","type":"number"},"deleted":{"description":"Whether the image is soft-deleted.","type":"boolean"},"active":{"description":"Whether the image is active (visible on the public site).","type":"boolean"}}}},"mainImageId":{"description":"Blob token of the current main/featured image.","type":"string"},"itemCount":{"description":"Total number of non-deleted images in the gallery.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Gallery images sorted by active status then position.","type":"array","items":{"type":"object","required":["blob","title","position","deleted","active"],"properties":{"id":{"description":"Blob token (used as image identifier in other endpoints).","type":"string"},"url":{"description":"External URL if the media is not a blob.","type":"string"},"blob":{"description":"Blob file metadata (filename, URL, dimensions, size)."},"title":{"description":"Image alt text / title.","type":"string"},"position":{"description":"Display order position (1-based).","type":"number"},"deleted":{"description":"Whether the image is soft-deleted.","type":"boolean"},"active":{"description":"Whether the image is active (visible on the public site).","type":"boolean"}}}},"mainImageId":{"description":"Blob token of the current main/featured image.","type":"string"},"itemCount":{"description":"Total number of non-deleted images in the gallery.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProductProduct-gallery-list","tags":["Product"],"summary":"List product gallery images","description":"Returns all non-deleted images in the product gallery sorted by active status and position. Includes blob metadata (URL, dimensions) and identifies the main/featured image."}},"/bff/product/product-image-active-toggle":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"Blob token of the image to toggle.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"imageId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the toggle was successful.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the toggle was successful.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the toggle was successful.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffProductProduct-image-active-toggle","tags":["Product"],"summary":"Toggle image active status","description":"Toggles the active/inactive status of a gallery image. Inactive images are hidden on the public site but remain in the gallery for re-activation. If the main image is deactivated, the first remaining active image becomes the new main."}},"/bff/product/product-image-delete":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"Blob token of the image to delete.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"imageId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the deletion was successful.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the deletion was successful.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the deletion was successful.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffProductProduct-image-delete","tags":["Product"],"summary":"Delete gallery image","description":"Soft-deletes an image from the product gallery (sets deleted flag, does not remove the blob). If the deleted image was the main image, the first remaining active image becomes the new main."}},"/bff/product/product-image-mark-main":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"Blob token of the image to set as main.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"imageId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffProductProduct-image-mark-main","tags":["Product"],"summary":"Set main product image","description":"Sets the specified image as the main/featured image for the product. The main image is used as the product thumbnail in lists and social sharing."}},"/bff/product/product-image-update-meta":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"Blob token of the image to update.","examples":["abc123def456"],"schema":{"type":"string"},"in":"query","name":"imageId","required":true},{"description":"New alt text / title for the image (used for SEO and accessibility).","examples":["Product photo front view"],"schema":{"type":"string"},"in":"query","name":"title","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the metadata was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the metadata was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the metadata was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffProductProduct-image-update-meta","tags":["Product"],"summary":"Update image metadata","description":"Updates the alt text / title of a gallery image. Alt text is important for SEO and accessibility. Pass an empty string to clear it."}},"/bff/product/product-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was updated.","type":"boolean"},"customFieldsRaw":{"description":"Echo of the custom fields that were updated, if provided."}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was updated.","type":"boolean"},"customFieldsRaw":{"description":"Echo of the custom fields that were updated, if provided."}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the product was updated.","type":"boolean"},"customFieldsRaw":{"description":"Echo of the custom fields that were updated, if provided."}},"required":["success"]}}}}},"operationId":"postBffProductProduct-update","tags":["Product"],"summary":"Update product","description":"Updates all editable fields of a product. Locale determines which translation to write to. If saving in the primary locale, base product columns are also updated. If the price changes, a price history entry is created and watchdog notifications are triggered. Custom fields can be batch-updated via customFieldsRaw. Read models for all locales are regenerated.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","code","locale"],"properties":{"name":{"minLength":1,"description":"Product name (will be normalized and capitalized).","examples":["My Product"],"type":"string"},"code":{"minLength":1,"description":"Product code (used to identify the product).","examples":["my-product"],"type":"string"},"locale":{"minLength":2,"maxLength":5,"description":"Locale code for translation (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"slug":{"description":"URL slug. If not provided, keeps existing slug.","examples":["my-product"],"type":"string"},"ean":{"description":"EAN barcode (validated, ignored if invalid).","examples":["8594000000123"],"type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"longDescription":{"description":"Long HTML description.","type":"string"},"internalNote":{"description":"Internal note (admin only).","type":"string"},"active":{"description":"Whether the product is active.","type":"boolean"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"price":{"description":"Price with VAT.","examples":[299.9],"type":"number"},"standardPricePercentage":{"description":"Standard price percentage for discount calculation.","examples":[100],"type":"number"},"vat":{"description":"VAT rate percentage.","examples":[21],"type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","examples":[150],"type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","examples":[200],"type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","examples":[50],"type":"number"},"weightGrams":{"description":"Product weight in grams.","examples":[500],"type":"number"},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","examples":[100],"type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","examples":[10],"type":"number"},"customFieldsRaw":{"description":"Custom fields key-value map for batch update.","type":"object","patternProperties":{"^(.*)$":{}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["name","code","locale"],"properties":{"name":{"minLength":1,"description":"Product name (will be normalized and capitalized).","examples":["My Product"],"type":"string"},"code":{"minLength":1,"description":"Product code (used to identify the product).","examples":["my-product"],"type":"string"},"locale":{"minLength":2,"maxLength":5,"description":"Locale code for translation (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"slug":{"description":"URL slug. If not provided, keeps existing slug.","examples":["my-product"],"type":"string"},"ean":{"description":"EAN barcode (validated, ignored if invalid).","examples":["8594000000123"],"type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"longDescription":{"description":"Long HTML description.","type":"string"},"internalNote":{"description":"Internal note (admin only).","type":"string"},"active":{"description":"Whether the product is active.","type":"boolean"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"price":{"description":"Price with VAT.","examples":[299.9],"type":"number"},"standardPricePercentage":{"description":"Standard price percentage for discount calculation.","examples":[100],"type":"number"},"vat":{"description":"VAT rate percentage.","examples":[21],"type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","examples":[150],"type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","examples":[200],"type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","examples":[50],"type":"number"},"weightGrams":{"description":"Product weight in grams.","examples":[500],"type":"number"},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","examples":[100],"type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","examples":[10],"type":"number"},"customFieldsRaw":{"description":"Custom fields key-value map for batch update.","type":"object","patternProperties":{"^(.*)$":{}}}}}},"text/plain":{"schema":{"type":"object","required":["name","code","locale"],"properties":{"name":{"minLength":1,"description":"Product name (will be normalized and capitalized).","examples":["My Product"],"type":"string"},"code":{"minLength":1,"description":"Product code (used to identify the product).","examples":["my-product"],"type":"string"},"locale":{"minLength":2,"maxLength":5,"description":"Locale code for translation (e.g. \"cs\", \"en\").","examples":["cs"],"type":"string"},"slug":{"description":"URL slug. If not provided, keeps existing slug.","examples":["my-product"],"type":"string"},"ean":{"description":"EAN barcode (validated, ignored if invalid).","examples":["8594000000123"],"type":"string"},"shortDescription":{"description":"Short HTML description.","type":"string"},"longDescription":{"description":"Long HTML description.","type":"string"},"internalNote":{"description":"Internal note (admin only).","type":"string"},"active":{"description":"Whether the product is active.","type":"boolean"},"b2b":{"description":"Whether the product is B2B only.","type":"boolean"},"showInFeed":{"description":"Whether the product appears in product feeds.","type":"boolean"},"soldOut":{"description":"Whether the product is sold out.","type":"boolean"},"price":{"description":"Price with VAT.","examples":[299.9],"type":"number"},"standardPricePercentage":{"description":"Standard price percentage for discount calculation.","examples":[100],"type":"number"},"vat":{"description":"VAT rate percentage.","examples":[21],"type":"number"},"sizeWidthMm":{"description":"Product width in millimeters.","examples":[150],"type":"number"},"sizeHeightMm":{"description":"Product height in millimeters.","examples":[200],"type":"number"},"sizeDepthMm":{"description":"Product depth in millimeters.","examples":[50],"type":"number"},"weightGrams":{"description":"Product weight in grams.","examples":[500],"type":"number"},"warehouseAllQuantity":{"description":"Total warehouse stock quantity.","examples":[100],"type":"number"},"warehouseLimit":{"description":"Minimum stock level before reorder alert.","examples":[10],"type":"number"},"customFieldsRaw":{"description":"Custom fields key-value map for batch update.","type":"object","patternProperties":{"^(.*)$":{}}}}}}}}}},"/bff/product/product-auto-translate":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"translatedLocales":{"description":"List of locale codes that were translated.","type":"array","items":{"description":"Locale code that was translated (e.g. \"en\", \"de\").","type":"string"}}},"required":["translatedLocales"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"translatedLocales":{"description":"List of locale codes that were translated.","type":"array","items":{"description":"Locale code that was translated (e.g. \"en\", \"de\").","type":"string"}}},"required":["translatedLocales"]}},"text/plain":{"schema":{"type":"object","properties":{"translatedLocales":{"description":"List of locale codes that were translated.","type":"array","items":{"description":"Locale code that was translated (e.g. \"en\", \"de\").","type":"string"}}},"required":["translatedLocales"]}}}}},"operationId":"postBffProductProduct-auto-translate","tags":["Product"],"summary":"Auto-translate product","description":"Automatically translates the product name, short description, and long description from the organisation default locale to all other configured organisation locales using AI. Existing translations are overwritten. After translation, the product read model is regenerated.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code to auto-translate.","examples":["my-product"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code to auto-translate.","examples":["my-product"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code to auto-translate.","examples":["my-product"],"type":"string"}}}}}}}},"/bff/product/product-voucher-template-list":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Linked voucher templates.","type":"array","items":{"type":"object","required":["voucherId","code","typeId","value","active"],"properties":{"voucherId":{"description":"Voucher ID.","type":"number"},"code":{"description":"Voucher code.","type":"string"},"typeId":{"description":"Voucher type ID.","type":"number"},"value":{"description":"Voucher value (percentage or absolute).","type":"string"},"active":{"description":"Whether the voucher is active.","type":"boolean"},"usageLimit":{"description":"Maximum number of times this voucher can be used.","type":"number"},"validFrom":{"description":"Voucher validity start date.","type":"string"},"validTo":{"description":"Voucher validity end date.","type":"string"}}}},"itemCount":{"description":"Total number of linked voucher templates.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Linked voucher templates.","type":"array","items":{"type":"object","required":["voucherId","code","typeId","value","active"],"properties":{"voucherId":{"description":"Voucher ID.","type":"number"},"code":{"description":"Voucher code.","type":"string"},"typeId":{"description":"Voucher type ID.","type":"number"},"value":{"description":"Voucher value (percentage or absolute).","type":"string"},"active":{"description":"Whether the voucher is active.","type":"boolean"},"usageLimit":{"description":"Maximum number of times this voucher can be used.","type":"number"},"validFrom":{"description":"Voucher validity start date.","type":"string"},"validTo":{"description":"Voucher validity end date.","type":"string"}}}},"itemCount":{"description":"Total number of linked voucher templates.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Linked voucher templates.","type":"array","items":{"type":"object","required":["voucherId","code","typeId","value","active"],"properties":{"voucherId":{"description":"Voucher ID.","type":"number"},"code":{"description":"Voucher code.","type":"string"},"typeId":{"description":"Voucher type ID.","type":"number"},"value":{"description":"Voucher value (percentage or absolute).","type":"string"},"active":{"description":"Whether the voucher is active.","type":"boolean"},"usageLimit":{"description":"Maximum number of times this voucher can be used.","type":"number"},"validFrom":{"description":"Voucher validity start date.","type":"string"},"validTo":{"description":"Voucher validity end date.","type":"string"}}}},"itemCount":{"description":"Total number of linked voucher templates.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProductProduct-voucher-template-list","tags":["Product"],"summary":"List linked voucher templates","description":"Returns all voucher templates linked to the product."}},"/bff/product/product-voucher-template-link":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was created.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was created.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was created.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-voucher-template-link","tags":["Product"],"summary":"Link voucher template to product","description":"Links a voucher template to a product. Idempotent — re-linking the same voucher is a no-op.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","voucherCode"],"properties":{"productCode":{"description":"Product code to link the voucher to.","examples":["my-product"],"type":"string"},"voucherCode":{"description":"Voucher code to link.","examples":["SUMMER2024"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","voucherCode"],"properties":{"productCode":{"description":"Product code to link the voucher to.","examples":["my-product"],"type":"string"},"voucherCode":{"description":"Voucher code to link.","examples":["SUMMER2024"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","voucherCode"],"properties":{"productCode":{"description":"Product code to link the voucher to.","examples":["my-product"],"type":"string"},"voucherCode":{"description":"Voucher code to link.","examples":["SUMMER2024"],"type":"string"}}}}}}}},"/bff/product/product-voucher-template-unlink":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was removed.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was removed.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was removed.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-voucher-template-unlink","tags":["Product"],"summary":"Unlink voucher template from product","description":"Removes the link between a voucher template and a product.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","voucherCode"],"properties":{"productCode":{"description":"Product code to unlink the voucher from.","examples":["my-product"],"type":"string"},"voucherCode":{"description":"Voucher code to unlink.","examples":["SUMMER2024"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","voucherCode"],"properties":{"productCode":{"description":"Product code to unlink the voucher from.","examples":["my-product"],"type":"string"},"voucherCode":{"description":"Voucher code to unlink.","examples":["SUMMER2024"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","voucherCode"],"properties":{"productCode":{"description":"Product code to unlink the voucher from.","examples":["my-product"],"type":"string"},"voucherCode":{"description":"Voucher code to unlink.","examples":["SUMMER2024"],"type":"string"}}}}}}}},"/bff/product/product-subscription-plan-list":{"get":{"parameters":[{"description":"Product code.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Linked subscription plans.","type":"array","items":{"type":"object","required":["interval"],"properties":{"interval":{"description":"Subscription interval (e.g. \"1m\", \"6m\", \"12m\").","type":"string"}}}},"itemCount":{"description":"Total number of linked subscription plans.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Linked subscription plans.","type":"array","items":{"type":"object","required":["interval"],"properties":{"interval":{"description":"Subscription interval (e.g. \"1m\", \"6m\", \"12m\").","type":"string"}}}},"itemCount":{"description":"Total number of linked subscription plans.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Linked subscription plans.","type":"array","items":{"type":"object","required":["interval"],"properties":{"interval":{"description":"Subscription interval (e.g. \"1m\", \"6m\", \"12m\").","type":"string"}}}},"itemCount":{"description":"Total number of linked subscription plans.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProductProduct-subscription-plan-list","tags":["Product"],"summary":"List linked subscription plans","description":"Returns all subscription plans linked to the product, including variant details and intervals."}},"/bff/product/product-subscription-plan-link":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the plan was linked.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the plan was linked.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the plan was linked.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-subscription-plan-link","tags":["Product"],"summary":"Link subscription plan to product","description":"Links a subscription plan (interval) to a product. If the product already has a plan, the interval is updated.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","interval"],"properties":{"productCode":{"description":"Product code.","examples":["my-product"],"type":"string"},"interval":{"description":"Subscription interval (e.g. \"1m\", \"6m\", \"12m\").","examples":["1m"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","interval"],"properties":{"productCode":{"description":"Product code.","examples":["my-product"],"type":"string"},"interval":{"description":"Subscription interval (e.g. \"1m\", \"6m\", \"12m\").","examples":["1m"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","interval"],"properties":{"productCode":{"description":"Product code.","examples":["my-product"],"type":"string"},"interval":{"description":"Subscription interval (e.g. \"1m\", \"6m\", \"12m\").","examples":["1m"],"type":"string"}}}}}}}},"/bff/product/product-subscription-plan-unlink":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the plan was removed.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the plan was removed.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the plan was removed.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-subscription-plan-unlink","tags":["Product"],"summary":"Unlink subscription plan from product","description":"Removes the subscription plan from a product.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code.","examples":["my-product"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code.","examples":["my-product"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode"],"properties":{"productCode":{"description":"Product code.","examples":["my-product"],"type":"string"}}}}}}}},"/bff/product/product-category-unset-main":{"get":{"parameters":[{"description":"Product code to unset the main category for.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main category was unset.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main category was unset.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main category was unset.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffProductProduct-category-unset-main","tags":["Product"],"summary":"Unset main product category","description":"Removes the main category from a product by setting it to null."}},"/bff/product/product-category-link":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was created.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was created.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was created.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-category-link","tags":["Product"],"summary":"Link category to product","description":"Links a related category to a product. Idempotent — re-linking the same category is a no-op.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","categoryCode"],"properties":{"productCode":{"description":"Product code to link the category to.","examples":["my-product"],"type":"string"},"categoryCode":{"description":"Category code to link.","examples":["electronics"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","categoryCode"],"properties":{"productCode":{"description":"Product code to link the category to.","examples":["my-product"],"type":"string"},"categoryCode":{"description":"Category code to link.","examples":["electronics"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","categoryCode"],"properties":{"productCode":{"description":"Product code to link the category to.","examples":["my-product"],"type":"string"},"categoryCode":{"description":"Category code to link.","examples":["electronics"],"type":"string"}}}}}}}},"/bff/product/product-category-unlink":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was removed.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was removed.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the link was removed.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-category-unlink","tags":["Product"],"summary":"Unlink category from product","description":"Removes the link between a related category and a product.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","categoryCode"],"properties":{"productCode":{"description":"Product code to unlink the category from.","examples":["my-product"],"type":"string"},"categoryCode":{"description":"Category code to unlink.","examples":["electronics"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","categoryCode"],"properties":{"productCode":{"description":"Product code to unlink the category from.","examples":["my-product"],"type":"string"},"categoryCode":{"description":"Category code to unlink.","examples":["electronics"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","categoryCode"],"properties":{"productCode":{"description":"Product code to unlink the category from.","examples":["my-product"],"type":"string"},"categoryCode":{"description":"Category code to unlink.","examples":["electronics"],"type":"string"}}}}}}}},"/bff/product-category/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Include soft-deleted categories (\"true\").","schema":{"type":"string"},"in":"query","name":"includeDeleted","required":false},{"description":"Return only soft-deleted categories (\"true\").","schema":{"type":"string"},"in":"query","name":"onlyDeleted","required":false}],"operationId":"getBffProduct-categoryList","tags":["Product Category"],"summary":"List product categories","description":"Returns a paginated flat list of product categories for datagrid display.","responses":{"200":{}}}},"/bff/product-category/list-selectbox":{"get":{"operationId":"getBffProduct-categoryList-selectbox","tags":["Product Category"],"summary":"List categories for selectbox","description":"Returns a lightweight list of categories formatted for select/dropdown components.","responses":{"200":{}}}},"/bff/product-category/list-with-counts":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Categories with at least one product, sorted by count DESC.","type":"array","items":{"type":"object","required":["code","name","productCount"],"properties":{"code":{"description":"Category code (used as filter value).","type":"string"},"name":{"description":"Category display name.","type":"string"},"productCount":{"description":"Number of non-deleted products with this main category.","type":"number"}}}},"noCategoryCount":{"description":"Number of non-deleted products with main_category_id IS NULL.","type":"number"},"totalCount":{"description":"Total number of non-deleted products in the organisation.","type":"number"}},"required":["items","noCategoryCount","totalCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Categories with at least one product, sorted by count DESC.","type":"array","items":{"type":"object","required":["code","name","productCount"],"properties":{"code":{"description":"Category code (used as filter value).","type":"string"},"name":{"description":"Category display name.","type":"string"},"productCount":{"description":"Number of non-deleted products with this main category.","type":"number"}}}},"noCategoryCount":{"description":"Number of non-deleted products with main_category_id IS NULL.","type":"number"},"totalCount":{"description":"Total number of non-deleted products in the organisation.","type":"number"}},"required":["items","noCategoryCount","totalCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Categories with at least one product, sorted by count DESC.","type":"array","items":{"type":"object","required":["code","name","productCount"],"properties":{"code":{"description":"Category code (used as filter value).","type":"string"},"name":{"description":"Category display name.","type":"string"},"productCount":{"description":"Number of non-deleted products with this main category.","type":"number"}}}},"noCategoryCount":{"description":"Number of non-deleted products with main_category_id IS NULL.","type":"number"},"totalCount":{"description":"Total number of non-deleted products in the organisation.","type":"number"}},"required":["items","noCategoryCount","totalCount"]}}}}},"operationId":"getBffProduct-categoryList-with-counts","tags":["Product Category"],"summary":"List categories with product counts","description":"Returns categories that have at least one non-deleted product assigned as their main category, sorted by product count DESC (then name ASC). Also returns the count of products with no main category and the grand total. Intended for the product-list filter dropdown."}},"/bff/product-category/tree":{"get":{"operationId":"getBffProduct-categoryTree","tags":["Product Category"],"summary":"Get category tree","description":"Returns the hierarchical tree structure of product categories with parent-child relationships.","responses":{"200":{}}}},"/bff/product-category/category-detail":{"get":{"parameters":[{"description":"Category unique code.","examples":["electronics"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"operationId":"getBffProduct-categoryCategory-detail","tags":["Product Category"],"summary":"Get category detail","description":"Returns full detail of a single product category by its code.","responses":{"200":{}}}},"/bff/product-category/category-create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"type":"string"},"slug":{"type":"string"}},"required":["success","code","slug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"type":"string"},"slug":{"type":"string"}},"required":["success","code","slug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"type":"string"},"slug":{"type":"string"}},"required":["success","code","slug"]}}}}},"operationId":"postBffProduct-categoryCategory-create","tags":["Product Category"],"summary":"Create product category","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","code"],"properties":{"name":{"description":"Category display name.","examples":["Electronics"],"type":"string"},"code":{"description":"Unique category code (slug-like).","examples":["electronics"],"type":"string"},"slug":{"description":"URL slug. Auto-generated from name if not provided.","type":"string"},"parentCode":{"description":"Parent category code for nesting.","examples":["root"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name","code"],"properties":{"name":{"description":"Category display name.","examples":["Electronics"],"type":"string"},"code":{"description":"Unique category code (slug-like).","examples":["electronics"],"type":"string"},"slug":{"description":"URL slug. Auto-generated from name if not provided.","type":"string"},"parentCode":{"description":"Parent category code for nesting.","examples":["root"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["name","code"],"properties":{"name":{"description":"Category display name.","examples":["Electronics"],"type":"string"},"code":{"description":"Unique category code (slug-like).","examples":["electronics"],"type":"string"},"slug":{"description":"URL slug. Auto-generated from name if not provided.","type":"string"},"parentCode":{"description":"Parent category code for nesting.","examples":["root"],"type":"string"}}}}}}}},"/bff/product-category/category-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-categoryCategory-update","tags":["Product Category"],"summary":"Update product category","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","code"],"properties":{"name":{"type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"parentCode":{"type":"string"},"description":{"type":"string"},"active":{"type":"boolean"},"internal":{"type":"boolean"},"b2b":{"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name","code"],"properties":{"name":{"type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"parentCode":{"type":"string"},"description":{"type":"string"},"active":{"type":"boolean"},"internal":{"type":"boolean"},"b2b":{"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["name","code"],"properties":{"name":{"type":"string"},"code":{"type":"string"},"slug":{"type":"string"},"parentCode":{"type":"string"},"description":{"type":"string"},"active":{"type":"boolean"},"internal":{"type":"boolean"},"b2b":{"type":"boolean"}}}}}}}},"/bff/product-category/category-delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"affected":{"type":"number"}},"required":["affected"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"affected":{"type":"number"}},"required":["affected"]}},"text/plain":{"schema":{"type":"object","properties":{"affected":{"type":"number"}},"required":["affected"]}}}}},"operationId":"postBffProduct-categoryCategory-delete","tags":["Product Category"],"summary":"Soft-delete product category","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"cascade":{"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"cascade":{"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"cascade":{"type":"boolean"}}}}}}}},"/bff/product-category/category-restore":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"restored":{"type":"boolean"},"parentReset":{"type":"boolean"}},"required":["restored"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"restored":{"type":"boolean"},"parentReset":{"type":"boolean"}},"required":["restored"]}},"text/plain":{"schema":{"type":"object","properties":{"restored":{"type":"boolean"},"parentReset":{"type":"boolean"}},"required":["restored"]}}}}},"operationId":"postBffProduct-categoryCategory-restore","tags":["Product Category"],"summary":"Restore soft-deleted category","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}}}}}}},"/bff/product-category/category-reorder":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"newPosition":{"type":"number"},"siblings":{"type":"number"}},"required":["newPosition","siblings"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"newPosition":{"type":"number"},"siblings":{"type":"number"}},"required":["newPosition","siblings"]}},"text/plain":{"schema":{"type":"object","properties":{"newPosition":{"type":"number"},"siblings":{"type":"number"}},"required":["newPosition","siblings"]}}}}},"operationId":"postBffProduct-categoryCategory-reorder","tags":["Product Category"],"summary":"Reorder / move category in tree","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","newPosition"],"properties":{"code":{"type":"string"},"newParentCode":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"newPosition":{"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","newPosition"],"properties":{"code":{"type":"string"},"newParentCode":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"newPosition":{"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["code","newPosition"],"properties":{"code":{"type":"string"},"newParentCode":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"newPosition":{"type":"number"}}}}}}}},"/bff/product-category/category-set-main-image":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-categoryCategory-set-main-image","tags":["Product Category"],"summary":"Set or remove category main image","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"blobToken":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"blobToken":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"blobToken":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/product-category/category-update-seo":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-categoryCategory-update-seo","tags":["Product Category"],"summary":"Update category SEO fields","description":"Updates meta_title, meta_description, canonical_url, noindex and og:image. Empty strings reset to NULL.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"metaTitle":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaDescription":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"canonicalUrl":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"noindex":{"type":"boolean"},"ogImageBlobToken":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"metaTitle":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaDescription":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"canonicalUrl":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"noindex":{"type":"boolean"},"ogImageBlobToken":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"metaTitle":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaDescription":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"canonicalUrl":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"noindex":{"type":"boolean"},"ogImageBlobToken":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/product-category/category-locale-upsert":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-categoryCategory-locale-upsert","tags":["Product Category"],"summary":"Upsert a category translation","description":"Creates or updates a translation row in shop__product_category_locale for the given locale.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","locale"],"properties":{"code":{"type":"string"},"locale":{"examples":["en"],"type":"string"},"name":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"slug":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaTitle":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaDescription":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","locale"],"properties":{"code":{"type":"string"},"locale":{"examples":["en"],"type":"string"},"name":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"slug":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaTitle":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaDescription":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code","locale"],"properties":{"code":{"type":"string"},"locale":{"examples":["en"],"type":"string"},"name":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"slug":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaTitle":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"metaDescription":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/product-category/category-locale-delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-categoryCategory-locale-delete","tags":["Product Category"],"summary":"Delete a category translation","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","locale"],"properties":{"code":{"type":"string"},"locale":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","locale"],"properties":{"code":{"type":"string"},"locale":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code","locale"],"properties":{"code":{"type":"string"},"locale":{"type":"string"}}}}}}}},"/bff/product-category/category-bulk":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"affected":{"type":"number"},"skipped":{"type":"number"}},"required":["affected","skipped"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"affected":{"type":"number"},"skipped":{"type":"number"}},"required":["affected","skipped"]}},"text/plain":{"schema":{"type":"object","properties":{"affected":{"type":"number"},"skipped":{"type":"number"}},"required":["affected","skipped"]}}}}},"operationId":"postBffProduct-categoryCategory-bulk","tags":["Product Category"],"summary":"Bulk operation on categories","description":"Apply an action to a set of categories by their codes. Supported: activate, deactivate, mark-internal, unmark-internal, mark-b2b, unmark-b2b, delete (always cascades), restore, change-parent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["codes","action"],"properties":{"codes":{"description":"Codes of categories to act on.","type":"array","items":{"type":"string"}},"action":{"anyOf":[{"const":"activate","type":"string"},{"const":"deactivate","type":"string"},{"const":"mark-internal","type":"string"},{"const":"unmark-internal","type":"string"},{"const":"mark-b2b","type":"string"},{"const":"unmark-b2b","type":"string"},{"const":"delete","type":"string"},{"const":"restore","type":"string"},{"const":"change-parent","type":"string"}]},"newParentCode":{"nullable":true,"anyOf":[{"description":"Only used with change-parent.","type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["codes","action"],"properties":{"codes":{"description":"Codes of categories to act on.","type":"array","items":{"type":"string"}},"action":{"anyOf":[{"const":"activate","type":"string"},{"const":"deactivate","type":"string"},{"const":"mark-internal","type":"string"},{"const":"unmark-internal","type":"string"},{"const":"mark-b2b","type":"string"},{"const":"unmark-b2b","type":"string"},{"const":"delete","type":"string"},{"const":"restore","type":"string"},{"const":"change-parent","type":"string"}]},"newParentCode":{"nullable":true,"anyOf":[{"description":"Only used with change-parent.","type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["codes","action"],"properties":{"codes":{"description":"Codes of categories to act on.","type":"array","items":{"type":"string"}},"action":{"anyOf":[{"const":"activate","type":"string"},{"const":"deactivate","type":"string"},{"const":"mark-internal","type":"string"},{"const":"unmark-internal","type":"string"},{"const":"mark-b2b","type":"string"},{"const":"unmark-b2b","type":"string"},{"const":"delete","type":"string"},{"const":"restore","type":"string"},{"const":"change-parent","type":"string"}]},"newParentCode":{"nullable":true,"anyOf":[{"description":"Only used with change-parent.","type":"string"},{"type":"null"}]}}}}}}}},"/bff/product-category/bulk-delete-preview":{"get":{"parameters":[{"description":"Comma-separated codes.","schema":{"type":"string"},"in":"query","name":"codes","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"direct":{"type":"number"},"descendants":{"type":"number"}},"required":["direct","descendants"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"direct":{"type":"number"},"descendants":{"type":"number"}},"required":["direct","descendants"]}},"text/plain":{"schema":{"type":"object","properties":{"direct":{"type":"number"},"descendants":{"type":"number"}},"required":["direct","descendants"]}}}}},"operationId":"getBffProduct-categoryBulk-delete-preview","tags":["Product Category"],"summary":"Preview cascade delete","description":"Returns how many categories total would be soft-deleted if the given codes were deleted with cascade."}},"/bff/product-category/export-csv":{"get":{"operationId":"getBffProduct-categoryExport-csv","tags":["Product Category"],"summary":"Export categories as CSV","description":"Streams a UTF-8 BOM CSV file with all non-deleted categories. Compatible with the importer.","responses":{"200":{}}}},"/bff/product-category/import-csv":{"post":{"parameters":[],"operationId":"postBffProduct-categoryImport-csv","tags":["Product Category"],"summary":"Import categories from CSV","description":"Validates and (if dryRun=false) applies the CSV. Existing categories are matched by `code` and updated; missing codes are inserted. The importer never deletes.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["csv"],"properties":{"csv":{"description":"Raw CSV content.","type":"string"},"dryRun":{"description":"If true, returns only the diff without applying.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["csv"],"properties":{"csv":{"description":"Raw CSV content.","type":"string"},"dryRun":{"description":"If true, returns only the diff without applying.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["csv"],"properties":{"csv":{"description":"Raw CSV content.","type":"string"},"dryRun":{"description":"If true, returns only the diff without applying.","type":"boolean"}}}}}},"responses":{"200":{}}}},"/bff/product-category/assignable-products":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"categoryCode","required":true},{"schema":{"type":"string"},"in":"query","name":"search","required":false},{"examples":["unassigned"],"schema":{"type":"string"},"in":"query","name":"scope","required":false},{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffProduct-categoryAssignable-products","tags":["Product Category"],"summary":"List products to (un)assign to/from a category","description":"Returns products with two flags: isMain (this category is product.main_category_id) and isInRel (it is linked via shop__product_rel_category). Use scope=unassigned (default) when adding, scope=assigned when removing.","responses":{"200":{}}}},"/bff/product-category/assign-products":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"affected":{"type":"number"},"missingProducts":{"type":"array","items":{"type":"string"}}},"required":["affected","missingProducts"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"affected":{"type":"number"},"missingProducts":{"type":"array","items":{"type":"string"}}},"required":["affected","missingProducts"]}},"text/plain":{"schema":{"type":"object","properties":{"affected":{"type":"number"},"missingProducts":{"type":"array","items":{"type":"string"}}},"required":["affected","missingProducts"]}}}}},"operationId":"postBffProduct-categoryAssign-products","tags":["Product Category"],"summary":"Bulk (un)assign products to a category","description":"mode=main sets the category as main_category_id (replaces existing); addRel links via shop__product_rel_category; removeRel removes the rel link.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["categoryCode","productCodes","mode"],"properties":{"categoryCode":{"type":"string"},"productCodes":{"type":"array","items":{"type":"string"}},"mode":{"anyOf":[{"const":"main","type":"string"},{"const":"addRel","type":"string"},{"const":"removeRel","type":"string"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["categoryCode","productCodes","mode"],"properties":{"categoryCode":{"type":"string"},"productCodes":{"type":"array","items":{"type":"string"}},"mode":{"anyOf":[{"const":"main","type":"string"},{"const":"addRel","type":"string"},{"const":"removeRel","type":"string"}]}}}},"text/plain":{"schema":{"type":"object","required":["categoryCode","productCodes","mode"],"properties":{"categoryCode":{"type":"string"},"productCodes":{"type":"array","items":{"type":"string"}},"mode":{"anyOf":[{"const":"main","type":"string"},{"const":"addRel","type":"string"},{"const":"removeRel","type":"string"}]}}}}}}}},"/bff/product-category/category-analytics":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"code","required":true}],"operationId":"getBffProduct-categoryCategory-analytics","tags":["Product Category"],"summary":"Category KPIs","description":"Returns 30-day revenue, order counts, top products, sparkline and stock health for the category subtree.","responses":{"200":{}}}},"/bff/product-category/category-update-schedule":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-categoryCategory-update-schedule","tags":["Product Category"],"summary":"Update category schedule + visibility rules","description":"Sets active_from / active_to (cron auto-toggles `active`) and visibility_rules JSONB.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"activeFrom":{"nullable":true,"anyOf":[{"description":"ISO timestamp. Empty/null clears the schedule.","type":"string"},{"type":"null"}]},"activeTo":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"visibilityRules":{"nullable":true,"anyOf":[{"type":"object","properties":{"customerGroups":{"type":"array","items":{"type":"string"}},"branches":{"type":"array","items":{"type":"string"}},"locales":{"type":"array","items":{"type":"string"}},"countries":{"type":"array","items":{"type":"string"}}}},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"activeFrom":{"nullable":true,"anyOf":[{"description":"ISO timestamp. Empty/null clears the schedule.","type":"string"},{"type":"null"}]},"activeTo":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"visibilityRules":{"nullable":true,"anyOf":[{"type":"object","properties":{"customerGroups":{"type":"array","items":{"type":"string"}},"branches":{"type":"array","items":{"type":"string"}},"locales":{"type":"array","items":{"type":"string"}},"countries":{"type":"array","items":{"type":"string"}}}},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"activeFrom":{"nullable":true,"anyOf":[{"description":"ISO timestamp. Empty/null clears the schedule.","type":"string"},{"type":"null"}]},"activeTo":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"visibilityRules":{"nullable":true,"anyOf":[{"type":"object","properties":{"customerGroups":{"type":"array","items":{"type":"string"}},"branches":{"type":"array","items":{"type":"string"}},"locales":{"type":"array","items":{"type":"string"}},"countries":{"type":"array","items":{"type":"string"}}}},{"type":"null"}]}}}}}}}},"/bff/product-category/category-update-feed-mapping":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-categoryCategory-update-feed-mapping","tags":["Product Category"],"summary":"Update feed taxonomy mapping","description":"Updates Heureka / Google / Glami category mapping fields used by export feeds.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"heurekaCategoryId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"googleTaxonomyId":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"glamiCategoryId":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"heurekaCategoryId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"googleTaxonomyId":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"glamiCategoryId":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"heurekaCategoryId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"googleTaxonomyId":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"glamiCategoryId":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/product-category/taxonomy-google":{"get":{"operationId":"getBffProduct-categoryTaxonomy-google","tags":["Product Category"],"summary":"Bundled Google Product Taxonomy","description":"Returns a compact extract of the Google Product Taxonomy for the autocomplete picker.","responses":{"200":{}}}},"/bff/product-category/category-custom-fields":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"code","required":true}],"operationId":"getBffProduct-categoryCategory-custom-fields","tags":["Product Category"],"summary":"List category-scoped custom field definitions","responses":{"200":{}}}},"/bff/product-category/category-custom-field-upsert":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}}}}},"operationId":"postBffProduct-categoryCategory-custom-field-upsert","tags":["Product Category"],"summary":"Create/update a category-scoped custom field","description":"Adds (or edits) a custom field definition that will be shown only for products whose main_category equals this category.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["categoryCode","key","type","label","required","active"],"properties":{"categoryCode":{"type":"string"},"id":{"type":"string"},"key":{"description":"snake_case identifier, 2-32 chars.","type":"string"},"type":{"examples":["text","number","boolean","date","select","url","email"],"type":"string"},"label":{"type":"string"},"helperText":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"placeholder":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"required":{"type":"boolean"},"active":{"type":"boolean"},"position":{"type":"number"},"validationPattern":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["categoryCode","key","type","label","required","active"],"properties":{"categoryCode":{"type":"string"},"id":{"type":"string"},"key":{"description":"snake_case identifier, 2-32 chars.","type":"string"},"type":{"examples":["text","number","boolean","date","select","url","email"],"type":"string"},"label":{"type":"string"},"helperText":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"placeholder":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"required":{"type":"boolean"},"active":{"type":"boolean"},"position":{"type":"number"},"validationPattern":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["categoryCode","key","type","label","required","active"],"properties":{"categoryCode":{"type":"string"},"id":{"type":"string"},"key":{"description":"snake_case identifier, 2-32 chars.","type":"string"},"type":{"examples":["text","number","boolean","date","select","url","email"],"type":"string"},"label":{"type":"string"},"helperText":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"placeholder":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"required":{"type":"boolean"},"active":{"type":"boolean"},"position":{"type":"number"},"validationPattern":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/product-category/category-custom-field-delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-categoryCategory-custom-field-delete","tags":["Product Category"],"summary":"Delete a category-scoped custom field","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}}}}}}},"/bff/product-category/category-ai-suggest":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string"},"metaTitle":{"type":"string"},"metaDescription":{"type":"string"},"imageAlt":{"type":"string"}},"required":["description","metaTitle","metaDescription","imageAlt"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"description":{"type":"string"},"metaTitle":{"type":"string"},"metaDescription":{"type":"string"},"imageAlt":{"type":"string"}},"required":["description","metaTitle","metaDescription","imageAlt"]}},"text/plain":{"schema":{"type":"object","properties":{"description":{"type":"string"},"metaTitle":{"type":"string"},"metaDescription":{"type":"string"},"imageAlt":{"type":"string"}},"required":["description","metaTitle","metaDescription","imageAlt"]}}}}},"operationId":"postBffProduct-categoryCategory-ai-suggest","tags":["Product Category"],"summary":"AI: generate category description + SEO","description":"Uses Claude (via askAIJson) and the categorys products to produce description, metaTitle, metaDescription, imageAlt.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"locale":{"type":"string"},"styleHint":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"locale":{"type":"string"},"styleHint":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"locale":{"type":"string"},"styleHint":{"type":"string"}}}}}}}},"/bff/product-category/category-ai-restructure-suggest":{"post":{"parameters":[],"operationId":"postBffProduct-categoryCategory-ai-restructure-suggest","tags":["Product Category"],"summary":"AI: propose a new category hierarchy","description":"Reads existing categories + sample products and proposes a cleaner tree. Returns the plan only — apply via /category-ai-restructure-apply.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"locale":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"locale":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"locale":{"type":"string"}}}}}},"responses":{"200":{}}}},"/bff/product-category/category-ai-restructure-apply":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"number"},"moved":{"type":"number"},"deprecated":{"type":"number"}},"required":["created","moved","deprecated"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"created":{"type":"number"},"moved":{"type":"number"},"deprecated":{"type":"number"}},"required":["created","moved","deprecated"]}},"text/plain":{"schema":{"type":"object","properties":{"created":{"type":"number"},"moved":{"type":"number"},"deprecated":{"type":"number"}},"required":["created","moved","deprecated"]}}}}},"operationId":"postBffProduct-categoryCategory-ai-restructure-apply","tags":["Product Category"],"summary":"AI: apply a proposed restructure","description":"Moves / creates categories according to the (possibly-edited) plan. Categories listed in toDeprecate are soft-deleted with cascade.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tree","toDeprecate"],"properties":{"tree":{"description":"Tree shape returned by /category-ai-restructure-suggest (possibly user-edited)."},"toDeprecate":{"type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["tree","toDeprecate"],"properties":{"tree":{"description":"Tree shape returned by /category-ai-restructure-suggest (possibly user-edited)."},"toDeprecate":{"type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["tree","toDeprecate"],"properties":{"tree":{"description":"Tree shape returned by /category-ai-restructure-suggest (possibly user-edited)."},"toDeprecate":{"type":"array","items":{"type":"string"}}}}}}}}},"/bff/product-parameter/group-list":{"get":{"responses":{"200":{"description":"List of parameter groups.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"All parameter groups ordered by position then name.","type":"array","items":{"description":"Parameter group item.","type":"object","required":["id","code","name","position","active"],"properties":{"id":{"description":"Internal group ID.","type":"number"},"code":{"description":"Unique group code (URL-friendly slug).","type":"string"},"name":{"description":"Display name of the group.","type":"string"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the group is active.","type":"boolean"}}}},"itemCount":{"description":"Total number of groups.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"All parameter groups ordered by position then name.","type":"array","items":{"description":"Parameter group item.","type":"object","required":["id","code","name","position","active"],"properties":{"id":{"description":"Internal group ID.","type":"number"},"code":{"description":"Unique group code (URL-friendly slug).","type":"string"},"name":{"description":"Display name of the group.","type":"string"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the group is active.","type":"boolean"}}}},"itemCount":{"description":"Total number of groups.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"All parameter groups ordered by position then name.","type":"array","items":{"description":"Parameter group item.","type":"object","required":["id","code","name","position","active"],"properties":{"id":{"description":"Internal group ID.","type":"number"},"code":{"description":"Unique group code (URL-friendly slug).","type":"string"},"name":{"description":"Display name of the group.","type":"string"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the group is active.","type":"boolean"}}}},"itemCount":{"description":"Total number of groups.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProduct-parameterGroup-list","tags":["Product Parameter"],"summary":"List parameter groups","description":"Returns all parameter groups for the authenticated organisation. Groups are used to visually organize parameters into sections (e.g. \"Dimensions\", \"Technical specs\")."}},"/bff/product-parameter/group-add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created group.","type":"number"},"code":{"description":"Final code of the created group (after slugification).","type":"string"}},"required":["id","code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created group.","type":"number"},"code":{"description":"Final code of the created group (after slugification).","type":"string"}},"required":["id","code"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created group.","type":"number"},"code":{"description":"Final code of the created group (after slugification).","type":"string"}},"required":["id","code"]}}}}},"operationId":"postBffProduct-parameterGroup-add","tags":["Product Parameter"],"summary":"Create parameter group","description":"Creates a new parameter group for organizing parameters into logical sections. The code is auto-generated from the name if not provided.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Display name for the group (e.g. \"Technical specs\").","examples":["Technical specs"],"type":"string"},"code":{"description":"URL-friendly code. If not provided, generated from name via slugification.","examples":["technical-specs"],"type":"string"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Display name for the group (e.g. \"Technical specs\").","examples":["Technical specs"],"type":"string"},"code":{"description":"URL-friendly code. If not provided, generated from name via slugification.","examples":["technical-specs"],"type":"string"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Display name for the group (e.g. \"Technical specs\").","examples":["Technical specs"],"type":"string"},"code":{"description":"URL-friendly code. If not provided, generated from name via slugification.","examples":["technical-specs"],"type":"string"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}}}}}},"/bff/product-parameter/group-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the group was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the group was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the group was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterGroup-update","tags":["Product Parameter"],"summary":"Update parameter group","description":"Updates properties of an existing parameter group. Only provided fields are changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to update.","examples":["technical-specs"],"type":"string"},"name":{"description":"New display name.","examples":["Dimensions"],"type":"string"},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to update.","examples":["technical-specs"],"type":"string"},"name":{"description":"New display name.","examples":["Dimensions"],"type":"string"},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to update.","examples":["technical-specs"],"type":"string"},"name":{"description":"New display name.","examples":["Dimensions"],"type":"string"},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}}}}}},"/bff/product-parameter/group-delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the group was deleted.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the group was deleted.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the group was deleted.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterGroup-delete","tags":["Product Parameter"],"summary":"Delete parameter group","description":"Deletes a parameter group. Parameters in this group will have their group_id set to NULL (ungrouped). Fails if the group does not exist.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to delete.","examples":["technical-specs"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to delete.","examples":["technical-specs"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to delete.","examples":["technical-specs"],"type":"string"}}}}}}}},"/bff/product-parameter/list":{"get":{"parameters":[{"description":"Filter parameters by group code. If not provided, returns all parameters.","examples":["technical-specs"],"schema":{"type":"string"},"in":"query","name":"groupCode","required":false}],"responses":{"200":{"description":"List of parameter definitions.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Parameters ordered by position then name.","type":"array","items":{"description":"Parameter definition item.","type":"object","required":["id","code","name","type","filterable","comparable","variantForming","multiValue","position","active","valueCount"],"properties":{"id":{"description":"Internal parameter ID.","type":"number"},"code":{"description":"Unique parameter code.","type":"string"},"name":{"description":"Display name of the parameter.","type":"string"},"group":{"description":"Group this parameter belongs to. Undefined if ungrouped.","type":"object","required":["code","name"],"properties":{"code":{"description":"Group code.","type":"string"},"name":{"description":"Group display name.","type":"string"}}},"type":{"description":"Data type: string, number, boolean, enum, or color.","type":"string"},"unit":{"description":"Unit label (e.g. \"mm\", \"kg\"). Only for number type.","type":"string"},"filterable":{"description":"Whether this parameter should appear in frontend product filters.","type":"boolean"},"comparable":{"description":"Whether this parameter should appear in the product comparison table.","type":"boolean"},"variantForming":{"description":"Whether this parameter forms product variants (e.g. \"Size\" creates variants, \"Material\" does not). Only enum/color.","type":"boolean"},"multiValue":{"description":"Whether a product can have multiple values for this parameter (e.g. multiple colors). Only enum/color.","type":"boolean"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the parameter is active.","type":"boolean"},"valueCount":{"description":"Number of predefined values (relevant for enum/color types).","type":"number"}}}},"itemCount":{"description":"Total number of parameters.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Parameters ordered by position then name.","type":"array","items":{"description":"Parameter definition item.","type":"object","required":["id","code","name","type","filterable","comparable","variantForming","multiValue","position","active","valueCount"],"properties":{"id":{"description":"Internal parameter ID.","type":"number"},"code":{"description":"Unique parameter code.","type":"string"},"name":{"description":"Display name of the parameter.","type":"string"},"group":{"description":"Group this parameter belongs to. Undefined if ungrouped.","type":"object","required":["code","name"],"properties":{"code":{"description":"Group code.","type":"string"},"name":{"description":"Group display name.","type":"string"}}},"type":{"description":"Data type: string, number, boolean, enum, or color.","type":"string"},"unit":{"description":"Unit label (e.g. \"mm\", \"kg\"). Only for number type.","type":"string"},"filterable":{"description":"Whether this parameter should appear in frontend product filters.","type":"boolean"},"comparable":{"description":"Whether this parameter should appear in the product comparison table.","type":"boolean"},"variantForming":{"description":"Whether this parameter forms product variants (e.g. \"Size\" creates variants, \"Material\" does not). Only enum/color.","type":"boolean"},"multiValue":{"description":"Whether a product can have multiple values for this parameter (e.g. multiple colors). Only enum/color.","type":"boolean"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the parameter is active.","type":"boolean"},"valueCount":{"description":"Number of predefined values (relevant for enum/color types).","type":"number"}}}},"itemCount":{"description":"Total number of parameters.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Parameters ordered by position then name.","type":"array","items":{"description":"Parameter definition item.","type":"object","required":["id","code","name","type","filterable","comparable","variantForming","multiValue","position","active","valueCount"],"properties":{"id":{"description":"Internal parameter ID.","type":"number"},"code":{"description":"Unique parameter code.","type":"string"},"name":{"description":"Display name of the parameter.","type":"string"},"group":{"description":"Group this parameter belongs to. Undefined if ungrouped.","type":"object","required":["code","name"],"properties":{"code":{"description":"Group code.","type":"string"},"name":{"description":"Group display name.","type":"string"}}},"type":{"description":"Data type: string, number, boolean, enum, or color.","type":"string"},"unit":{"description":"Unit label (e.g. \"mm\", \"kg\"). Only for number type.","type":"string"},"filterable":{"description":"Whether this parameter should appear in frontend product filters.","type":"boolean"},"comparable":{"description":"Whether this parameter should appear in the product comparison table.","type":"boolean"},"variantForming":{"description":"Whether this parameter forms product variants (e.g. \"Size\" creates variants, \"Material\" does not). Only enum/color.","type":"boolean"},"multiValue":{"description":"Whether a product can have multiple values for this parameter (e.g. multiple colors). Only enum/color.","type":"boolean"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the parameter is active.","type":"boolean"},"valueCount":{"description":"Number of predefined values (relevant for enum/color types).","type":"number"}}}},"itemCount":{"description":"Total number of parameters.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProduct-parameterList","tags":["Product Parameter"],"summary":"List parameters","description":"Returns all parameter definitions for the organisation. Each parameter includes its type, flags, associated group, and count of predefined values (for enum/color types). Optionally filtered by group code."}},"/bff/product-parameter/add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created parameter.","type":"number"},"code":{"description":"Final code after slugification.","type":"string"}},"required":["id","code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created parameter.","type":"number"},"code":{"description":"Final code after slugification.","type":"string"}},"required":["id","code"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created parameter.","type":"number"},"code":{"description":"Final code after slugification.","type":"string"}},"required":["id","code"]}}}}},"operationId":"postBffProduct-parameterAdd","tags":["Product Parameter"],"summary":"Create parameter","description":"Creates a new parameter definition. For enum/color types, add predefined values afterwards via /value-add. DB-level constraints enforce: variant_forming only for enum/color; multi_value only for enum/color.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Display name (e.g. \"Weight\", \"Color\", \"Material\").","examples":["Weight"],"type":"string"},"code":{"description":"URL-friendly code. Auto-generated from name if not provided.","examples":["weight"],"type":"string"},"groupCode":{"description":"Code of the group to assign the parameter to. Omit for ungrouped.","examples":["technical-specs"],"type":"string"},"type":{"description":"Parameter data type. \"string\" = free text, \"number\" = numeric with optional unit, \"boolean\" = true/false, \"enum\" = predefined list of values, \"color\" = predefined colors with hex codes.","anyOf":[{"const":"string","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"enum","type":"string"},{"const":"color","type":"string"}]},"unit":{"description":"Unit label for number type (e.g. \"mm\", \"kg\", \"W\").","examples":["kg"],"type":"string"},"filterable":{"description":"Show in frontend filters. Defaults to false.","type":"boolean"},"comparable":{"description":"Show in product comparison. Defaults to false.","type":"boolean"},"variantForming":{"description":"Whether this parameter creates product variants. Only allowed for enum/color type. Defaults to false.","type":"boolean"},"multiValue":{"description":"Allow multiple values per product. Only allowed for enum/color type. Defaults to false.","type":"boolean"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Display name (e.g. \"Weight\", \"Color\", \"Material\").","examples":["Weight"],"type":"string"},"code":{"description":"URL-friendly code. Auto-generated from name if not provided.","examples":["weight"],"type":"string"},"groupCode":{"description":"Code of the group to assign the parameter to. Omit for ungrouped.","examples":["technical-specs"],"type":"string"},"type":{"description":"Parameter data type. \"string\" = free text, \"number\" = numeric with optional unit, \"boolean\" = true/false, \"enum\" = predefined list of values, \"color\" = predefined colors with hex codes.","anyOf":[{"const":"string","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"enum","type":"string"},{"const":"color","type":"string"}]},"unit":{"description":"Unit label for number type (e.g. \"mm\", \"kg\", \"W\").","examples":["kg"],"type":"string"},"filterable":{"description":"Show in frontend filters. Defaults to false.","type":"boolean"},"comparable":{"description":"Show in product comparison. Defaults to false.","type":"boolean"},"variantForming":{"description":"Whether this parameter creates product variants. Only allowed for enum/color type. Defaults to false.","type":"boolean"},"multiValue":{"description":"Allow multiple values per product. Only allowed for enum/color type. Defaults to false.","type":"boolean"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["name"],"properties":{"name":{"minLength":1,"description":"Display name (e.g. \"Weight\", \"Color\", \"Material\").","examples":["Weight"],"type":"string"},"code":{"description":"URL-friendly code. Auto-generated from name if not provided.","examples":["weight"],"type":"string"},"groupCode":{"description":"Code of the group to assign the parameter to. Omit for ungrouped.","examples":["technical-specs"],"type":"string"},"type":{"description":"Parameter data type. \"string\" = free text, \"number\" = numeric with optional unit, \"boolean\" = true/false, \"enum\" = predefined list of values, \"color\" = predefined colors with hex codes.","anyOf":[{"const":"string","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"enum","type":"string"},{"const":"color","type":"string"}]},"unit":{"description":"Unit label for number type (e.g. \"mm\", \"kg\", \"W\").","examples":["kg"],"type":"string"},"filterable":{"description":"Show in frontend filters. Defaults to false.","type":"boolean"},"comparable":{"description":"Show in product comparison. Defaults to false.","type":"boolean"},"variantForming":{"description":"Whether this parameter creates product variants. Only allowed for enum/color type. Defaults to false.","type":"boolean"},"multiValue":{"description":"Allow multiple values per product. Only allowed for enum/color type. Defaults to false.","type":"boolean"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}}}}}},"/bff/product-parameter/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the parameter was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the parameter was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the parameter was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterUpdate","tags":["Product Parameter"],"summary":"Update parameter","description":"Updates properties of an existing parameter definition. Only provided fields are changed. Changing the type does not automatically migrate existing product assignments.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the parameter to update.","examples":["weight"],"type":"string"},"name":{"description":"New display name.","examples":["Net Weight"],"type":"string"},"groupCode":{"nullable":true,"anyOf":[{"description":"New group code, or null to ungroup the parameter.","examples":["technical-specs"],"type":"string"},{"type":"null"}]},"type":{"description":"Parameter data type. \"string\" = free text, \"number\" = numeric with optional unit, \"boolean\" = true/false, \"enum\" = predefined list of values, \"color\" = predefined colors with hex codes.","anyOf":[{"const":"string","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"enum","type":"string"},{"const":"color","type":"string"}]},"unit":{"nullable":true,"anyOf":[{"description":"New unit label, or null to clear.","examples":["g"],"type":"string"},{"type":"null"}]},"filterable":{"description":"New filterable flag.","type":"boolean"},"comparable":{"description":"New comparable flag.","type":"boolean"},"variantForming":{"description":"New variant-forming flag.","type":"boolean"},"multiValue":{"description":"New multi-value flag.","type":"boolean"},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the parameter to update.","examples":["weight"],"type":"string"},"name":{"description":"New display name.","examples":["Net Weight"],"type":"string"},"groupCode":{"nullable":true,"anyOf":[{"description":"New group code, or null to ungroup the parameter.","examples":["technical-specs"],"type":"string"},{"type":"null"}]},"type":{"description":"Parameter data type. \"string\" = free text, \"number\" = numeric with optional unit, \"boolean\" = true/false, \"enum\" = predefined list of values, \"color\" = predefined colors with hex codes.","anyOf":[{"const":"string","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"enum","type":"string"},{"const":"color","type":"string"}]},"unit":{"nullable":true,"anyOf":[{"description":"New unit label, or null to clear.","examples":["g"],"type":"string"},{"type":"null"}]},"filterable":{"description":"New filterable flag.","type":"boolean"},"comparable":{"description":"New comparable flag.","type":"boolean"},"variantForming":{"description":"New variant-forming flag.","type":"boolean"},"multiValue":{"description":"New multi-value flag.","type":"boolean"},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the parameter to update.","examples":["weight"],"type":"string"},"name":{"description":"New display name.","examples":["Net Weight"],"type":"string"},"groupCode":{"nullable":true,"anyOf":[{"description":"New group code, or null to ungroup the parameter.","examples":["technical-specs"],"type":"string"},{"type":"null"}]},"type":{"description":"Parameter data type. \"string\" = free text, \"number\" = numeric with optional unit, \"boolean\" = true/false, \"enum\" = predefined list of values, \"color\" = predefined colors with hex codes.","anyOf":[{"const":"string","type":"string"},{"const":"number","type":"string"},{"const":"boolean","type":"string"},{"const":"enum","type":"string"},{"const":"color","type":"string"}]},"unit":{"nullable":true,"anyOf":[{"description":"New unit label, or null to clear.","examples":["g"],"type":"string"},{"type":"null"}]},"filterable":{"description":"New filterable flag.","type":"boolean"},"comparable":{"description":"New comparable flag.","type":"boolean"},"variantForming":{"description":"New variant-forming flag.","type":"boolean"},"multiValue":{"description":"New multi-value flag.","type":"boolean"},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}}}}}},"/bff/product-parameter/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the parameter was deleted.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the parameter was deleted.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the parameter was deleted.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterDelete","tags":["Product Parameter"],"summary":"Delete parameter","description":"Deletes a parameter definition. Cascades to all predefined values, product assignments, category mappings, and locale translations associated with this parameter.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the parameter to delete.","examples":["weight"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the parameter to delete.","examples":["weight"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the parameter to delete.","examples":["weight"],"type":"string"}}}}}}}},"/bff/product-parameter/value-list":{"get":{"parameters":[{"description":"Code of the enum/color parameter to list values for.","examples":["color","size"],"schema":{"type":"string"},"in":"query","name":"parameterCode","required":true}],"responses":{"200":{"description":"List of predefined parameter values.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Values ordered by position then label.","type":"array","items":{"description":"Predefined parameter value.","type":"object","required":["id","code","label","position","active"],"properties":{"id":{"description":"Internal value ID.","type":"number"},"code":{"description":"Unique value code within this parameter.","type":"string"},"label":{"description":"Display label (e.g. \"Red\", \"XL\", \"Cotton\").","type":"string"},"colorHex":{"description":"Hex color code (e.g. \"#FF5733\"). Only for color-type parameters.","type":"string"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the value is active.","type":"boolean"}}}},"itemCount":{"description":"Total number of values.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Values ordered by position then label.","type":"array","items":{"description":"Predefined parameter value.","type":"object","required":["id","code","label","position","active"],"properties":{"id":{"description":"Internal value ID.","type":"number"},"code":{"description":"Unique value code within this parameter.","type":"string"},"label":{"description":"Display label (e.g. \"Red\", \"XL\", \"Cotton\").","type":"string"},"colorHex":{"description":"Hex color code (e.g. \"#FF5733\"). Only for color-type parameters.","type":"string"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the value is active.","type":"boolean"}}}},"itemCount":{"description":"Total number of values.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Values ordered by position then label.","type":"array","items":{"description":"Predefined parameter value.","type":"object","required":["id","code","label","position","active"],"properties":{"id":{"description":"Internal value ID.","type":"number"},"code":{"description":"Unique value code within this parameter.","type":"string"},"label":{"description":"Display label (e.g. \"Red\", \"XL\", \"Cotton\").","type":"string"},"colorHex":{"description":"Hex color code (e.g. \"#FF5733\"). Only for color-type parameters.","type":"string"},"position":{"description":"Sort order position.","type":"number"},"active":{"description":"Whether the value is active.","type":"boolean"}}}},"itemCount":{"description":"Total number of values.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProduct-parameterValue-list","tags":["Product Parameter"],"summary":"List parameter values","description":"Returns all predefined values for an enum or color parameter. Values are ordered by position then label. Each value has a code (for API use) and a label (for display)."}},"/bff/product-parameter/value-add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created value.","type":"number"},"code":{"description":"Final code after slugification.","type":"string"}},"required":["id","code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created value.","type":"number"},"code":{"description":"Final code after slugification.","type":"string"}},"required":["id","code"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"ID of the created value.","type":"number"},"code":{"description":"Final code after slugification.","type":"string"}},"required":["id","code"]}}}}},"operationId":"postBffProduct-parameterValue-add","tags":["Product Parameter"],"summary":"Add parameter value","description":"Adds a new predefined value to an enum or color parameter. Fails if the parameter type is not enum or color.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["parameterCode","label"],"properties":{"parameterCode":{"description":"Code of the enum/color parameter to add the value to.","examples":["color"],"type":"string"},"label":{"minLength":1,"description":"Display label (e.g. \"Red\", \"Large\").","examples":["Red"],"type":"string"},"code":{"description":"URL-friendly value code. Auto-generated from label if not provided.","examples":["red"],"type":"string"},"colorHex":{"description":"Hex color code for color-type parameters (e.g. \"#FF5733\"). Validated format.","examples":["#FF5733"],"type":"string"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["parameterCode","label"],"properties":{"parameterCode":{"description":"Code of the enum/color parameter to add the value to.","examples":["color"],"type":"string"},"label":{"minLength":1,"description":"Display label (e.g. \"Red\", \"Large\").","examples":["Red"],"type":"string"},"code":{"description":"URL-friendly value code. Auto-generated from label if not provided.","examples":["red"],"type":"string"},"colorHex":{"description":"Hex color code for color-type parameters (e.g. \"#FF5733\"). Validated format.","examples":["#FF5733"],"type":"string"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["parameterCode","label"],"properties":{"parameterCode":{"description":"Code of the enum/color parameter to add the value to.","examples":["color"],"type":"string"},"label":{"minLength":1,"description":"Display label (e.g. \"Red\", \"Large\").","examples":["Red"],"type":"string"},"code":{"description":"URL-friendly value code. Auto-generated from label if not provided.","examples":["red"],"type":"string"},"colorHex":{"description":"Hex color code for color-type parameters (e.g. \"#FF5733\"). Validated format.","examples":["#FF5733"],"type":"string"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}}}}}},"/bff/product-parameter/value-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterValue-update","tags":["Product Parameter"],"summary":"Update parameter value","description":"Updates properties of a predefined parameter value. Only provided fields are changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["parameterCode","valueCode"],"properties":{"parameterCode":{"description":"Code of the parameter the value belongs to.","examples":["color"],"type":"string"},"valueCode":{"description":"Code of the value to update.","examples":["red"],"type":"string"},"label":{"description":"New display label.","examples":["Dark Red"],"type":"string"},"colorHex":{"nullable":true,"anyOf":[{"description":"New hex color code, or null to clear.","examples":["#8B0000"],"type":"string"},{"type":"null"}]},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["parameterCode","valueCode"],"properties":{"parameterCode":{"description":"Code of the parameter the value belongs to.","examples":["color"],"type":"string"},"valueCode":{"description":"Code of the value to update.","examples":["red"],"type":"string"},"label":{"description":"New display label.","examples":["Dark Red"],"type":"string"},"colorHex":{"nullable":true,"anyOf":[{"description":"New hex color code, or null to clear.","examples":["#8B0000"],"type":"string"},{"type":"null"}]},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["parameterCode","valueCode"],"properties":{"parameterCode":{"description":"Code of the parameter the value belongs to.","examples":["color"],"type":"string"},"valueCode":{"description":"Code of the value to update.","examples":["red"],"type":"string"},"label":{"description":"New display label.","examples":["Dark Red"],"type":"string"},"colorHex":{"nullable":true,"anyOf":[{"description":"New hex color code, or null to clear.","examples":["#8B0000"],"type":"string"},{"type":"null"}]},"position":{"description":"New sort order position.","examples":[1],"type":"number"},"active":{"description":"New active status.","examples":[true],"type":"boolean"}}}}}}}},"/bff/product-parameter/value-delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was deleted.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was deleted.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was deleted.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterValue-delete","tags":["Product Parameter"],"summary":"Delete parameter value","description":"Deletes a predefined parameter value. Cascades to all product assignments that reference this value and all locale translations.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["parameterCode","valueCode"],"properties":{"parameterCode":{"description":"Code of the parameter the value belongs to.","examples":["color"],"type":"string"},"valueCode":{"description":"Code of the value to delete.","examples":["red"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["parameterCode","valueCode"],"properties":{"parameterCode":{"description":"Code of the parameter the value belongs to.","examples":["color"],"type":"string"},"valueCode":{"description":"Code of the value to delete.","examples":["red"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["parameterCode","valueCode"],"properties":{"parameterCode":{"description":"Code of the parameter the value belongs to.","examples":["color"],"type":"string"},"valueCode":{"description":"Code of the value to delete.","examples":["red"],"type":"string"}}}}}}}},"/bff/product-parameter/product-values":{"get":{"parameters":[{"description":"Product code to list parameter values for.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true}],"responses":{"200":{"description":"Product parameter values.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"All parameter assignments for the product.","type":"array","items":{"description":"Single parameter assignment on a product.","type":"object","required":["assignmentId","parameterCode","parameterName","parameterType"],"properties":{"assignmentId":{"description":"Unique assignment ID (used to remove the assignment).","type":"number"},"parameterCode":{"description":"Parameter code.","type":"string"},"parameterName":{"description":"Parameter display name.","type":"string"},"parameterType":{"description":"Parameter data type.","type":"string"},"parameterUnit":{"description":"Parameter unit (e.g. \"mm\").","type":"string"},"groupCode":{"description":"Group code, if the parameter is grouped.","type":"string"},"groupName":{"description":"Group display name.","type":"string"},"valueCode":{"description":"Predefined value code (for enum/color types).","type":"string"},"valueLabel":{"description":"Predefined value display label (for enum/color types).","type":"string"},"colorHex":{"description":"Hex color code (for color-type values).","type":"string"},"valueString":{"description":"Free-text value (for string type).","type":"string"},"valueNumber":{"description":"Numeric value (for number type).","type":"number"},"valueBoolean":{"description":"Boolean value (for boolean type).","type":"boolean"},"variantCode":{"description":"Variant code if this assignment is variant-specific. Undefined for product-level.","type":"string"}}}},"itemCount":{"description":"Total number of assignments.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"All parameter assignments for the product.","type":"array","items":{"description":"Single parameter assignment on a product.","type":"object","required":["assignmentId","parameterCode","parameterName","parameterType"],"properties":{"assignmentId":{"description":"Unique assignment ID (used to remove the assignment).","type":"number"},"parameterCode":{"description":"Parameter code.","type":"string"},"parameterName":{"description":"Parameter display name.","type":"string"},"parameterType":{"description":"Parameter data type.","type":"string"},"parameterUnit":{"description":"Parameter unit (e.g. \"mm\").","type":"string"},"groupCode":{"description":"Group code, if the parameter is grouped.","type":"string"},"groupName":{"description":"Group display name.","type":"string"},"valueCode":{"description":"Predefined value code (for enum/color types).","type":"string"},"valueLabel":{"description":"Predefined value display label (for enum/color types).","type":"string"},"colorHex":{"description":"Hex color code (for color-type values).","type":"string"},"valueString":{"description":"Free-text value (for string type).","type":"string"},"valueNumber":{"description":"Numeric value (for number type).","type":"number"},"valueBoolean":{"description":"Boolean value (for boolean type).","type":"boolean"},"variantCode":{"description":"Variant code if this assignment is variant-specific. Undefined for product-level.","type":"string"}}}},"itemCount":{"description":"Total number of assignments.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"All parameter assignments for the product.","type":"array","items":{"description":"Single parameter assignment on a product.","type":"object","required":["assignmentId","parameterCode","parameterName","parameterType"],"properties":{"assignmentId":{"description":"Unique assignment ID (used to remove the assignment).","type":"number"},"parameterCode":{"description":"Parameter code.","type":"string"},"parameterName":{"description":"Parameter display name.","type":"string"},"parameterType":{"description":"Parameter data type.","type":"string"},"parameterUnit":{"description":"Parameter unit (e.g. \"mm\").","type":"string"},"groupCode":{"description":"Group code, if the parameter is grouped.","type":"string"},"groupName":{"description":"Group display name.","type":"string"},"valueCode":{"description":"Predefined value code (for enum/color types).","type":"string"},"valueLabel":{"description":"Predefined value display label (for enum/color types).","type":"string"},"colorHex":{"description":"Hex color code (for color-type values).","type":"string"},"valueString":{"description":"Free-text value (for string type).","type":"string"},"valueNumber":{"description":"Numeric value (for number type).","type":"number"},"valueBoolean":{"description":"Boolean value (for boolean type).","type":"boolean"},"variantCode":{"description":"Variant code if this assignment is variant-specific. Undefined for product-level.","type":"string"}}}},"itemCount":{"description":"Total number of assignments.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProduct-parameterProduct-values","tags":["Product Parameter"],"summary":"List product parameter values","description":"Returns all parameter values assigned to a product, including variant-level assignments. Each assignment contains the parameter definition, the concrete value (enum, string, number, or boolean), and optionally the variant code if the assignment is variant-specific."}},"/bff/product-parameter/product-assign":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was assigned.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was assigned.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was assigned.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterProduct-assign","tags":["Product Parameter"],"summary":"Assign parameter value to product","description":"Assigns a parameter value to a product. Exactly one value field must be provided based on the parameter type: valueCode for enum/color, valueString for string, valueNumber for number, valueBoolean for boolean. For multi-value enum/color parameters, call this endpoint multiple times with different valueCodes. For scalar types (string, number, boolean), only one assignment per product+parameter(+variant) is allowed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","parameterCode"],"properties":{"productCode":{"description":"Product code to assign the parameter value to.","examples":["my-product"],"type":"string"},"parameterCode":{"description":"Parameter code to assign.","examples":["color"],"type":"string"},"valueCode":{"description":"Predefined value code (required for enum/color parameters).","examples":["red"],"type":"string"},"valueString":{"description":"Free-text value (for string-type parameters).","examples":["Cotton blend"],"type":"string"},"valueNumber":{"description":"Numeric value (for number-type parameters).","examples":[500],"type":"number"},"valueBoolean":{"description":"Boolean value (for boolean-type parameters).","examples":[true],"type":"boolean"},"variantCode":{"description":"Variant code for variant-level assignment. Omit for product-level assignment.","examples":["variant-xl"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","parameterCode"],"properties":{"productCode":{"description":"Product code to assign the parameter value to.","examples":["my-product"],"type":"string"},"parameterCode":{"description":"Parameter code to assign.","examples":["color"],"type":"string"},"valueCode":{"description":"Predefined value code (required for enum/color parameters).","examples":["red"],"type":"string"},"valueString":{"description":"Free-text value (for string-type parameters).","examples":["Cotton blend"],"type":"string"},"valueNumber":{"description":"Numeric value (for number-type parameters).","examples":[500],"type":"number"},"valueBoolean":{"description":"Boolean value (for boolean-type parameters).","examples":[true],"type":"boolean"},"variantCode":{"description":"Variant code for variant-level assignment. Omit for product-level assignment.","examples":["variant-xl"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","parameterCode"],"properties":{"productCode":{"description":"Product code to assign the parameter value to.","examples":["my-product"],"type":"string"},"parameterCode":{"description":"Parameter code to assign.","examples":["color"],"type":"string"},"valueCode":{"description":"Predefined value code (required for enum/color parameters).","examples":["red"],"type":"string"},"valueString":{"description":"Free-text value (for string-type parameters).","examples":["Cotton blend"],"type":"string"},"valueNumber":{"description":"Numeric value (for number-type parameters).","examples":[500],"type":"number"},"valueBoolean":{"description":"Boolean value (for boolean-type parameters).","examples":[true],"type":"boolean"},"variantCode":{"description":"Variant code for variant-level assignment. Omit for product-level assignment.","examples":["variant-xl"],"type":"string"}}}}}}}},"/bff/product-parameter/product-remove":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the assignment was removed.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the assignment was removed.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the assignment was removed.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterProduct-remove","tags":["Product Parameter"],"summary":"Remove parameter assignment from product","description":"Removes a specific parameter value assignment from a product by its assignment ID. The assignment ID is returned in the /product-values endpoint.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["assignmentId"],"properties":{"assignmentId":{"description":"Assignment ID to remove (obtained from /product-values response).","examples":[42],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["assignmentId"],"properties":{"assignmentId":{"description":"Assignment ID to remove (obtained from /product-values response).","examples":[42],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["assignmentId"],"properties":{"assignmentId":{"description":"Assignment ID to remove (obtained from /product-values response).","examples":[42],"type":"number"}}}}}}}},"/bff/product-parameter/category-parameters":{"get":{"parameters":[{"description":"Product category code to list mapped parameters for.","examples":["electronics","clothing"],"schema":{"type":"string"},"in":"query","name":"categoryCode","required":true}],"responses":{"200":{"description":"Parameters assigned to the category.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Parameters mapped to this category, ordered by position then name.","type":"array","items":{"description":"Category-parameter mapping item.","type":"object","required":["parameterCode","parameterName","parameterType","required","position"],"properties":{"parameterCode":{"description":"Parameter code.","type":"string"},"parameterName":{"description":"Parameter display name.","type":"string"},"parameterType":{"description":"Parameter data type.","type":"string"},"required":{"description":"Whether the parameter is required for products in this category.","type":"boolean"},"position":{"description":"Sort order position within this category.","type":"number"}}}},"itemCount":{"description":"Total number of mapped parameters.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Parameters mapped to this category, ordered by position then name.","type":"array","items":{"description":"Category-parameter mapping item.","type":"object","required":["parameterCode","parameterName","parameterType","required","position"],"properties":{"parameterCode":{"description":"Parameter code.","type":"string"},"parameterName":{"description":"Parameter display name.","type":"string"},"parameterType":{"description":"Parameter data type.","type":"string"},"required":{"description":"Whether the parameter is required for products in this category.","type":"boolean"},"position":{"description":"Sort order position within this category.","type":"number"}}}},"itemCount":{"description":"Total number of mapped parameters.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Parameters mapped to this category, ordered by position then name.","type":"array","items":{"description":"Category-parameter mapping item.","type":"object","required":["parameterCode","parameterName","parameterType","required","position"],"properties":{"parameterCode":{"description":"Parameter code.","type":"string"},"parameterName":{"description":"Parameter display name.","type":"string"},"parameterType":{"description":"Parameter data type.","type":"string"},"required":{"description":"Whether the parameter is required for products in this category.","type":"boolean"},"position":{"description":"Sort order position within this category.","type":"number"}}}},"itemCount":{"description":"Total number of mapped parameters.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProduct-parameterCategory-parameters","tags":["Product Parameter"],"summary":"List category parameters","description":"Returns all parameters mapped to a product category. Category-parameter mapping defines which parameters are relevant (and optionally required) for products in this category. Used by the admin UI to show the appropriate parameter form."}},"/bff/product-parameter/category-assign":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the mapping was created.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the mapping was created.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the mapping was created.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterCategory-assign","tags":["Product Parameter"],"summary":"Assign parameter to category","description":"Maps a parameter to a product category. If the mapping already exists, the request is silently ignored (idempotent). This mapping tells the admin UI which parameters to show when editing products in this category.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["categoryCode","parameterCode"],"properties":{"categoryCode":{"description":"Product category code to map the parameter to.","examples":["electronics"],"type":"string"},"parameterCode":{"description":"Parameter code to assign to the category.","examples":["weight"],"type":"string"},"required":{"description":"Whether the parameter is required for products in this category. Defaults to false.","examples":[false],"type":"boolean"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["categoryCode","parameterCode"],"properties":{"categoryCode":{"description":"Product category code to map the parameter to.","examples":["electronics"],"type":"string"},"parameterCode":{"description":"Parameter code to assign to the category.","examples":["weight"],"type":"string"},"required":{"description":"Whether the parameter is required for products in this category. Defaults to false.","examples":[false],"type":"boolean"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["categoryCode","parameterCode"],"properties":{"categoryCode":{"description":"Product category code to map the parameter to.","examples":["electronics"],"type":"string"},"parameterCode":{"description":"Parameter code to assign to the category.","examples":["weight"],"type":"string"},"required":{"description":"Whether the parameter is required for products in this category. Defaults to false.","examples":[false],"type":"boolean"},"position":{"description":"Sort order position. Defaults to 0.","examples":[0],"type":"number"}}}}}}}},"/bff/product-parameter/category-remove":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the mapping was removed.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the mapping was removed.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the mapping was removed.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProduct-parameterCategory-remove","tags":["Product Parameter"],"summary":"Remove parameter from category","description":"Removes the mapping between a parameter and a product category. Does not delete existing product assignments — only removes the category-level mapping.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["categoryCode","parameterCode"],"properties":{"categoryCode":{"description":"Product category code to remove the mapping from.","examples":["electronics"],"type":"string"},"parameterCode":{"description":"Parameter code to remove from the category.","examples":["weight"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["categoryCode","parameterCode"],"properties":{"categoryCode":{"description":"Product category code to remove the mapping from.","examples":["electronics"],"type":"string"},"parameterCode":{"description":"Parameter code to remove from the category.","examples":["weight"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["categoryCode","parameterCode"],"properties":{"categoryCode":{"description":"Product category code to remove the mapping from.","examples":["electronics"],"type":"string"},"parameterCode":{"description":"Parameter code to remove from the category.","examples":["weight"],"type":"string"}}}}}}}},"/bff/product/search-product-variant-list":{"get":{"parameters":[{"description":"Product code to list variants for.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Product variants.","type":"array","items":{"type":"object","required":["code","name","price"],"properties":{"code":{"description":"Variant code.","type":"string"},"name":{"description":"Variant display name (falls back to code).","type":"string"},"price":{"description":"Variant price with VAT.","type":"number"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Product variants.","type":"array","items":{"type":"object","required":["code","name","price"],"properties":{"code":{"description":"Variant code.","type":"string"},"name":{"description":"Variant display name (falls back to code).","type":"string"},"price":{"description":"Variant price with VAT.","type":"number"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Product variants.","type":"array","items":{"type":"object","required":["code","name","price"],"properties":{"code":{"description":"Variant code.","type":"string"},"name":{"description":"Variant display name (falls back to code).","type":"string"},"price":{"description":"Variant price with VAT.","type":"number"}}}}},"required":["items"]}}}}},"operationId":"getBffProductSearch-product-variant-list","tags":["Product"],"summary":"Search product variants (lightweight)","description":"Returns a lightweight list of all product variants (including deleted). Used for search/autocomplete in variant selectors. Ordered by position."}},"/bff/product/product-variant-list":{"get":{"parameters":[{"description":"Product code to list variants for.","examples":["my-product"],"schema":{"type":"string"},"in":"query","name":"productCode","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Product variants.","type":"array","items":{"type":"object","required":["id","code","price","priceAddition","soldOut","warehouseAllQuantity"],"properties":{"id":{"description":"Variant relation hash (unique identifier).","type":"string"},"name":{"description":"Variant display name.","type":"string"},"code":{"description":"Variant code.","type":"string"},"ean":{"description":"Variant EAN barcode.","type":"string"},"price":{"description":"Price object with priceWithVat, priceWithoutVat, vat, currency."},"priceAddition":{"description":"Additional price on top of the base product price.","type":"number"},"soldOut":{"description":"Whether the variant is sold out.","type":"boolean"},"warehouseAllQuantity":{"description":"Total warehouse stock for this variant.","type":"number"},"mainImage":{"type":"object","required":["token","filename","downloadUrl","contentType"],"properties":{"token":{"description":"Blob token (image identifier).","type":"string"},"filename":{"description":"Original filename.","type":"string"},"downloadUrl":{"description":"Public download URL.","type":"string"},"contentType":{"description":"MIME content type.","type":"string"}}}}}},"itemCount":{"description":"Total number of non-deleted variants.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Product variants.","type":"array","items":{"type":"object","required":["id","code","price","priceAddition","soldOut","warehouseAllQuantity"],"properties":{"id":{"description":"Variant relation hash (unique identifier).","type":"string"},"name":{"description":"Variant display name.","type":"string"},"code":{"description":"Variant code.","type":"string"},"ean":{"description":"Variant EAN barcode.","type":"string"},"price":{"description":"Price object with priceWithVat, priceWithoutVat, vat, currency."},"priceAddition":{"description":"Additional price on top of the base product price.","type":"number"},"soldOut":{"description":"Whether the variant is sold out.","type":"boolean"},"warehouseAllQuantity":{"description":"Total warehouse stock for this variant.","type":"number"},"mainImage":{"type":"object","required":["token","filename","downloadUrl","contentType"],"properties":{"token":{"description":"Blob token (image identifier).","type":"string"},"filename":{"description":"Original filename.","type":"string"},"downloadUrl":{"description":"Public download URL.","type":"string"},"contentType":{"description":"MIME content type.","type":"string"}}}}}},"itemCount":{"description":"Total number of non-deleted variants.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Product variants.","type":"array","items":{"type":"object","required":["id","code","price","priceAddition","soldOut","warehouseAllQuantity"],"properties":{"id":{"description":"Variant relation hash (unique identifier).","type":"string"},"name":{"description":"Variant display name.","type":"string"},"code":{"description":"Variant code.","type":"string"},"ean":{"description":"Variant EAN barcode.","type":"string"},"price":{"description":"Price object with priceWithVat, priceWithoutVat, vat, currency."},"priceAddition":{"description":"Additional price on top of the base product price.","type":"number"},"soldOut":{"description":"Whether the variant is sold out.","type":"boolean"},"warehouseAllQuantity":{"description":"Total warehouse stock for this variant.","type":"number"},"mainImage":{"type":"object","required":["token","filename","downloadUrl","contentType"],"properties":{"token":{"description":"Blob token (image identifier).","type":"string"},"filename":{"description":"Original filename.","type":"string"},"downloadUrl":{"description":"Public download URL.","type":"string"},"contentType":{"description":"MIME content type.","type":"string"}}}}}},"itemCount":{"description":"Total number of non-deleted variants.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffProductProduct-variant-list","tags":["Product"],"summary":"List product variants (paginated)","description":"Returns a paginated list of non-deleted product variants with full detail. Ordered by warehouse quantity (highest first), then by position. Supports pagination via \"page\" and \"limit\" query parameters."}},"/bff/product/update-variant":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductUpdate-variant","tags":["Product"],"summary":"Update variant property","description":"Updates a single property of a product variant. Used for inline editing in data grids. Regenerates the parent product read model after update.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","code","haystack","property"],"properties":{"id":{"description":"Variant relation hash (unique identifier).","examples":["a1b2c3d4"],"type":"string"},"code":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"haystack":{"description":"New value for the property.","examples":["XL"],"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"property":{"description":"Property to update: name, code, ean, price, priceAddition, soldOut, or warehouse.","examples":["name"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","code","haystack","property"],"properties":{"id":{"description":"Variant relation hash (unique identifier).","examples":["a1b2c3d4"],"type":"string"},"code":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"haystack":{"description":"New value for the property.","examples":["XL"],"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"property":{"description":"Property to update: name, code, ean, price, priceAddition, soldOut, or warehouse.","examples":["name"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id","code","haystack","property"],"properties":{"id":{"description":"Variant relation hash (unique identifier).","examples":["a1b2c3d4"],"type":"string"},"code":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"haystack":{"description":"New value for the property.","examples":["XL"],"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"property":{"description":"Property to update: name, code, ean, price, priceAddition, soldOut, or warehouse.","examples":["name"],"type":"string"}}}}}}}},"/bff/product/delete-product-variant":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was deleted.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was deleted.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was deleted.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductDelete-product-variant","tags":["Product"],"summary":"Delete product variant","description":"Soft-deletes a product variant (sets deleted flag). The variant will no longer appear in public feeds.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","variantCode"],"properties":{"code":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"variantCode":{"description":"Variant code to delete.","examples":["variant-xl"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","variantCode"],"properties":{"code":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"variantCode":{"description":"Variant code to delete.","examples":["variant-xl"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code","variantCode"],"properties":{"code":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"variantCode":{"description":"Variant code to delete.","examples":["variant-xl"],"type":"string"}}}}}}}},"/bff/product/product-variant-create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was created.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was created.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the variant was created.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductProduct-variant-create","tags":["Product"],"summary":"Create product variant","description":"Creates a new variant for a product. The variant code is generated from the provided code (or from product code + name) and deduplicated. Each variant gets a unique relation hash for identification.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mainProductCode","name","code"],"properties":{"mainProductCode":{"description":"Product code to add the variant to.","examples":["my-product"],"type":"string"},"name":{"minLength":1,"description":"Variant display name.","examples":["Size XL"],"type":"string"},"code":{"minLength":1,"description":"Variant code (will be slugified and deduplicated).","examples":["xl"],"type":"string"},"ean":{"description":"Variant EAN barcode.","examples":["8594000000456"],"type":"string"},"price":{"description":"Variant price with VAT.","examples":[399.9],"type":"number"},"priceAdd":{"description":"Additional price on top of the base product price.","examples":[50],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["mainProductCode","name","code"],"properties":{"mainProductCode":{"description":"Product code to add the variant to.","examples":["my-product"],"type":"string"},"name":{"minLength":1,"description":"Variant display name.","examples":["Size XL"],"type":"string"},"code":{"minLength":1,"description":"Variant code (will be slugified and deduplicated).","examples":["xl"],"type":"string"},"ean":{"description":"Variant EAN barcode.","examples":["8594000000456"],"type":"string"},"price":{"description":"Variant price with VAT.","examples":[399.9],"type":"number"},"priceAdd":{"description":"Additional price on top of the base product price.","examples":[50],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["mainProductCode","name","code"],"properties":{"mainProductCode":{"description":"Product code to add the variant to.","examples":["my-product"],"type":"string"},"name":{"minLength":1,"description":"Variant display name.","examples":["Size XL"],"type":"string"},"code":{"minLength":1,"description":"Variant code (will be slugified and deduplicated).","examples":["xl"],"type":"string"},"ean":{"description":"Variant EAN barcode.","examples":["8594000000456"],"type":"string"},"price":{"description":"Variant price with VAT.","examples":[399.9],"type":"number"},"priceAdd":{"description":"Additional price on top of the base product price.","examples":[50],"type":"number"}}}}}}}},"/bff/product/variant-set-main-image":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the main image was updated.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffProductVariant-set-main-image","tags":["Product"],"summary":"Set or remove variant main image","description":"Sets the main image for a product variant. The image must already be uploaded in the product gallery. To remove the current image, omit imageToken or pass null.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productCode","variantCode"],"properties":{"productCode":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"variantCode":{"description":"Variant code to set the image for.","examples":["variant-xl"],"type":"string"},"imageToken":{"description":"Blob token of the image to set as main. Must be an image from the product gallery. Omit or pass null to remove the current main image.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["productCode","variantCode"],"properties":{"productCode":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"variantCode":{"description":"Variant code to set the image for.","examples":["variant-xl"],"type":"string"},"imageToken":{"description":"Blob token of the image to set as main. Must be an image from the product gallery. Omit or pass null to remove the current main image.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["productCode","variantCode"],"properties":{"productCode":{"description":"Product code the variant belongs to.","examples":["my-product"],"type":"string"},"variantCode":{"description":"Variant code to set the image for.","examples":["variant-xl"],"type":"string"},"imageToken":{"description":"Blob token of the image to set as main. Must be an image from the product gallery. Omit or pass null to remove the current main image.","type":"string"}}}}}}}},"/bff/rss-feed/list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","url","active","insertedDate","postCount","newsroomShortlistCountToday"],"properties":{"id":{"description":"Feed external ID.","type":"string"},"url":{"description":"RSS feed URL.","type":"string"},"title":{"description":"Feed title parsed from the last successful fetch.","type":"string"},"description":{"description":"Feed description parsed from the last successful fetch.","type":"string"},"active":{"description":"Whether this feed is active for the organisation.","type":"boolean"},"lastFetchDate":{"description":"Timestamp of the last fetch attempt.","anyOf":[{"description":"Timestamp of the last fetch attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastFetchHttpCode":{"description":"HTTP status code from the last fetch.","type":"number"},"insertedDate":{"description":"When the feed was linked to the organisation.","anyOf":[{"description":"When the feed was linked to the organisation.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Total number of articles discovered from this feed.","type":"number"},"latestPostDate":{"description":"Published date of the most recent article.","anyOf":[{"description":"Published date of the most recent article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"oldestPostDate":{"description":"Published date of the oldest article.","anyOf":[{"description":"Published date of the oldest article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"newsroomShortlistCountToday":{"description":"Number of articles from this feed in today's Newsroom shortlist (excluding dismissed). 0 if Newsroom is unused or no items today.","type":"number"}}}},"itemCount":{"description":"Total number of feeds.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","url","active","insertedDate","postCount","newsroomShortlistCountToday"],"properties":{"id":{"description":"Feed external ID.","type":"string"},"url":{"description":"RSS feed URL.","type":"string"},"title":{"description":"Feed title parsed from the last successful fetch.","type":"string"},"description":{"description":"Feed description parsed from the last successful fetch.","type":"string"},"active":{"description":"Whether this feed is active for the organisation.","type":"boolean"},"lastFetchDate":{"description":"Timestamp of the last fetch attempt.","anyOf":[{"description":"Timestamp of the last fetch attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastFetchHttpCode":{"description":"HTTP status code from the last fetch.","type":"number"},"insertedDate":{"description":"When the feed was linked to the organisation.","anyOf":[{"description":"When the feed was linked to the organisation.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Total number of articles discovered from this feed.","type":"number"},"latestPostDate":{"description":"Published date of the most recent article.","anyOf":[{"description":"Published date of the most recent article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"oldestPostDate":{"description":"Published date of the oldest article.","anyOf":[{"description":"Published date of the oldest article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"newsroomShortlistCountToday":{"description":"Number of articles from this feed in today's Newsroom shortlist (excluding dismissed). 0 if Newsroom is unused or no items today.","type":"number"}}}},"itemCount":{"description":"Total number of feeds.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","url","active","insertedDate","postCount","newsroomShortlistCountToday"],"properties":{"id":{"description":"Feed external ID.","type":"string"},"url":{"description":"RSS feed URL.","type":"string"},"title":{"description":"Feed title parsed from the last successful fetch.","type":"string"},"description":{"description":"Feed description parsed from the last successful fetch.","type":"string"},"active":{"description":"Whether this feed is active for the organisation.","type":"boolean"},"lastFetchDate":{"description":"Timestamp of the last fetch attempt.","anyOf":[{"description":"Timestamp of the last fetch attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastFetchHttpCode":{"description":"HTTP status code from the last fetch.","type":"number"},"insertedDate":{"description":"When the feed was linked to the organisation.","anyOf":[{"description":"When the feed was linked to the organisation.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Total number of articles discovered from this feed.","type":"number"},"latestPostDate":{"description":"Published date of the most recent article.","anyOf":[{"description":"Published date of the most recent article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"oldestPostDate":{"description":"Published date of the oldest article.","anyOf":[{"description":"Published date of the oldest article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"newsroomShortlistCountToday":{"description":"Number of articles from this feed in today's Newsroom shortlist (excluding dismissed). 0 if Newsroom is unused or no items today.","type":"number"}}}},"itemCount":{"description":"Total number of feeds.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffRss-feedList","tags":["RSS Feed"],"summary":"List RSS feeds","description":"Returns all RSS feeds linked to the authenticated organisation."}},"/bff/rss-feed/detail":{"get":{"parameters":[{"description":"Feed external ID.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Feed external ID.","type":"string"},"url":{"description":"RSS feed URL.","type":"string"},"title":{"description":"Feed title.","type":"string"},"description":{"description":"Feed description.","type":"string"},"active":{"description":"Whether this feed is active for the organisation.","type":"boolean"},"lastFetchDate":{"description":"Timestamp of the last fetch attempt.","anyOf":[{"description":"Timestamp of the last fetch attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastFetchHttpCode":{"description":"HTTP status code from the last fetch.","type":"number"},"lastFetchHash":{"description":"MD5 hash of the last fetched content.","type":"string"},"insertedDate":{"description":"When the feed was created.","anyOf":[{"description":"When the feed was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"When the feed was last updated.","anyOf":[{"description":"When the feed was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Total number of articles discovered.","type":"number"},"latestPostDate":{"description":"Published date of the most recent article.","anyOf":[{"description":"Published date of the most recent article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"oldestPostDate":{"description":"Published date of the oldest article.","anyOf":[{"description":"Published date of the oldest article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","url","active","insertedDate","updatedDate","postCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Feed external ID.","type":"string"},"url":{"description":"RSS feed URL.","type":"string"},"title":{"description":"Feed title.","type":"string"},"description":{"description":"Feed description.","type":"string"},"active":{"description":"Whether this feed is active for the organisation.","type":"boolean"},"lastFetchDate":{"description":"Timestamp of the last fetch attempt.","anyOf":[{"description":"Timestamp of the last fetch attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastFetchHttpCode":{"description":"HTTP status code from the last fetch.","type":"number"},"lastFetchHash":{"description":"MD5 hash of the last fetched content.","type":"string"},"insertedDate":{"description":"When the feed was created.","anyOf":[{"description":"When the feed was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"When the feed was last updated.","anyOf":[{"description":"When the feed was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Total number of articles discovered.","type":"number"},"latestPostDate":{"description":"Published date of the most recent article.","anyOf":[{"description":"Published date of the most recent article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"oldestPostDate":{"description":"Published date of the oldest article.","anyOf":[{"description":"Published date of the oldest article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","url","active","insertedDate","updatedDate","postCount"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Feed external ID.","type":"string"},"url":{"description":"RSS feed URL.","type":"string"},"title":{"description":"Feed title.","type":"string"},"description":{"description":"Feed description.","type":"string"},"active":{"description":"Whether this feed is active for the organisation.","type":"boolean"},"lastFetchDate":{"description":"Timestamp of the last fetch attempt.","anyOf":[{"description":"Timestamp of the last fetch attempt.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"lastFetchHttpCode":{"description":"HTTP status code from the last fetch.","type":"number"},"lastFetchHash":{"description":"MD5 hash of the last fetched content.","type":"string"},"insertedDate":{"description":"When the feed was created.","anyOf":[{"description":"When the feed was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"When the feed was last updated.","anyOf":[{"description":"When the feed was last updated.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"postCount":{"description":"Total number of articles discovered.","type":"number"},"latestPostDate":{"description":"Published date of the most recent article.","anyOf":[{"description":"Published date of the most recent article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"oldestPostDate":{"description":"Published date of the oldest article.","anyOf":[{"description":"Published date of the oldest article.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","url","active","insertedDate","updatedDate","postCount"]}}}}},"operationId":"getBffRss-feedDetail","tags":["RSS Feed"],"summary":"Get RSS feed detail","description":"Returns full detail of a single RSS feed including post statistics."}},"/bff/rss-feed/post-list":{"get":{"parameters":[{"description":"Feed external ID to list posts for.","examples":["a1b2c3d4"],"schema":{"type":"string"},"in":"query","name":"feedId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","guid","discoveredDate"],"properties":{"id":{"description":"Post external ID.","type":"string"},"guid":{"description":"Unique identifier from the RSS feed (guid or link).","type":"string"},"url":{"description":"Article URL.","type":"string"},"title":{"description":"Article title.","type":"string"},"description":{"description":"Article summary/excerpt.","type":"string"},"author":{"description":"Article author.","type":"string"},"publishedDate":{"description":"Published date from the feed.","anyOf":[{"description":"Published date from the feed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"discoveredDate":{"description":"When the article was first discovered by the system.","anyOf":[{"description":"When the article was first discovered by the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of posts for this feed.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","guid","discoveredDate"],"properties":{"id":{"description":"Post external ID.","type":"string"},"guid":{"description":"Unique identifier from the RSS feed (guid or link).","type":"string"},"url":{"description":"Article URL.","type":"string"},"title":{"description":"Article title.","type":"string"},"description":{"description":"Article summary/excerpt.","type":"string"},"author":{"description":"Article author.","type":"string"},"publishedDate":{"description":"Published date from the feed.","anyOf":[{"description":"Published date from the feed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"discoveredDate":{"description":"When the article was first discovered by the system.","anyOf":[{"description":"When the article was first discovered by the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of posts for this feed.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","guid","discoveredDate"],"properties":{"id":{"description":"Post external ID.","type":"string"},"guid":{"description":"Unique identifier from the RSS feed (guid or link).","type":"string"},"url":{"description":"Article URL.","type":"string"},"title":{"description":"Article title.","type":"string"},"description":{"description":"Article summary/excerpt.","type":"string"},"author":{"description":"Article author.","type":"string"},"publishedDate":{"description":"Published date from the feed.","anyOf":[{"description":"Published date from the feed.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"discoveredDate":{"description":"When the article was first discovered by the system.","anyOf":[{"description":"When the article was first discovered by the system.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of posts for this feed.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffRss-feedPost-list","tags":["RSS Feed"],"summary":"List RSS feed posts","description":"Returns a paginated list of articles discovered from a specific RSS feed. Ordered by published date (newest first). Supports ?page= and ?limit= query params."}},"/bff/rss-feed/add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"feedId":{"description":"External ID of the feed (existing or newly created).","type":"string"},"created":{"description":"True if a new feed record was created, false if it already existed.","type":"boolean"}},"required":["success","feedId","created"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"feedId":{"description":"External ID of the feed (existing or newly created).","type":"string"},"created":{"description":"True if a new feed record was created, false if it already existed.","type":"boolean"}},"required":["success","feedId","created"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"feedId":{"description":"External ID of the feed (existing or newly created).","type":"string"},"created":{"description":"True if a new feed record was created, false if it already existed.","type":"boolean"}},"required":["success","feedId","created"]}}}}},"operationId":"postBffRss-feedAdd","tags":["RSS Feed"],"summary":"Add RSS feed","description":"Adds an RSS feed URL. If the URL already exists in the shared feed table, only a relation to the organisation is created. Otherwise a new feed record is inserted first.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"description":"RSS feed URL to add.","examples":["https://example.com/rss.xml"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["url"],"properties":{"url":{"description":"RSS feed URL to add.","examples":["https://example.com/rss.xml"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["url"],"properties":{"url":{"description":"RSS feed URL to add.","examples":["https://example.com/rss.xml"],"type":"string"}}}}}}}},"/bff/rss-feed/set-active":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"feedId":{"description":"Feed external ID.","type":"string"},"active":{"description":"New active state.","type":"boolean"}},"required":["success","feedId","active"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"feedId":{"description":"Feed external ID.","type":"string"},"active":{"description":"New active state.","type":"boolean"}},"required":["success","feedId","active"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"feedId":{"description":"Feed external ID.","type":"string"},"active":{"description":"New active state.","type":"boolean"}},"required":["success","feedId","active"]}}}}},"operationId":"postBffRss-feedSet-active","tags":["RSS Feed"],"summary":"Set RSS feed active flag","description":"Toggles the active flag on the link between the organisation and the feed. Inactive feeds are excluded from sync, AI enrichment, the Newsroom shortlist, and any AI-driven overview or article-writing logic. The flag is per-organisation and does not affect the global feed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["feedId","active"],"properties":{"feedId":{"description":"Feed external ID.","examples":["a1b2c3d4"],"type":"string"},"active":{"description":"Whether the feed should be active for this organisation.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["feedId","active"],"properties":{"feedId":{"description":"Feed external ID.","examples":["a1b2c3d4"],"type":"string"},"active":{"description":"Whether the feed should be active for this organisation.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["feedId","active"],"properties":{"feedId":{"description":"Feed external ID.","examples":["a1b2c3d4"],"type":"string"},"active":{"description":"Whether the feed should be active for this organisation.","type":"boolean"}}}}}}}},"/bff/rss-feed/sync":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","required":["feedId","updated"],"properties":{"feedId":{"description":"Feed external ID.","type":"string"},"updated":{"description":"Whether the feed content changed since the last fetch.","type":"boolean"},"error":{"description":"Error message if the sync failed for this feed.","type":"string"}}}}},"required":["success","results"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","required":["feedId","updated"],"properties":{"feedId":{"description":"Feed external ID.","type":"string"},"updated":{"description":"Whether the feed content changed since the last fetch.","type":"boolean"},"error":{"description":"Error message if the sync failed for this feed.","type":"string"}}}}},"required":["success","results"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","required":["feedId","updated"],"properties":{"feedId":{"description":"Feed external ID.","type":"string"},"updated":{"description":"Whether the feed content changed since the last fetch.","type":"boolean"},"error":{"description":"Error message if the sync failed for this feed.","type":"string"}}}}},"required":["success","results"]}}}}},"operationId":"postBffRss-feedSync","tags":["RSS Feed"],"summary":"Sync RSS feeds","description":"Fetches the latest content from RSS feed URLs. If feedId is provided, only that feed is synced. Otherwise all active feeds for the organisation are synced. Content is cached locally and compared by hash to avoid unnecessary updates.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"feedId":{"description":"Feed external ID to sync. If omitted, all active feeds for the organisation are synced.","examples":["a1b2c3d4"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"feedId":{"description":"Feed external ID to sync. If omitted, all active feeds for the organisation are synced.","examples":["a1b2c3d4"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"feedId":{"description":"Feed external ID to sync. If omitted, all active feeds for the organisation are synced.","examples":["a1b2c3d4"],"type":"string"}}}}}}}},"/bff/rss-feed/{feedId}/newsroom-shortlist":{"get":{"parameters":[{"description":"Feed external ID.","schema":{"type":"string"},"in":"path","name":"feedId","required":true},{"description":"Maximum number of items (default 10).","schema":{"type":"string"},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","shortlistDate","rank","title","hotnessScore","czRelevanceScore","cctvFitScore","totalScore","status","insertedDate"],"properties":{"id":{"type":"string"},"shortlistDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"rank":{"type":"number"},"title":{"type":"string"},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"},"hotnessScore":{"type":"number"},"czRelevanceScore":{"type":"number"},"cctvFitScore":{"type":"number"},"totalScore":{"type":"number"},"reason":{"type":"string"},"status":{"type":"string"},"draftId":{"type":"string"},"draftStatus":{"type":"string"},"topicType":{"type":"string"},"severity":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","shortlistDate","rank","title","hotnessScore","czRelevanceScore","cctvFitScore","totalScore","status","insertedDate"],"properties":{"id":{"type":"string"},"shortlistDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"rank":{"type":"number"},"title":{"type":"string"},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"},"hotnessScore":{"type":"number"},"czRelevanceScore":{"type":"number"},"cctvFitScore":{"type":"number"},"totalScore":{"type":"number"},"reason":{"type":"string"},"status":{"type":"string"},"draftId":{"type":"string"},"draftStatus":{"type":"string"},"topicType":{"type":"string"},"severity":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","shortlistDate","rank","title","hotnessScore","czRelevanceScore","cctvFitScore","totalScore","status","insertedDate"],"properties":{"id":{"type":"string"},"shortlistDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"rank":{"type":"number"},"title":{"type":"string"},"source":{"type":"string"},"sourceUrl":{"type":"string"},"feedId":{"description":"External ID of the source RSS feed.","type":"string"},"hotnessScore":{"type":"number"},"czRelevanceScore":{"type":"number"},"cctvFitScore":{"type":"number"},"totalScore":{"type":"number"},"reason":{"type":"string"},"status":{"type":"string"},"draftId":{"type":"string"},"draftStatus":{"type":"string"},"topicType":{"type":"string"},"severity":{"type":"string"},"insertedDate":{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffRss-feedByFeedIdNewsroom-shortlist","tags":["RSS Feed","Newsroom"],"summary":"List Newsroom shortlist items for a feed","description":"Returns Newsroom shortlist items whose source RSS post belongs to the given feed, across all dates. Same item shape as GET /bff/newsroom/shortlist. Ordered by shortlist date DESC, then rank ASC."}},"/bff/routing/list":{"get":{"parameters":[{"description":"Filter by route type code (e.g. \"article\", \"product-detail\").","examples":["article"],"schema":{"type":"string"},"in":"query","name":"typeCode","required":false},{"description":"Filter by related entity ID. Accepts internal numeric ID or external ID (e.g. \"P93gIby6q5t2gi2a\"). When using external ID, typeCode must also be provided for correct resolution.","examples":["42"],"schema":{"type":"string"},"in":"query","name":"relatedEntityId","required":false},{"description":"Filter by slug (partial match, case-insensitive).","examples":["my-article"],"schema":{"type":"string"},"in":"query","name":"slug","required":false},{"description":"Filter by canonical status (\"true\" or \"false\").","examples":["true"],"schema":{"type":"string"},"in":"query","name":"canonical","required":false},{"description":"Filter by locale code (e.g. \"cs\", \"en\").","examples":["cs"],"schema":{"type":"string"},"in":"query","name":"locale","required":false},{"description":"Page number (1-based). Default: 1.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Items per page (max 200). Default: 50.","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"responses":{"200":{"description":"Paginated list of routes.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of route entries matching the filter criteria.","type":"array","items":{"description":"Single route entry.","type":"object","required":["id","typeCode","slug","canonical","relatedEntityId","locale","insertedDate"],"properties":{"id":{"description":"Unique route identifier.","type":"string"},"typeCode":{"description":"Entity type code (e.g. \"article\", \"product-detail\").","type":"string"},"slug":{"description":"URL slug for this route.","type":"string"},"canonical":{"description":"Whether this is the canonical route for the entity.","type":"boolean"},"relatedEntityId":{"description":"ID of the related entity (post, product, etc.).","type":"number"},"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"},"insertedDate":{"description":"Date when the route was created.","anyOf":[{"description":"Date when the route was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of matching routes (before pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of route entries matching the filter criteria.","type":"array","items":{"description":"Single route entry.","type":"object","required":["id","typeCode","slug","canonical","relatedEntityId","locale","insertedDate"],"properties":{"id":{"description":"Unique route identifier.","type":"string"},"typeCode":{"description":"Entity type code (e.g. \"article\", \"product-detail\").","type":"string"},"slug":{"description":"URL slug for this route.","type":"string"},"canonical":{"description":"Whether this is the canonical route for the entity.","type":"boolean"},"relatedEntityId":{"description":"ID of the related entity (post, product, etc.).","type":"number"},"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"},"insertedDate":{"description":"Date when the route was created.","anyOf":[{"description":"Date when the route was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of matching routes (before pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of route entries matching the filter criteria.","type":"array","items":{"description":"Single route entry.","type":"object","required":["id","typeCode","slug","canonical","relatedEntityId","locale","insertedDate"],"properties":{"id":{"description":"Unique route identifier.","type":"string"},"typeCode":{"description":"Entity type code (e.g. \"article\", \"product-detail\").","type":"string"},"slug":{"description":"URL slug for this route.","type":"string"},"canonical":{"description":"Whether this is the canonical route for the entity.","type":"boolean"},"relatedEntityId":{"description":"ID of the related entity (post, product, etc.).","type":"number"},"locale":{"description":"Locale code (e.g. \"cs\", \"en\").","type":"string"},"insertedDate":{"description":"Date when the route was created.","anyOf":[{"description":"Date when the route was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of matching routes (before pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffRoutingList","tags":["Routing"],"summary":"List routes","description":"Returns a paginated routing table for the authenticated organisation. Supports filtering by entity type, entity ID, slug, canonical status, and locale. Routes are ordered by insertion date (newest first)."}},"/bff/routing/type-list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code"],"properties":{"id":{"description":"Route type ID.","type":"number"},"code":{"description":"Route type code.","type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code"],"properties":{"id":{"description":"Route type ID.","type":"number"},"code":{"description":"Route type code.","type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code"],"properties":{"id":{"description":"Route type ID.","type":"number"},"code":{"description":"Route type code.","type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffRoutingType-list","tags":["Routing"],"summary":"List route types","description":"Returns all available route types (e.g. \"article\", \"product-detail\", \"post-category\", \"tag\"). Use these codes when creating or filtering routes."}},"/bff/routing/add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"id":{"description":"ID of the created route.","type":"string"},"slug":{"description":"Final slug (may differ from input if sanitized or deduplicated).","type":"string"}},"required":["success","id","slug"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"id":{"description":"ID of the created route.","type":"string"},"slug":{"description":"Final slug (may differ from input if sanitized or deduplicated).","type":"string"}},"required":["success","id","slug"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"},"id":{"description":"ID of the created route.","type":"string"},"slug":{"description":"Final slug (may differ from input if sanitized or deduplicated).","type":"string"}},"required":["success","id","slug"]}}}}},"operationId":"postBffRoutingAdd","tags":["Routing"],"summary":"Create route","description":"Creates a new route (URL slug) pointing to an entity. The slug is automatically sanitized and made unique by appending a numeric suffix if needed. New routes are marked as canonical by default.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","locale","slug","relatedEntityId"],"properties":{"type":{"description":"Route entity type code.","anyOf":[{"const":"product-detail","type":"string"},{"const":"article","type":"string"},{"const":"post-category","type":"string"},{"const":"tag","type":"string"}]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"slug":{"description":"Desired URL slug. Will be automatically sanitized and deduplicated (e.g. \"My Article!\" becomes \"my-article\", or \"my-article-2\" if already taken).","examples":["my-article"],"type":"string"},"relatedEntityId":{"description":"ID of the entity this route points to. Accepts internal numeric ID or external ID (e.g. \"SohsLD38Hw8vs4MC\"); external IDs are resolved against the entity table for the given type.","examples":["42"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["type","locale","slug","relatedEntityId"],"properties":{"type":{"description":"Route entity type code.","anyOf":[{"const":"product-detail","type":"string"},{"const":"article","type":"string"},{"const":"post-category","type":"string"},{"const":"tag","type":"string"}]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"slug":{"description":"Desired URL slug. Will be automatically sanitized and deduplicated (e.g. \"My Article!\" becomes \"my-article\", or \"my-article-2\" if already taken).","examples":["my-article"],"type":"string"},"relatedEntityId":{"description":"ID of the entity this route points to. Accepts internal numeric ID or external ID (e.g. \"SohsLD38Hw8vs4MC\"); external IDs are resolved against the entity table for the given type.","examples":["42"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["type","locale","slug","relatedEntityId"],"properties":{"type":{"description":"Route entity type code.","anyOf":[{"const":"product-detail","type":"string"},{"const":"article","type":"string"},{"const":"post-category","type":"string"},{"const":"tag","type":"string"}]},"locale":{"examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"minLength":2,"maxLength":2,"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","type":"string"},"slug":{"description":"Desired URL slug. Will be automatically sanitized and deduplicated (e.g. \"My Article!\" becomes \"my-article\", or \"my-article-2\" if already taken).","examples":["my-article"],"type":"string"},"relatedEntityId":{"description":"ID of the entity this route points to. Accepts internal numeric ID or external ID (e.g. \"SohsLD38Hw8vs4MC\"); external IDs are resolved against the entity table for the given type.","examples":["42"],"type":"string"}}}}}}}},"/bff/routing/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffRoutingUpdate","tags":["Routing"],"summary":"Update route","description":"Updates route properties (slug, canonical status). Only provided fields are updated, others remain unchanged. For canonical switching (unmark old + mark new), prefer the /set-canonical endpoint.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to update.","examples":["123"],"type":"string"},"slug":{"description":"New slug value. Must be unique within the organisation.","examples":["new-slug"],"type":"string"},"canonical":{"description":"Set canonical status. Use /set-canonical endpoint for safe canonical switching.","type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to update.","examples":["123"],"type":"string"},"slug":{"description":"New slug value. Must be unique within the organisation.","examples":["new-slug"],"type":"string"},"canonical":{"description":"Set canonical status. Use /set-canonical endpoint for safe canonical switching.","type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to update.","examples":["123"],"type":"string"},"slug":{"description":"New slug value. Must be unique within the organisation.","examples":["new-slug"],"type":"string"},"canonical":{"description":"Set canonical status. Use /set-canonical endpoint for safe canonical switching.","type":"boolean"}}}}}}}},"/bff/routing/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffRoutingDelete","tags":["Routing"],"summary":"Delete route","description":"Permanently deletes a route. The entity remains, only the URL mapping is removed. If the deleted route was canonical, make sure to set another route as canonical.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to delete.","examples":["123"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to delete.","examples":["123"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to delete.","examples":["123"],"type":"string"}}}}}}}},"/bff/routing/set-canonical":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"const":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffRoutingSet-canonical","tags":["Routing"],"summary":"Set canonical route","description":"Marks a route as the canonical URL for its entity and locale. All other routes for the same entity, type, and locale are automatically unmarked. Canonical routes are used for link generation and SEO (rel=canonical).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to mark as canonical.","examples":["123"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to mark as canonical.","examples":["123"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"description":"Route ID to mark as canonical.","examples":["123"],"type":"string"}}}}}}}},"/bff/search/":{"get":{"parameters":[{"description":"Search query string.","examples":["invoice"],"schema":{"type":"string"},"in":"query","name":"query","required":false},{"description":"Communication locale code used to filter content.\n\nSupported locales: `cs`, `en`, `fr`, `it`, `pl`, `de`, `sk`, `sv`, `es`, `zh`, `ja`, `uk`, `da`.","examples":["cs","en","fr","it","pl","de","sk","sv","es","zh","ja","uk","da"],"schema":{"type":"string","minLength":2,"maxLength":2},"in":"query","name":"locale","required":false},{"description":"Limit search to a specific result type (e.g. order, product, contact).","examples":["order"],"schema":{"type":"string"},"in":"query","name":"category","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"description":"Normalized search query.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["type","label","score"],"properties":{"type":{"description":"Result entity type (order, product, contact, post, etc.).","examples":["order"],"type":"string"},"label":{"description":"Display label of the result.","type":"string"},"description":{"description":"Additional context or subtitle.","type":"string"},"url":{"description":"Link to the result detail page.","type":"string"},"score":{"description":"Relevance score (higher = better match).","type":"number"}}}}},"required":["query","items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"query":{"description":"Normalized search query.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["type","label","score"],"properties":{"type":{"description":"Result entity type (order, product, contact, post, etc.).","examples":["order"],"type":"string"},"label":{"description":"Display label of the result.","type":"string"},"description":{"description":"Additional context or subtitle.","type":"string"},"url":{"description":"Link to the result detail page.","type":"string"},"score":{"description":"Relevance score (higher = better match).","type":"number"}}}}},"required":["query","items"]}},"text/plain":{"schema":{"type":"object","properties":{"query":{"description":"Normalized search query.","type":"string"},"items":{"type":"array","items":{"type":"object","required":["type","label","score"],"properties":{"type":{"description":"Result entity type (order, product, contact, post, etc.).","examples":["order"],"type":"string"},"label":{"description":"Display label of the result.","type":"string"},"description":{"description":"Additional context or subtitle.","type":"string"},"url":{"description":"Link to the result detail page.","type":"string"},"score":{"description":"Relevance score (higher = better match).","type":"number"}}}}},"required":["query","items"]}}}}},"operationId":"getBffSearch","tags":["Search"],"summary":"Global search","description":"Performs a full-text search across all entity types (orders, products, contacts, posts, etc.). Logs search queries for analytics."}},"/bff/search/user":{"get":{"parameters":[{"description":"Contact email address.\n\nThe system validates the input as a standard email address and automatically applies **normalization and canonicalization**.\n\nAll API responses return the **normalized form**, and each email address is **unique per organisation** within the system.\n\n**Phone-only contacts:** Since 2026-06-10 a contact may exist without an e-mail when it was registered only by phone (e.g. imports of phone-only records). Responses that expose such contacts use `API_EMAIL_NULLABLE` instead, where this field can be `null`. Endpoints that accept e-mail as input still require a valid value here — phone-only creation goes through admin-only import / BFF flows.","examples":["jan@barasek.com"],"schema":{"type":"string"},"in":"query","name":"email","required":true}],"operationId":"getBffSearchUser","tags":["Search"],"summary":"Find user by email","description":"Looks up a user profile by exact email match. Used for user autocomplete and validation.","responses":{"200":{}}}},"/bff/settings/env-variables":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Configuration variables ordered by key.","type":"array","items":{"type":"object","required":["key","valuePreview","valueLength","expired"],"properties":{"key":{"description":"Configuration key identifier.","type":"string"},"valuePreview":{"description":"Masked value preview (e.g. \"****abcd\").","type":"string"},"valueLength":{"description":"Length of the actual (unmasked) value.","type":"number"},"expirationDate":{"description":"ISO date when the value expires, if set.","type":"string"},"expired":{"description":"Whether the value has expired.","type":"boolean"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Configuration variables ordered by key.","type":"array","items":{"type":"object","required":["key","valuePreview","valueLength","expired"],"properties":{"key":{"description":"Configuration key identifier.","type":"string"},"valuePreview":{"description":"Masked value preview (e.g. \"****abcd\").","type":"string"},"valueLength":{"description":"Length of the actual (unmasked) value.","type":"number"},"expirationDate":{"description":"ISO date when the value expires, if set.","type":"string"},"expired":{"description":"Whether the value has expired.","type":"boolean"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Configuration variables ordered by key.","type":"array","items":{"type":"object","required":["key","valuePreview","valueLength","expired"],"properties":{"key":{"description":"Configuration key identifier.","type":"string"},"valuePreview":{"description":"Masked value preview (e.g. \"****abcd\").","type":"string"},"valueLength":{"description":"Length of the actual (unmasked) value.","type":"number"},"expirationDate":{"description":"ISO date when the value expires, if set.","type":"string"},"expired":{"description":"Whether the value has expired.","type":"boolean"}}}}},"required":["items"]}}}}},"operationId":"getBffSettingsEnv-variables","tags":["Settings"],"description":"Returns all configuration variables for the organisation. Values are masked for security — only the last 4 characters are visible (high-secret keys are fully masked). This is the advanced key-value store for secrets and integration keys. For common settings, use GET /organisation/profile instead.","summary":"List environment variables"}},"/bff/settings/env-variable-value":{"get":{"parameters":[{"description":"Configuration key to retrieve the value for.","examples":["GOOGLE_ANALYTICS_ID"],"schema":{"type":"string"},"in":"query","name":"key","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"Full value of the configuration variable. Empty string if not found.","type":"string"}},"required":["value"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"value":{"description":"Full value of the configuration variable. Empty string if not found.","type":"string"}},"required":["value"]}},"text/plain":{"schema":{"type":"object","properties":{"value":{"description":"Full value of the configuration variable. Empty string if not found.","type":"string"}},"required":["value"]}}}}},"operationId":"getBffSettingsEnv-variable-value","tags":["Settings"],"description":"Returns the full (unmasked) value of a configuration variable. Use with caution — exposes secrets.","summary":"Get environment variable value"}},"/bff/settings/env-change-variable-value":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was changed successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was changed successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the value was changed successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffSettingsEnv-change-variable-value","tags":["Settings"],"description":"Updates a configuration variable value. Includes an optimistic concurrency check — oldValue must match the current value or the request is rejected. A history entry is created for audit purposes.","summary":"Change environment variable","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key","oldValue","newValue"],"properties":{"key":{"description":"Configuration key to update.","examples":["GOOGLE_ANALYTICS_ID"],"type":"string"},"oldValue":{"description":"Expected current value (optimistic concurrency check). Must match the actual value.","type":"string"},"newValue":{"description":"New value to set.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["key","oldValue","newValue"],"properties":{"key":{"description":"Configuration key to update.","examples":["GOOGLE_ANALYTICS_ID"],"type":"string"},"oldValue":{"description":"Expected current value (optimistic concurrency check). Must match the actual value.","type":"string"},"newValue":{"description":"New value to set.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["key","oldValue","newValue"],"properties":{"key":{"description":"Configuration key to update.","examples":["GOOGLE_ANALYTICS_ID"],"type":"string"},"oldValue":{"description":"Expected current value (optimistic concurrency check). Must match the actual value.","type":"string"},"newValue":{"description":"New value to set.","type":"string"}}}}}}}},"/bff/settings/ip-ban-list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["geoId","ip","hostname","city","country","countryRegion","latitude","longitude","isp","organisation","tor","hosting","proxy","reason","insertedDate"],"properties":{"geoId":{"description":"Geo IP record ID.","type":"number"},"ip":{"description":"IP address.","examples":["1.2.3.4"],"type":"string"},"hostname":{"nullable":true,"anyOf":[{"description":"Reverse DNS hostname.","type":"string"},{"type":"null"}]},"city":{"nullable":true,"anyOf":[{"description":"City name.","type":"string"},{"type":"null"}]},"country":{"nullable":true,"anyOf":[{"description":"Country code.","examples":["CZ"],"type":"string"},{"type":"null"}]},"countryRegion":{"nullable":true,"anyOf":[{"description":"Country region.","type":"string"},{"type":"null"}]},"latitude":{"nullable":true,"anyOf":[{"description":"Latitude.","type":"number"},{"type":"null"}]},"longitude":{"nullable":true,"anyOf":[{"description":"Longitude.","type":"number"},{"type":"null"}]},"isp":{"nullable":true,"anyOf":[{"description":"Internet service provider.","type":"string"},{"type":"null"}]},"organisation":{"nullable":true,"anyOf":[{"description":"IP organisation.","type":"string"},{"type":"null"}]},"tor":{"description":"Whether the IP is a known Tor exit node.","type":"boolean"},"hosting":{"description":"Whether the IP belongs to a hosting provider.","type":"boolean"},"proxy":{"description":"Whether the IP is a known proxy.","type":"boolean"},"reason":{"nullable":true,"anyOf":[{"description":"Reason for the ban.","type":"string"},{"type":"null"}]},"insertedDate":{"description":"ISO date when the ban was created.","anyOf":[{"description":"ISO date when the ban was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of banned IPs.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["geoId","ip","hostname","city","country","countryRegion","latitude","longitude","isp","organisation","tor","hosting","proxy","reason","insertedDate"],"properties":{"geoId":{"description":"Geo IP record ID.","type":"number"},"ip":{"description":"IP address.","examples":["1.2.3.4"],"type":"string"},"hostname":{"nullable":true,"anyOf":[{"description":"Reverse DNS hostname.","type":"string"},{"type":"null"}]},"city":{"nullable":true,"anyOf":[{"description":"City name.","type":"string"},{"type":"null"}]},"country":{"nullable":true,"anyOf":[{"description":"Country code.","examples":["CZ"],"type":"string"},{"type":"null"}]},"countryRegion":{"nullable":true,"anyOf":[{"description":"Country region.","type":"string"},{"type":"null"}]},"latitude":{"nullable":true,"anyOf":[{"description":"Latitude.","type":"number"},{"type":"null"}]},"longitude":{"nullable":true,"anyOf":[{"description":"Longitude.","type":"number"},{"type":"null"}]},"isp":{"nullable":true,"anyOf":[{"description":"Internet service provider.","type":"string"},{"type":"null"}]},"organisation":{"nullable":true,"anyOf":[{"description":"IP organisation.","type":"string"},{"type":"null"}]},"tor":{"description":"Whether the IP is a known Tor exit node.","type":"boolean"},"hosting":{"description":"Whether the IP belongs to a hosting provider.","type":"boolean"},"proxy":{"description":"Whether the IP is a known proxy.","type":"boolean"},"reason":{"nullable":true,"anyOf":[{"description":"Reason for the ban.","type":"string"},{"type":"null"}]},"insertedDate":{"description":"ISO date when the ban was created.","anyOf":[{"description":"ISO date when the ban was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of banned IPs.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["geoId","ip","hostname","city","country","countryRegion","latitude","longitude","isp","organisation","tor","hosting","proxy","reason","insertedDate"],"properties":{"geoId":{"description":"Geo IP record ID.","type":"number"},"ip":{"description":"IP address.","examples":["1.2.3.4"],"type":"string"},"hostname":{"nullable":true,"anyOf":[{"description":"Reverse DNS hostname.","type":"string"},{"type":"null"}]},"city":{"nullable":true,"anyOf":[{"description":"City name.","type":"string"},{"type":"null"}]},"country":{"nullable":true,"anyOf":[{"description":"Country code.","examples":["CZ"],"type":"string"},{"type":"null"}]},"countryRegion":{"nullable":true,"anyOf":[{"description":"Country region.","type":"string"},{"type":"null"}]},"latitude":{"nullable":true,"anyOf":[{"description":"Latitude.","type":"number"},{"type":"null"}]},"longitude":{"nullable":true,"anyOf":[{"description":"Longitude.","type":"number"},{"type":"null"}]},"isp":{"nullable":true,"anyOf":[{"description":"Internet service provider.","type":"string"},{"type":"null"}]},"organisation":{"nullable":true,"anyOf":[{"description":"IP organisation.","type":"string"},{"type":"null"}]},"tor":{"description":"Whether the IP is a known Tor exit node.","type":"boolean"},"hosting":{"description":"Whether the IP belongs to a hosting provider.","type":"boolean"},"proxy":{"description":"Whether the IP is a known proxy.","type":"boolean"},"reason":{"nullable":true,"anyOf":[{"description":"Reason for the ban.","type":"string"},{"type":"null"}]},"insertedDate":{"description":"ISO date when the ban was created.","anyOf":[{"description":"ISO date when the ban was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of banned IPs.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffSettingsIp-ban-list","tags":["Settings"],"description":"Returns all IP addresses banned for this organisation.","summary":"List banned IP addresses"}},"/bff/settings/ip-ban-add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the IP was banned successfully.","type":"boolean"},"geoId":{"description":"Geo IP record ID of the banned IP.","type":"number"}},"required":["success","geoId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the IP was banned successfully.","type":"boolean"},"geoId":{"description":"Geo IP record ID of the banned IP.","type":"number"}},"required":["success","geoId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the IP was banned successfully.","type":"boolean"},"geoId":{"description":"Geo IP record ID of the banned IP.","type":"number"}},"required":["success","geoId"]}}}}},"operationId":"postBffSettingsIp-ban-add","tags":["Settings"],"description":"Add an IP address to the organisation ban list. The IP is resolved to a geo record automatically.","summary":"Ban an IP address","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ip"],"properties":{"ip":{"description":"IP address to ban.","examples":["1.2.3.4"],"type":"string"},"reason":{"description":"Reason for the ban.","examples":["Fraudulent orders"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["ip"],"properties":{"ip":{"description":"IP address to ban.","examples":["1.2.3.4"],"type":"string"},"reason":{"description":"Reason for the ban.","examples":["Fraudulent orders"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["ip"],"properties":{"ip":{"description":"IP address to ban.","examples":["1.2.3.4"],"type":"string"},"reason":{"description":"Reason for the ban.","examples":["Fraudulent orders"],"type":"string"}}}}}}}},"/bff/settings/ip-ban-remove":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the ban was removed successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the ban was removed successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the ban was removed successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffSettingsIp-ban-remove","tags":["Settings"],"description":"Remove an IP address from the organisation ban list.","summary":"Remove IP ban","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["geoId"],"properties":{"geoId":{"description":"Geo IP record ID to unban.","examples":[42],"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["geoId"],"properties":{"geoId":{"description":"Geo IP record ID to unban.","examples":[42],"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["geoId"],"properties":{"geoId":{"description":"Geo IP record ID to unban.","examples":[42],"type":"number"}}}}}}}},"/bff/tariff/list":{"get":{"responses":{"200":{"items":{"type":"object","required":["id","code","position","monthlyPriceCzk","priceFrom","commission","limits","product"],"properties":{"id":{"description":"Tariff ID.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"position":{"description":"Display order on the pricing page.","type":"number"},"monthlyPriceCzk":{"description":"Monthly catalogue price in WHOLE CZK without VAT. 0 = free.","type":"number"},"priceFrom":{"description":"True when monthlyPriceCzk is \"od\" — actual price is negotiated per organisation (Enterprise).","type":"boolean"},"commission":{"type":"object","required":["flatCzk","percent"],"properties":{"flatCzk":{"description":"Flat salesperson commission per sale, in CZK. Mutually exclusive with percent.","type":"number"},"percent":{"description":"Percentage commission of the actual paid price (0-100). Used by Enterprise.","type":"number"}}},"limits":{"type":"object","required":["storageMb","members","products","ordersMonthly","customers","emailsMonthly","aiTokensMonthly","apiRequestsMonthly","forms"],"properties":{"storageMb":{"description":"Total storage occupied across the organisation, in MB. 0 = unlimited.","type":"number"},"members":{"description":"Total members in the organisation. 0 = unlimited.","type":"number"},"products":{"description":"Total products in the organisation. 0 = unlimited.","type":"number"},"ordersMonthly":{"description":"New orders created in the organisation per month. 0 = unlimited.","type":"number"},"customers":{"description":"Total customers in the organisation. 0 = unlimited.","type":"number"},"emailsMonthly":{"description":"Transactional emails sent or received in the organisation per month. 0 = unlimited.","type":"number"},"aiTokensMonthly":{"description":"AI tokens consumed in the organisation per month. 0 = unlimited.","type":"number"},"apiRequestsMonthly":{"description":"Authenticated public API requests processed for the organisation per month. 0 = unlimited.","type":"number"},"forms":{"description":"Forms in the organisation. 0 = unlimited.","type":"number"}}},"product":{"anyOf":[{"type":"object","required":["name","code","price","active","subscriptionInterval"],"properties":{"name":{"description":"Product slug.","type":"string"},"code":{"description":"Product code.","type":"string"},"price":{"description":"Product price.","type":"number"},"active":{"description":"Whether the product is active.","type":"boolean"},"subscriptionInterval":{"description":"Subscription interval (e.g. 1m).","anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]}}},"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["id","code","position","monthlyPriceCzk","priceFrom","commission","limits","product"],"properties":{"id":{"description":"Tariff ID.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"position":{"description":"Display order on the pricing page.","type":"number"},"monthlyPriceCzk":{"description":"Monthly catalogue price in WHOLE CZK without VAT. 0 = free.","type":"number"},"priceFrom":{"description":"True when monthlyPriceCzk is \"od\" — actual price is negotiated per organisation (Enterprise).","type":"boolean"},"commission":{"type":"object","required":["flatCzk","percent"],"properties":{"flatCzk":{"description":"Flat salesperson commission per sale, in CZK. Mutually exclusive with percent.","type":"number"},"percent":{"description":"Percentage commission of the actual paid price (0-100). Used by Enterprise.","type":"number"}}},"limits":{"type":"object","required":["storageMb","members","products","ordersMonthly","customers","emailsMonthly","aiTokensMonthly","apiRequestsMonthly","forms"],"properties":{"storageMb":{"description":"Total storage occupied across the organisation, in MB. 0 = unlimited.","type":"number"},"members":{"description":"Total members in the organisation. 0 = unlimited.","type":"number"},"products":{"description":"Total products in the organisation. 0 = unlimited.","type":"number"},"ordersMonthly":{"description":"New orders created in the organisation per month. 0 = unlimited.","type":"number"},"customers":{"description":"Total customers in the organisation. 0 = unlimited.","type":"number"},"emailsMonthly":{"description":"Transactional emails sent or received in the organisation per month. 0 = unlimited.","type":"number"},"aiTokensMonthly":{"description":"AI tokens consumed in the organisation per month. 0 = unlimited.","type":"number"},"apiRequestsMonthly":{"description":"Authenticated public API requests processed for the organisation per month. 0 = unlimited.","type":"number"},"forms":{"description":"Forms in the organisation. 0 = unlimited.","type":"number"}}},"product":{"anyOf":[{"type":"object","required":["name","code","price","active","subscriptionInterval"],"properties":{"name":{"description":"Product slug.","type":"string"},"code":{"description":"Product code.","type":"string"},"price":{"description":"Product price.","type":"number"},"active":{"description":"Whether the product is active.","type":"boolean"},"subscriptionInterval":{"description":"Subscription interval (e.g. 1m).","anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]}}}}},"multipart/form-data":{"schema":{"type":"array","items":{"type":"object","required":["id","code","position","monthlyPriceCzk","priceFrom","commission","limits","product"],"properties":{"id":{"description":"Tariff ID.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"position":{"description":"Display order on the pricing page.","type":"number"},"monthlyPriceCzk":{"description":"Monthly catalogue price in WHOLE CZK without VAT. 0 = free.","type":"number"},"priceFrom":{"description":"True when monthlyPriceCzk is \"od\" — actual price is negotiated per organisation (Enterprise).","type":"boolean"},"commission":{"type":"object","required":["flatCzk","percent"],"properties":{"flatCzk":{"description":"Flat salesperson commission per sale, in CZK. Mutually exclusive with percent.","type":"number"},"percent":{"description":"Percentage commission of the actual paid price (0-100). Used by Enterprise.","type":"number"}}},"limits":{"type":"object","required":["storageMb","members","products","ordersMonthly","customers","emailsMonthly","aiTokensMonthly","apiRequestsMonthly","forms"],"properties":{"storageMb":{"description":"Total storage occupied across the organisation, in MB. 0 = unlimited.","type":"number"},"members":{"description":"Total members in the organisation. 0 = unlimited.","type":"number"},"products":{"description":"Total products in the organisation. 0 = unlimited.","type":"number"},"ordersMonthly":{"description":"New orders created in the organisation per month. 0 = unlimited.","type":"number"},"customers":{"description":"Total customers in the organisation. 0 = unlimited.","type":"number"},"emailsMonthly":{"description":"Transactional emails sent or received in the organisation per month. 0 = unlimited.","type":"number"},"aiTokensMonthly":{"description":"AI tokens consumed in the organisation per month. 0 = unlimited.","type":"number"},"apiRequestsMonthly":{"description":"Authenticated public API requests processed for the organisation per month. 0 = unlimited.","type":"number"},"forms":{"description":"Forms in the organisation. 0 = unlimited.","type":"number"}}},"product":{"anyOf":[{"type":"object","required":["name","code","price","active","subscriptionInterval"],"properties":{"name":{"description":"Product slug.","type":"string"},"code":{"description":"Product code.","type":"string"},"price":{"description":"Product price.","type":"number"},"active":{"description":"Whether the product is active.","type":"boolean"},"subscriptionInterval":{"description":"Subscription interval (e.g. 1m).","anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]}}}}},"text/plain":{"schema":{"type":"array","items":{"type":"object","required":["id","code","position","monthlyPriceCzk","priceFrom","commission","limits","product"],"properties":{"id":{"description":"Tariff ID.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"position":{"description":"Display order on the pricing page.","type":"number"},"monthlyPriceCzk":{"description":"Monthly catalogue price in WHOLE CZK without VAT. 0 = free.","type":"number"},"priceFrom":{"description":"True when monthlyPriceCzk is \"od\" — actual price is negotiated per organisation (Enterprise).","type":"boolean"},"commission":{"type":"object","required":["flatCzk","percent"],"properties":{"flatCzk":{"description":"Flat salesperson commission per sale, in CZK. Mutually exclusive with percent.","type":"number"},"percent":{"description":"Percentage commission of the actual paid price (0-100). Used by Enterprise.","type":"number"}}},"limits":{"type":"object","required":["storageMb","members","products","ordersMonthly","customers","emailsMonthly","aiTokensMonthly","apiRequestsMonthly","forms"],"properties":{"storageMb":{"description":"Total storage occupied across the organisation, in MB. 0 = unlimited.","type":"number"},"members":{"description":"Total members in the organisation. 0 = unlimited.","type":"number"},"products":{"description":"Total products in the organisation. 0 = unlimited.","type":"number"},"ordersMonthly":{"description":"New orders created in the organisation per month. 0 = unlimited.","type":"number"},"customers":{"description":"Total customers in the organisation. 0 = unlimited.","type":"number"},"emailsMonthly":{"description":"Transactional emails sent or received in the organisation per month. 0 = unlimited.","type":"number"},"aiTokensMonthly":{"description":"AI tokens consumed in the organisation per month. 0 = unlimited.","type":"number"},"apiRequestsMonthly":{"description":"Authenticated public API requests processed for the organisation per month. 0 = unlimited.","type":"number"},"forms":{"description":"Forms in the organisation. 0 = unlimited.","type":"number"}}},"product":{"anyOf":[{"type":"object","required":["name","code","price","active","subscriptionInterval"],"properties":{"name":{"description":"Product slug.","type":"string"},"code":{"description":"Product code.","type":"string"},"price":{"description":"Product price.","type":"number"},"active":{"description":"Whether the product is active.","type":"boolean"},"subscriptionInterval":{"description":"Subscription interval (e.g. 1m).","anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]}}}}}}}},"operationId":"getBffTariffList","tags":["Tariff"],"summary":"List available tariffs","description":"Returns all tariffs with their limits and linked product pricing. Used for displaying the public pricing page."}},"/bff/tariff/current":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"organisationId":{"description":"Organisation the report belongs to.","type":"number"},"tariff":{"type":"object","required":["id","code","name","position","monthlyPriceCzk","priceFrom","requiresCustomPrice","minCustomPriceCzk","commission","billingInterval"],"properties":{"id":{"description":"Tariff ID in cas__tariff.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"description":"Display name (falls back to `code`).","type":"string"},"position":{"description":"Display order on the pricing page.","type":"number"},"monthlyPriceCzk":{"description":"Catalogue monthly price in WHOLE CZK without VAT.","type":"number"},"priceFrom":{"description":"True when monthlyPriceCzk is \"od\" (Enterprise) — the real price is negotiated per org.","type":"boolean"},"requiresCustomPrice":{"description":"True for plans where every organisation MUST have `customPriceCzk` set (Enterprise). When true and `billing.customPriceCzk` is null, validation.customPriceMissing will be true.","type":"boolean"},"minCustomPriceCzk":{"description":"Minimum allowed value for `customPriceCzk` when `requiresCustomPrice` is true. 0 for fixed plans.","type":"number"},"commission":{"description":"Salesperson commission rule from the catalogue.","type":"object","required":["mode","flatCzk","percent"],"properties":{"mode":{"description":"Which catalogue commission rule applies.","anyOf":[{"const":"flat","type":"string"},{"const":"percent","type":"string"},{"const":"none","type":"string"}]},"flatCzk":{"description":"Flat commission per sale in CZK (mode=flat).","type":"number"},"percent":{"description":"Percentage commission of the actual paid price (mode=percent), 0–100.","type":"number"}}},"billingInterval":{"description":"Linked product subscription interval (e.g. `1m`).","anyOf":[{"type":"string"},{"type":"null"}]}}},"billing":{"description":"Per-organisation billing block — everything that may differ from the catalogue. Modify via POST /tariff/set-billing.","type":"object","required":["effectivePriceCzk","catalogueMonthlyPriceCzk","customPriceCzk","discountPercent","activeFrom","activeTo","paidUntil","daysUntilExpiry","isExpired","expiringSoon","note","salesperson"],"properties":{"effectivePriceCzk":{"description":"Final monthly price the org actually pays, in WHOLE CZK. Equal to customPriceCzk when set, otherwise catalogueMonthlyPriceCzk minus discountPercent.","type":"number"},"catalogueMonthlyPriceCzk":{"description":"Same as tariff.monthlyPriceCzk — included for convenience.","type":"number"},"customPriceCzk":{"description":"Negotiated monthly price in CZK. NULL = use catalogue minus discount. REQUIRED for Enterprise — use POST /tariff/set-billing to set it.","anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"description":"Discount on top of catalogue price (0–100). Ignored when customPriceCzk is set.","type":"number"},"activeFrom":{"description":"When the current assignment started.","anyOf":[{"type":"string"},{"type":"null"}]},"activeTo":{"description":"Same as paidUntil — duplicated for back-compat.","anyOf":[{"type":"string"},{"type":"null"}]},"paidUntil":{"description":"Subscription paid-until date. After this timestamp the assignment is treated as expired and must be renewed (or auto-renewed at customPriceCzk / catalogue price).","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"description":"Whole days until paidUntil. Negative = already expired. NULL when paidUntil is unset.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Convenience flag = paidUntil < now.","type":"boolean"},"expiringSoon":{"description":"True when not expired and daysUntilExpiry ≤ 14. Drives the warning badge.","type":"boolean"},"note":{"description":"Free-form admin note attached to the assignment (e.g. \"VIP customer\", contract reference).","anyOf":[{"type":"string"},{"type":"null"}]},"salesperson":{"description":"Salesperson snapshot. NULL = self-service / no salesperson recorded.","anyOf":[{"type":"object","required":["userId","username","lockedCommissionCzk"],"properties":{"userId":{"description":"cas__user(id) of the BizKitHub staff member who closed the deal.","type":"number"},"username":{"description":"Salesperson username.","anyOf":[{"type":"string"},{"type":"null"}]},"lockedCommissionCzk":{"description":"Snapshot of the commission owed for this assignment, in CZK.","anyOf":[{"type":"number"},{"type":"null"}]}}},{"type":"null"}]}}},"vendor":{"description":"The white-label partner organisation that manages this org. Returned only when parent_id is set AND the parent holds an active cas__white_label_licence row. NULL otherwise (sold directly by us, or licence revoked).","anyOf":[{"type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor.","type":"string"},"contactPerson":{"description":"Vendor's nominated contact person (vendor.support_person_id).","anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"type":"number"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"description":"Email address customers should write to. Resolved as: vendor's default_send_from_email → contact person login username → null.","anyOf":[{"type":"string"},{"type":"null"}]},"myTariff":{"type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"monthlyPriceCzk":{"description":"Final monthly price in CZK that the customer pays.","type":"number"},"priceFrom":{"type":"boolean"},"customPriceCzk":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"type":"number"},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"}}}}},{"type":"null"}]},"validation":{"description":"State flags for admin UI badges. None of these throw — they describe configuration status.","type":"object","required":["requiresCustomPrice","minCustomPriceCzk","customPriceMissing","customPriceBelowMinimum","paidUntilMissing","expired","expiringSoon"],"properties":{"requiresCustomPrice":{"description":"Mirror of tariff.requiresCustomPrice.","type":"boolean"},"minCustomPriceCzk":{"description":"Mirror of tariff.minCustomPriceCzk.","type":"number"},"customPriceMissing":{"description":"TRUE when the tariff requires a custom price and none is set. Admin UI should block billing operations and show a \"Set price first\" CTA.","type":"boolean"},"customPriceBelowMinimum":{"description":"TRUE when customPriceCzk is below minCustomPriceCzk (data drift / manual edit).","type":"boolean"},"paidUntilMissing":{"description":"TRUE when no paidUntil is set. Encourage admin to fill it for predictable renewals.","type":"boolean"},"expired":{"description":"Same as billing.isExpired.","type":"boolean"},"expiringSoon":{"description":"Same as billing.expiringSoon.","type":"boolean"}}},"period":{"description":"Current calendar-month window. All `monthly_event` counters reset on `start`.","type":"object","required":["start","end","daysElapsed","daysTotal","elapsedFraction"],"properties":{"start":{"description":"Period start (first day of current calendar month, UTC).","type":"string"},"end":{"description":"Period end (first day of next calendar month, UTC, exclusive).","type":"string"},"daysElapsed":{"description":"Days elapsed since `start`, including today (1..daysTotal).","type":"number"},"daysTotal":{"description":"Total days in the current period.","type":"number"},"elapsedFraction":{"description":"`daysElapsed / daysTotal`, rounded to 3 decimals — used for end-of-month projections.","type":"number"}}},"resources":{"description":"Per-metric breakdown ordered roughly by importance (products → orders → storage → AI → API → emails → members → …).","type":"array","items":{"type":"object","required":["key","kind","unit","used","limit","unlimited","percent","projectedAtPeriodEnd","status","source"],"properties":{"key":{"description":"Stable machine key. One of: products, orders_monthly, storage_mb, ai_tokens_monthly, api_requests_monthly, emails_monthly, members, customers, forms.","type":"string"},"kind":{"description":"`running_total` = current snapshot count (e.g. members in the org). `monthly_event` = events that accumulate in the current calendar month and reset on the 1st.","anyOf":[{"const":"running_total","type":"string"},{"const":"monthly_event","type":"string"}]},"unit":{"description":"Display unit (orders, MB, tokens, requests, emails, members, …).","type":"string"},"used":{"description":"Current usage in `unit`.","type":"number"},"limit":{"description":"Tariff cap. `0 = unlimited`.","type":"number"},"unlimited":{"description":"Convenience flag = `limit === 0`.","type":"boolean"},"percent":{"description":"`used / limit * 100`, rounded to 1 decimal. `0` when unlimited.","type":"number"},"projectedAtPeriodEnd":{"description":"For `monthly_event` resources only: linear extrapolation of `used` to the end of the period at the current burn rate. `null` for `running_total`.","anyOf":[{"type":"number"},{"type":"null"}]},"status":{"description":"Severity bucket: unlimited | ok (<80%) | warn (≥80%) | critical (≥95%) | over (≥100%). Drives badge colour in admin UI.","anyOf":[{"const":"unlimited","type":"string"},{"const":"ok","type":"string"},{"const":"warn","type":"string"},{"const":"critical","type":"string"},{"const":"over","type":"string"}]},"source":{"description":"Origin of the value (table.column or live COUNT) — for debugging.","type":"string"}}}},"history":{"description":"Historical monthly usage from cas__organisation_usage_monthly.","type":"object","required":["monthly","totals"],"properties":{"monthly":{"description":"Last 12 months of monthly counters, newest first. Months with no recorded usage are returned with zeros (gaps filled).","type":"array","items":{"type":"object","required":["periodStart","ordersCount","emailsCount","aiTokensCount","apiRequestsCount"],"properties":{"periodStart":{"description":"First day of the month, ISO date (YYYY-MM-01).","type":"string"},"ordersCount":{"description":"New orders created in the month.","type":"number"},"emailsCount":{"description":"Transactional emails sent + received in the month.","type":"number"},"aiTokensCount":{"description":"AI tokens consumed in the month.","type":"number"},"apiRequestsCount":{"description":"Authenticated public API requests in the month.","type":"number"}}}},"totals":{"description":"Sums across the returned history window. Useful for \"last 12 months\" headlines.","type":"object","required":["orders","emails","aiTokens","apiRequests"],"properties":{"orders":{"type":"number"},"emails":{"type":"number"},"aiTokens":{"type":"number"},"apiRequests":{"type":"number"}}}}}},"required":["organisationId","tariff","billing","vendor","validation","period","resources","history"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"organisationId":{"description":"Organisation the report belongs to.","type":"number"},"tariff":{"type":"object","required":["id","code","name","position","monthlyPriceCzk","priceFrom","requiresCustomPrice","minCustomPriceCzk","commission","billingInterval"],"properties":{"id":{"description":"Tariff ID in cas__tariff.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"description":"Display name (falls back to `code`).","type":"string"},"position":{"description":"Display order on the pricing page.","type":"number"},"monthlyPriceCzk":{"description":"Catalogue monthly price in WHOLE CZK without VAT.","type":"number"},"priceFrom":{"description":"True when monthlyPriceCzk is \"od\" (Enterprise) — the real price is negotiated per org.","type":"boolean"},"requiresCustomPrice":{"description":"True for plans where every organisation MUST have `customPriceCzk` set (Enterprise). When true and `billing.customPriceCzk` is null, validation.customPriceMissing will be true.","type":"boolean"},"minCustomPriceCzk":{"description":"Minimum allowed value for `customPriceCzk` when `requiresCustomPrice` is true. 0 for fixed plans.","type":"number"},"commission":{"description":"Salesperson commission rule from the catalogue.","type":"object","required":["mode","flatCzk","percent"],"properties":{"mode":{"description":"Which catalogue commission rule applies.","anyOf":[{"const":"flat","type":"string"},{"const":"percent","type":"string"},{"const":"none","type":"string"}]},"flatCzk":{"description":"Flat commission per sale in CZK (mode=flat).","type":"number"},"percent":{"description":"Percentage commission of the actual paid price (mode=percent), 0–100.","type":"number"}}},"billingInterval":{"description":"Linked product subscription interval (e.g. `1m`).","anyOf":[{"type":"string"},{"type":"null"}]}}},"billing":{"description":"Per-organisation billing block — everything that may differ from the catalogue. Modify via POST /tariff/set-billing.","type":"object","required":["effectivePriceCzk","catalogueMonthlyPriceCzk","customPriceCzk","discountPercent","activeFrom","activeTo","paidUntil","daysUntilExpiry","isExpired","expiringSoon","note","salesperson"],"properties":{"effectivePriceCzk":{"description":"Final monthly price the org actually pays, in WHOLE CZK. Equal to customPriceCzk when set, otherwise catalogueMonthlyPriceCzk minus discountPercent.","type":"number"},"catalogueMonthlyPriceCzk":{"description":"Same as tariff.monthlyPriceCzk — included for convenience.","type":"number"},"customPriceCzk":{"description":"Negotiated monthly price in CZK. NULL = use catalogue minus discount. REQUIRED for Enterprise — use POST /tariff/set-billing to set it.","anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"description":"Discount on top of catalogue price (0–100). Ignored when customPriceCzk is set.","type":"number"},"activeFrom":{"description":"When the current assignment started.","anyOf":[{"type":"string"},{"type":"null"}]},"activeTo":{"description":"Same as paidUntil — duplicated for back-compat.","anyOf":[{"type":"string"},{"type":"null"}]},"paidUntil":{"description":"Subscription paid-until date. After this timestamp the assignment is treated as expired and must be renewed (or auto-renewed at customPriceCzk / catalogue price).","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"description":"Whole days until paidUntil. Negative = already expired. NULL when paidUntil is unset.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Convenience flag = paidUntil < now.","type":"boolean"},"expiringSoon":{"description":"True when not expired and daysUntilExpiry ≤ 14. Drives the warning badge.","type":"boolean"},"note":{"description":"Free-form admin note attached to the assignment (e.g. \"VIP customer\", contract reference).","anyOf":[{"type":"string"},{"type":"null"}]},"salesperson":{"description":"Salesperson snapshot. NULL = self-service / no salesperson recorded.","anyOf":[{"type":"object","required":["userId","username","lockedCommissionCzk"],"properties":{"userId":{"description":"cas__user(id) of the BizKitHub staff member who closed the deal.","type":"number"},"username":{"description":"Salesperson username.","anyOf":[{"type":"string"},{"type":"null"}]},"lockedCommissionCzk":{"description":"Snapshot of the commission owed for this assignment, in CZK.","anyOf":[{"type":"number"},{"type":"null"}]}}},{"type":"null"}]}}},"vendor":{"description":"The white-label partner organisation that manages this org. Returned only when parent_id is set AND the parent holds an active cas__white_label_licence row. NULL otherwise (sold directly by us, or licence revoked).","anyOf":[{"type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor.","type":"string"},"contactPerson":{"description":"Vendor's nominated contact person (vendor.support_person_id).","anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"type":"number"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"description":"Email address customers should write to. Resolved as: vendor's default_send_from_email → contact person login username → null.","anyOf":[{"type":"string"},{"type":"null"}]},"myTariff":{"type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"monthlyPriceCzk":{"description":"Final monthly price in CZK that the customer pays.","type":"number"},"priceFrom":{"type":"boolean"},"customPriceCzk":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"type":"number"},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"}}}}},{"type":"null"}]},"validation":{"description":"State flags for admin UI badges. None of these throw — they describe configuration status.","type":"object","required":["requiresCustomPrice","minCustomPriceCzk","customPriceMissing","customPriceBelowMinimum","paidUntilMissing","expired","expiringSoon"],"properties":{"requiresCustomPrice":{"description":"Mirror of tariff.requiresCustomPrice.","type":"boolean"},"minCustomPriceCzk":{"description":"Mirror of tariff.minCustomPriceCzk.","type":"number"},"customPriceMissing":{"description":"TRUE when the tariff requires a custom price and none is set. Admin UI should block billing operations and show a \"Set price first\" CTA.","type":"boolean"},"customPriceBelowMinimum":{"description":"TRUE when customPriceCzk is below minCustomPriceCzk (data drift / manual edit).","type":"boolean"},"paidUntilMissing":{"description":"TRUE when no paidUntil is set. Encourage admin to fill it for predictable renewals.","type":"boolean"},"expired":{"description":"Same as billing.isExpired.","type":"boolean"},"expiringSoon":{"description":"Same as billing.expiringSoon.","type":"boolean"}}},"period":{"description":"Current calendar-month window. All `monthly_event` counters reset on `start`.","type":"object","required":["start","end","daysElapsed","daysTotal","elapsedFraction"],"properties":{"start":{"description":"Period start (first day of current calendar month, UTC).","type":"string"},"end":{"description":"Period end (first day of next calendar month, UTC, exclusive).","type":"string"},"daysElapsed":{"description":"Days elapsed since `start`, including today (1..daysTotal).","type":"number"},"daysTotal":{"description":"Total days in the current period.","type":"number"},"elapsedFraction":{"description":"`daysElapsed / daysTotal`, rounded to 3 decimals — used for end-of-month projections.","type":"number"}}},"resources":{"description":"Per-metric breakdown ordered roughly by importance (products → orders → storage → AI → API → emails → members → …).","type":"array","items":{"type":"object","required":["key","kind","unit","used","limit","unlimited","percent","projectedAtPeriodEnd","status","source"],"properties":{"key":{"description":"Stable machine key. One of: products, orders_monthly, storage_mb, ai_tokens_monthly, api_requests_monthly, emails_monthly, members, customers, forms.","type":"string"},"kind":{"description":"`running_total` = current snapshot count (e.g. members in the org). `monthly_event` = events that accumulate in the current calendar month and reset on the 1st.","anyOf":[{"const":"running_total","type":"string"},{"const":"monthly_event","type":"string"}]},"unit":{"description":"Display unit (orders, MB, tokens, requests, emails, members, …).","type":"string"},"used":{"description":"Current usage in `unit`.","type":"number"},"limit":{"description":"Tariff cap. `0 = unlimited`.","type":"number"},"unlimited":{"description":"Convenience flag = `limit === 0`.","type":"boolean"},"percent":{"description":"`used / limit * 100`, rounded to 1 decimal. `0` when unlimited.","type":"number"},"projectedAtPeriodEnd":{"description":"For `monthly_event` resources only: linear extrapolation of `used` to the end of the period at the current burn rate. `null` for `running_total`.","anyOf":[{"type":"number"},{"type":"null"}]},"status":{"description":"Severity bucket: unlimited | ok (<80%) | warn (≥80%) | critical (≥95%) | over (≥100%). Drives badge colour in admin UI.","anyOf":[{"const":"unlimited","type":"string"},{"const":"ok","type":"string"},{"const":"warn","type":"string"},{"const":"critical","type":"string"},{"const":"over","type":"string"}]},"source":{"description":"Origin of the value (table.column or live COUNT) — for debugging.","type":"string"}}}},"history":{"description":"Historical monthly usage from cas__organisation_usage_monthly.","type":"object","required":["monthly","totals"],"properties":{"monthly":{"description":"Last 12 months of monthly counters, newest first. Months with no recorded usage are returned with zeros (gaps filled).","type":"array","items":{"type":"object","required":["periodStart","ordersCount","emailsCount","aiTokensCount","apiRequestsCount"],"properties":{"periodStart":{"description":"First day of the month, ISO date (YYYY-MM-01).","type":"string"},"ordersCount":{"description":"New orders created in the month.","type":"number"},"emailsCount":{"description":"Transactional emails sent + received in the month.","type":"number"},"aiTokensCount":{"description":"AI tokens consumed in the month.","type":"number"},"apiRequestsCount":{"description":"Authenticated public API requests in the month.","type":"number"}}}},"totals":{"description":"Sums across the returned history window. Useful for \"last 12 months\" headlines.","type":"object","required":["orders","emails","aiTokens","apiRequests"],"properties":{"orders":{"type":"number"},"emails":{"type":"number"},"aiTokens":{"type":"number"},"apiRequests":{"type":"number"}}}}}},"required":["organisationId","tariff","billing","vendor","validation","period","resources","history"]}},"text/plain":{"schema":{"type":"object","properties":{"organisationId":{"description":"Organisation the report belongs to.","type":"number"},"tariff":{"type":"object","required":["id","code","name","position","monthlyPriceCzk","priceFrom","requiresCustomPrice","minCustomPriceCzk","commission","billingInterval"],"properties":{"id":{"description":"Tariff ID in cas__tariff.","type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"description":"Display name (falls back to `code`).","type":"string"},"position":{"description":"Display order on the pricing page.","type":"number"},"monthlyPriceCzk":{"description":"Catalogue monthly price in WHOLE CZK without VAT.","type":"number"},"priceFrom":{"description":"True when monthlyPriceCzk is \"od\" (Enterprise) — the real price is negotiated per org.","type":"boolean"},"requiresCustomPrice":{"description":"True for plans where every organisation MUST have `customPriceCzk` set (Enterprise). When true and `billing.customPriceCzk` is null, validation.customPriceMissing will be true.","type":"boolean"},"minCustomPriceCzk":{"description":"Minimum allowed value for `customPriceCzk` when `requiresCustomPrice` is true. 0 for fixed plans.","type":"number"},"commission":{"description":"Salesperson commission rule from the catalogue.","type":"object","required":["mode","flatCzk","percent"],"properties":{"mode":{"description":"Which catalogue commission rule applies.","anyOf":[{"const":"flat","type":"string"},{"const":"percent","type":"string"},{"const":"none","type":"string"}]},"flatCzk":{"description":"Flat commission per sale in CZK (mode=flat).","type":"number"},"percent":{"description":"Percentage commission of the actual paid price (mode=percent), 0–100.","type":"number"}}},"billingInterval":{"description":"Linked product subscription interval (e.g. `1m`).","anyOf":[{"type":"string"},{"type":"null"}]}}},"billing":{"description":"Per-organisation billing block — everything that may differ from the catalogue. Modify via POST /tariff/set-billing.","type":"object","required":["effectivePriceCzk","catalogueMonthlyPriceCzk","customPriceCzk","discountPercent","activeFrom","activeTo","paidUntil","daysUntilExpiry","isExpired","expiringSoon","note","salesperson"],"properties":{"effectivePriceCzk":{"description":"Final monthly price the org actually pays, in WHOLE CZK. Equal to customPriceCzk when set, otherwise catalogueMonthlyPriceCzk minus discountPercent.","type":"number"},"catalogueMonthlyPriceCzk":{"description":"Same as tariff.monthlyPriceCzk — included for convenience.","type":"number"},"customPriceCzk":{"description":"Negotiated monthly price in CZK. NULL = use catalogue minus discount. REQUIRED for Enterprise — use POST /tariff/set-billing to set it.","anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"description":"Discount on top of catalogue price (0–100). Ignored when customPriceCzk is set.","type":"number"},"activeFrom":{"description":"When the current assignment started.","anyOf":[{"type":"string"},{"type":"null"}]},"activeTo":{"description":"Same as paidUntil — duplicated for back-compat.","anyOf":[{"type":"string"},{"type":"null"}]},"paidUntil":{"description":"Subscription paid-until date. After this timestamp the assignment is treated as expired and must be renewed (or auto-renewed at customPriceCzk / catalogue price).","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"description":"Whole days until paidUntil. Negative = already expired. NULL when paidUntil is unset.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Convenience flag = paidUntil < now.","type":"boolean"},"expiringSoon":{"description":"True when not expired and daysUntilExpiry ≤ 14. Drives the warning badge.","type":"boolean"},"note":{"description":"Free-form admin note attached to the assignment (e.g. \"VIP customer\", contract reference).","anyOf":[{"type":"string"},{"type":"null"}]},"salesperson":{"description":"Salesperson snapshot. NULL = self-service / no salesperson recorded.","anyOf":[{"type":"object","required":["userId","username","lockedCommissionCzk"],"properties":{"userId":{"description":"cas__user(id) of the BizKitHub staff member who closed the deal.","type":"number"},"username":{"description":"Salesperson username.","anyOf":[{"type":"string"},{"type":"null"}]},"lockedCommissionCzk":{"description":"Snapshot of the commission owed for this assignment, in CZK.","anyOf":[{"type":"number"},{"type":"null"}]}}},{"type":"null"}]}}},"vendor":{"description":"The white-label partner organisation that manages this org. Returned only when parent_id is set AND the parent holds an active cas__white_label_licence row. NULL otherwise (sold directly by us, or licence revoked).","anyOf":[{"type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor.","type":"string"},"contactPerson":{"description":"Vendor's nominated contact person (vendor.support_person_id).","anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"type":"number"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"description":"Email address customers should write to. Resolved as: vendor's default_send_from_email → contact person login username → null.","anyOf":[{"type":"string"},{"type":"null"}]},"myTariff":{"type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"monthlyPriceCzk":{"description":"Final monthly price in CZK that the customer pays.","type":"number"},"priceFrom":{"type":"boolean"},"customPriceCzk":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"type":"number"},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"}}}}},{"type":"null"}]},"validation":{"description":"State flags for admin UI badges. None of these throw — they describe configuration status.","type":"object","required":["requiresCustomPrice","minCustomPriceCzk","customPriceMissing","customPriceBelowMinimum","paidUntilMissing","expired","expiringSoon"],"properties":{"requiresCustomPrice":{"description":"Mirror of tariff.requiresCustomPrice.","type":"boolean"},"minCustomPriceCzk":{"description":"Mirror of tariff.minCustomPriceCzk.","type":"number"},"customPriceMissing":{"description":"TRUE when the tariff requires a custom price and none is set. Admin UI should block billing operations and show a \"Set price first\" CTA.","type":"boolean"},"customPriceBelowMinimum":{"description":"TRUE when customPriceCzk is below minCustomPriceCzk (data drift / manual edit).","type":"boolean"},"paidUntilMissing":{"description":"TRUE when no paidUntil is set. Encourage admin to fill it for predictable renewals.","type":"boolean"},"expired":{"description":"Same as billing.isExpired.","type":"boolean"},"expiringSoon":{"description":"Same as billing.expiringSoon.","type":"boolean"}}},"period":{"description":"Current calendar-month window. All `monthly_event` counters reset on `start`.","type":"object","required":["start","end","daysElapsed","daysTotal","elapsedFraction"],"properties":{"start":{"description":"Period start (first day of current calendar month, UTC).","type":"string"},"end":{"description":"Period end (first day of next calendar month, UTC, exclusive).","type":"string"},"daysElapsed":{"description":"Days elapsed since `start`, including today (1..daysTotal).","type":"number"},"daysTotal":{"description":"Total days in the current period.","type":"number"},"elapsedFraction":{"description":"`daysElapsed / daysTotal`, rounded to 3 decimals — used for end-of-month projections.","type":"number"}}},"resources":{"description":"Per-metric breakdown ordered roughly by importance (products → orders → storage → AI → API → emails → members → …).","type":"array","items":{"type":"object","required":["key","kind","unit","used","limit","unlimited","percent","projectedAtPeriodEnd","status","source"],"properties":{"key":{"description":"Stable machine key. One of: products, orders_monthly, storage_mb, ai_tokens_monthly, api_requests_monthly, emails_monthly, members, customers, forms.","type":"string"},"kind":{"description":"`running_total` = current snapshot count (e.g. members in the org). `monthly_event` = events that accumulate in the current calendar month and reset on the 1st.","anyOf":[{"const":"running_total","type":"string"},{"const":"monthly_event","type":"string"}]},"unit":{"description":"Display unit (orders, MB, tokens, requests, emails, members, …).","type":"string"},"used":{"description":"Current usage in `unit`.","type":"number"},"limit":{"description":"Tariff cap. `0 = unlimited`.","type":"number"},"unlimited":{"description":"Convenience flag = `limit === 0`.","type":"boolean"},"percent":{"description":"`used / limit * 100`, rounded to 1 decimal. `0` when unlimited.","type":"number"},"projectedAtPeriodEnd":{"description":"For `monthly_event` resources only: linear extrapolation of `used` to the end of the period at the current burn rate. `null` for `running_total`.","anyOf":[{"type":"number"},{"type":"null"}]},"status":{"description":"Severity bucket: unlimited | ok (<80%) | warn (≥80%) | critical (≥95%) | over (≥100%). Drives badge colour in admin UI.","anyOf":[{"const":"unlimited","type":"string"},{"const":"ok","type":"string"},{"const":"warn","type":"string"},{"const":"critical","type":"string"},{"const":"over","type":"string"}]},"source":{"description":"Origin of the value (table.column or live COUNT) — for debugging.","type":"string"}}}},"history":{"description":"Historical monthly usage from cas__organisation_usage_monthly.","type":"object","required":["monthly","totals"],"properties":{"monthly":{"description":"Last 12 months of monthly counters, newest first. Months with no recorded usage are returned with zeros (gaps filled).","type":"array","items":{"type":"object","required":["periodStart","ordersCount","emailsCount","aiTokensCount","apiRequestsCount"],"properties":{"periodStart":{"description":"First day of the month, ISO date (YYYY-MM-01).","type":"string"},"ordersCount":{"description":"New orders created in the month.","type":"number"},"emailsCount":{"description":"Transactional emails sent + received in the month.","type":"number"},"aiTokensCount":{"description":"AI tokens consumed in the month.","type":"number"},"apiRequestsCount":{"description":"Authenticated public API requests in the month.","type":"number"}}}},"totals":{"description":"Sums across the returned history window. Useful for \"last 12 months\" headlines.","type":"object","required":["orders","emails","aiTokens","apiRequests"],"properties":{"orders":{"type":"number"},"emails":{"type":"number"},"aiTokens":{"type":"number"},"apiRequests":{"type":"number"}}}}}},"required":["organisationId","tariff","billing","vendor","validation","period","resources","history"]}}}}},"operationId":"getBffTariffCurrent","tags":["Tariff"],"summary":"Get current tariff, usage, and history","description":"Comprehensive tariff & usage report for the calling organisation. Returns tariff metadata (catalogue + per-org override + computed effective price), salesperson assignment, the current calendar-month period window, per-resource usage with limit/percent/projection/status, and the last 12 months of monthly usage counters (with gaps filled). Designed as the single source for the admin \"Tariff & usage\" screen."}},"/bff/tariff/assign":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"needsCustomPrice":{"description":"TRUE when the new tariff requires a custom price (Enterprise) and none is currently set. The admin should follow up with /tariff/set-billing.","type":"boolean"}},"required":["success","needsCustomPrice"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"needsCustomPrice":{"description":"TRUE when the new tariff requires a custom price (Enterprise) and none is currently set. The admin should follow up with /tariff/set-billing.","type":"boolean"}},"required":["success","needsCustomPrice"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"needsCustomPrice":{"description":"TRUE when the new tariff requires a custom price (Enterprise) and none is currently set. The admin should follow up with /tariff/set-billing.","type":"boolean"}},"required":["success","needsCustomPrice"]}}}}},"operationId":"postBffTariffAssign","tags":["Tariff","Admin"],"summary":"Assign tariff to organisation","description":"Assigns a tariff to an organisation. Updates both the organisation_tariff record and the tariff_id on the organisation table. Switches reset paid-until — follow up with /tariff/set-billing to set the negotiated price + paidUntil. Allowed for internal admin OR the vendor of the target organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug","tariffId"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"tariffId":{"description":"ID of the tariff to assign.","examples":[3],"type":"number"},"note":{"description":"Admin note (e.g. VIP client, volume discount).","examples":["VIP client"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug","tariffId"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"tariffId":{"description":"ID of the tariff to assign.","examples":[3],"type":"number"},"note":{"description":"Admin note (e.g. VIP client, volume discount).","examples":["VIP client"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug","tariffId"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"tariffId":{"description":"ID of the tariff to assign.","examples":[3],"type":"number"},"note":{"description":"Admin note (e.g. VIP client, volume discount).","examples":["VIP client"],"type":"string"}}}}}}}},"/bff/tariff/set-billing":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"organisationId":{"description":"Organisation ID.","type":"number"},"tariffId":{"description":"Assigned tariff ID.","type":"number"},"tariffCode":{"description":"Assigned tariff code.","type":"string"},"customPriceCzk":{"description":"Current custom price in CZK, or null.","anyOf":[{"type":"number"},{"type":"null"}]},"paidUntil":{"description":"Paid-until date as ISO string, or null.","anyOf":[{"type":"string"},{"type":"null"}]},"requiresCustomPrice":{"description":"Whether the tariff requires a custom price.","type":"boolean"},"minCustomPriceCzk":{"description":"Minimum allowed custom price in CZK.","type":"number"}},"required":["success","organisationId","tariffId","tariffCode","customPriceCzk","paidUntil","requiresCustomPrice","minCustomPriceCzk"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"organisationId":{"description":"Organisation ID.","type":"number"},"tariffId":{"description":"Assigned tariff ID.","type":"number"},"tariffCode":{"description":"Assigned tariff code.","type":"string"},"customPriceCzk":{"description":"Current custom price in CZK, or null.","anyOf":[{"type":"number"},{"type":"null"}]},"paidUntil":{"description":"Paid-until date as ISO string, or null.","anyOf":[{"type":"string"},{"type":"null"}]},"requiresCustomPrice":{"description":"Whether the tariff requires a custom price.","type":"boolean"},"minCustomPriceCzk":{"description":"Minimum allowed custom price in CZK.","type":"number"}},"required":["success","organisationId","tariffId","tariffCode","customPriceCzk","paidUntil","requiresCustomPrice","minCustomPriceCzk"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"organisationId":{"description":"Organisation ID.","type":"number"},"tariffId":{"description":"Assigned tariff ID.","type":"number"},"tariffCode":{"description":"Assigned tariff code.","type":"string"},"customPriceCzk":{"description":"Current custom price in CZK, or null.","anyOf":[{"type":"number"},{"type":"null"}]},"paidUntil":{"description":"Paid-until date as ISO string, or null.","anyOf":[{"type":"string"},{"type":"null"}]},"requiresCustomPrice":{"description":"Whether the tariff requires a custom price.","type":"boolean"},"minCustomPriceCzk":{"description":"Minimum allowed custom price in CZK.","type":"number"}},"required":["success","organisationId","tariffId","tariffCode","customPriceCzk","paidUntil","requiresCustomPrice","minCustomPriceCzk"]}}}}},"operationId":"postBffTariffSet-billing","tags":["Tariff","Admin"],"summary":"Set per-organisation billing (custom price + paid-until)","description":"Updates the negotiated monthly price (CZK), the paid-until date, and the admin note on an organisation tariff assignment. Validates Enterprise rules (minimum 10 000 CZK). Allowed for internal admin OR the vendor of the target organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"customPriceCzk":{"description":"Negotiated monthly price in WHOLE CZK. Omit to leave unchanged. Pass `null` to clear the override and fall back to catalogue minus discount. REQUIRED (and ≥ minCustomPriceCzk) for tariffs flagged `requiresCustomPrice` (Enterprise).","anyOf":[{"type":"number"},{"type":"null"}]},"paidUntil":{"description":"Subscription expiry as ISO date. Omit to leave unchanged. Pass `null` to clear. After this date the tariff is treated as expired and must be renewed.","anyOf":[{"type":"string"},{"type":"null"}]},"note":{"description":"Admin note attached to the assignment.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"customPriceCzk":{"description":"Negotiated monthly price in WHOLE CZK. Omit to leave unchanged. Pass `null` to clear the override and fall back to catalogue minus discount. REQUIRED (and ≥ minCustomPriceCzk) for tariffs flagged `requiresCustomPrice` (Enterprise).","anyOf":[{"type":"number"},{"type":"null"}]},"paidUntil":{"description":"Subscription expiry as ISO date. Omit to leave unchanged. Pass `null` to clear. After this date the tariff is treated as expired and must be renewed.","anyOf":[{"type":"string"},{"type":"null"}]},"note":{"description":"Admin note attached to the assignment.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"customPriceCzk":{"description":"Negotiated monthly price in WHOLE CZK. Omit to leave unchanged. Pass `null` to clear the override and fall back to catalogue minus discount. REQUIRED (and ≥ minCustomPriceCzk) for tariffs flagged `requiresCustomPrice` (Enterprise).","anyOf":[{"type":"number"},{"type":"null"}]},"paidUntil":{"description":"Subscription expiry as ISO date. Omit to leave unchanged. Pass `null` to clear. After this date the tariff is treated as expired and must be renewed.","anyOf":[{"type":"string"},{"type":"null"}]},"note":{"description":"Admin note attached to the assignment.","type":"string"}}}}}}}},"/bff/tariff/set-discount":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffTariffSet-discount","tags":["Tariff","Admin"],"summary":"Set tariff discount (legacy — prefer /tariff/set-billing)","description":"Sets a discount or custom price override on an organisation tariff assignment. Kept for backwards compatibility. New integrations should use /tariff/set-billing.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"discountPercent":{"description":"Discount percentage (0-100).","examples":[10],"type":"number"},"customPriceOverride":{"description":"Custom price override in CZK (null to remove). Prefer /tariff/set-billing.","anyOf":[{"type":"number"},{"type":"null"}]},"note":{"description":"Admin note.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"discountPercent":{"description":"Discount percentage (0-100).","examples":[10],"type":"number"},"customPriceOverride":{"description":"Custom price override in CZK (null to remove). Prefer /tariff/set-billing.","anyOf":[{"type":"number"},{"type":"null"}]},"note":{"description":"Admin note.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the target organisation.","examples":["my-shop"],"type":"string"},"discountPercent":{"description":"Discount percentage (0-100).","examples":[10],"type":"number"},"customPriceOverride":{"description":"Custom price override in CZK (null to remove). Prefer /tariff/set-billing.","anyOf":[{"type":"number"},{"type":"null"}]},"note":{"description":"Admin note.","type":"string"}}}}}}}},"/bff/tariff/seed-plans":{"post":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"plans":{"type":"array","items":{"type":"object","required":["id","code","inserted"],"properties":{"id":{"description":"Tariff ID assigned by the database.","type":"number"},"code":{"description":"Tariff code.","type":"string"},"inserted":{"description":"True if the row was newly inserted, false if updated.","type":"boolean"}}}}},"required":["plans"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"plans":{"type":"array","items":{"type":"object","required":["id","code","inserted"],"properties":{"id":{"description":"Tariff ID assigned by the database.","type":"number"},"code":{"description":"Tariff code.","type":"string"},"inserted":{"description":"True if the row was newly inserted, false if updated.","type":"boolean"}}}}},"required":["plans"]}},"text/plain":{"schema":{"type":"object","properties":{"plans":{"type":"array","items":{"type":"object","required":["id","code","inserted"],"properties":{"id":{"description":"Tariff ID assigned by the database.","type":"number"},"code":{"description":"Tariff code.","type":"string"},"inserted":{"description":"True if the row was newly inserted, false if updated.","type":"boolean"}}}}},"required":["plans"]}}}}},"operationId":"postBffTariffSeed-plans","tags":["Tariff","Admin"],"summary":"Seed standard tariff plans","description":"Idempotently inserts/updates the four standard plans (free, startup, business, enterprise) from features/tariff/tariffCatalogue.ts. Safe to re-run after editing the catalogue. Requires internal admin."}},"/bff/terminal/session":{"post":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"user":{"description":"Authenticated user info","type":"object","required":["id","name","role"],"properties":{"id":{"description":"User ID","type":"string"},"name":{"description":"Display name of the user","type":"string"},"role":{"description":"User role in the organisation","examples":["member"],"type":"string"}}},"tenant":{"description":"Current organisation context","type":"object","required":["id","name"],"properties":{"id":{"description":"Organisation ID","type":"string"},"name":{"description":"Organisation name","type":"string"}}},"cwd":{"description":"Initial working directory","examples":["/drive"],"type":"string"},"motd":{"description":"Message of the day shown on session start","type":"string"}},"required":["user","tenant","cwd","motd"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"user":{"description":"Authenticated user info","type":"object","required":["id","name","role"],"properties":{"id":{"description":"User ID","type":"string"},"name":{"description":"Display name of the user","type":"string"},"role":{"description":"User role in the organisation","examples":["member"],"type":"string"}}},"tenant":{"description":"Current organisation context","type":"object","required":["id","name"],"properties":{"id":{"description":"Organisation ID","type":"string"},"name":{"description":"Organisation name","type":"string"}}},"cwd":{"description":"Initial working directory","examples":["/drive"],"type":"string"},"motd":{"description":"Message of the day shown on session start","type":"string"}},"required":["user","tenant","cwd","motd"]}},"text/plain":{"schema":{"type":"object","properties":{"user":{"description":"Authenticated user info","type":"object","required":["id","name","role"],"properties":{"id":{"description":"User ID","type":"string"},"name":{"description":"Display name of the user","type":"string"},"role":{"description":"User role in the organisation","examples":["member"],"type":"string"}}},"tenant":{"description":"Current organisation context","type":"object","required":["id","name"],"properties":{"id":{"description":"Organisation ID","type":"string"},"name":{"description":"Organisation name","type":"string"}}},"cwd":{"description":"Initial working directory","examples":["/drive"],"type":"string"},"motd":{"description":"Message of the day shown on session start","type":"string"}},"required":["user","tenant","cwd","motd"]}}}}},"operationId":"postBffTerminalSession","tags":["Terminal"],"summary":"Initialize terminal session"}},"/bff/terminal/execute":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}},"text/plain":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}}}}},"operationId":"postBffTerminalExecute","tags":["Terminal"],"summary":"Execute terminal command","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["input"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"input":{"description":"Command string to execute","examples":["ls -la"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["input"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"input":{"description":"Command string to execute","examples":["ls -la"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["input"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"input":{"description":"Command string to execute","examples":["ls -la"],"type":"string"}}}}}}}},"/bff/terminal/execute-stream":{"post":{"parameters":[],"operationId":"postBffTerminalExecute-stream","tags":["Terminal"],"summary":"Execute terminal command with SSE streaming","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["input"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"input":{"description":"Command string to execute","examples":["ls -la"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["input"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"input":{"description":"Command string to execute","examples":["ls -la"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["input"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"input":{"description":"Command string to execute","examples":["ls -la"],"type":"string"}}}}}},"responses":{"200":{}}}},"/bff/terminal/interact":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}},"text/plain":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}}}}},"operationId":"postBffTerminalInteract","tags":["Terminal"],"summary":"Respond to interactive prompt","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["commandId","interactionId","value"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"commandId":{"description":"ID of the command awaiting input","type":"string"},"interactionId":{"description":"ID of the specific prompt to answer","type":"string"},"value":{"description":"User-provided response value","anyOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["commandId","interactionId","value"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"commandId":{"description":"ID of the command awaiting input","type":"string"},"interactionId":{"description":"ID of the specific prompt to answer","type":"string"},"value":{"description":"User-provided response value","anyOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]}}}},"text/plain":{"schema":{"type":"object","required":["commandId","interactionId","value"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"commandId":{"description":"ID of the command awaiting input","type":"string"},"interactionId":{"description":"ID of the specific prompt to answer","type":"string"},"value":{"description":"User-provided response value","anyOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]}}}}}}}},"/bff/terminal/cancel":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}},"text/plain":{"schema":{"type":"object","properties":{"commandId":{"description":"Unique identifier of the executed command","type":"string"},"outputs":{"description":"List of output blocks produced by the command","type":"array","items":{"anyOf":[{"type":"object","required":["type","content","style"],"properties":{"type":{"description":"Output type discriminator","const":"text","type":"string"},"content":{"description":"Text content of the output line","type":"string"},"style":{"description":"Visual style applied to the text","anyOf":[{"const":"info","type":"string"},{"const":"success","type":"string"},{"const":"warning","type":"string"},{"const":"error","type":"string"},{"const":"muted","type":"string"}]}}},{"type":"object","required":["type","columns","rows","total"],"properties":{"type":{"description":"Output type discriminator","const":"table","type":"string"},"columns":{"description":"Column header names","type":"array","items":{"type":"string"}},"rows":{"description":"Table row data as string arrays","type":"array","items":{"type":"array","items":{"type":"string"}}},"total":{"description":"Total number of rows before truncation","type":"number"},"truncated":{"description":"Number of rows omitted due to truncation","type":"number"}}},{"type":"object","required":["type","interactionId","promptType","message"],"properties":{"type":{"description":"Output type discriminator","const":"prompt","type":"string"},"interactionId":{"description":"Unique ID for this interactive prompt","type":"string"},"promptType":{"description":"Type of user input expected","anyOf":[{"const":"confirm","type":"string"},{"const":"input","type":"string"},{"const":"select","type":"string"},{"const":"password","type":"string"}]},"message":{"description":"Prompt message displayed to the user","type":"string"},"default":{"description":"Default value for confirm prompts","type":"boolean"},"options":{"description":"Available choices for select prompts","type":"array","items":{"type":"string"}}}},{"type":"object","required":["type","current","total","label"],"properties":{"type":{"description":"Output type discriminator","const":"progress","type":"string"},"current":{"description":"Current progress value","type":"number"},"total":{"description":"Total progress value","type":"number"},"label":{"description":"Progress bar label","type":"string"}}},{"type":"object","required":["type","url","name","size"],"properties":{"type":{"description":"Output type discriminator","const":"file","type":"string"},"url":{"description":"Download URL for the file","type":"string"},"name":{"description":"File name","examples":["report.csv"],"type":"string"},"size":{"description":"File size in bytes","type":"number"}}},{"type":"object","required":["type","data"],"properties":{"type":{"description":"Output type discriminator","const":"json","type":"string"},"data":{"description":"Arbitrary JSON payload"}}},{"type":"object","required":["type","url","label"],"properties":{"type":{"description":"Output type discriminator","const":"redirect","type":"string"},"url":{"description":"Target URL to navigate to","type":"string"},"label":{"description":"Display label for the link","type":"string"}}}]}},"status":{"description":"Current execution status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"cwd":{"description":"Working directory after command execution","examples":["/drive"],"type":"string"},"duration":{"description":"Execution time in milliseconds","type":"number"}},"required":["commandId","outputs","status","cwd","duration"]}}}}},"operationId":"postBffTerminalCancel","tags":["Terminal"],"summary":"Cancel running command","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["commandId"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"commandId":{"description":"ID of the command to cancel","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["commandId"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"commandId":{"description":"ID of the command to cancel","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["commandId"],"properties":{"cwd":{"description":"Current working directory","examples":["/drive"],"type":"string"},"commandId":{"description":"ID of the command to cancel","type":"string"}}}}}}}},"/bff/terminal/suggest":{"get":{"parameters":[{"description":"Current input text in the terminal","examples":["ls -"],"schema":{"type":"string"},"in":"query","name":"input","required":true},{"description":"Cursor position index within the input","examples":["4"],"schema":{"type":"string"},"in":"query","name":"cursor","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"suggestions":{"description":"Matching autocomplete suggestions","type":"array","items":{"type":"object","required":["value","label","type"],"properties":{"value":{"description":"Value to insert on completion","type":"string"},"label":{"description":"Display label for the suggestion","type":"string"},"type":{"description":"Category of the suggestion","anyOf":[{"const":"command","type":"string"},{"const":"subcommand","type":"string"},{"const":"param","type":"string"},{"const":"flag","type":"string"},{"const":"value","type":"string"},{"const":"path","type":"string"}]},"description":{"description":"Short help text for the suggestion","type":"string"},"completions":{"description":"Additional completion variants","type":"array","items":{"type":"string"}}}}},"context":{"description":"Parsed context of the input","type":"object","required":["currentToken"],"properties":{"command":{"description":"Detected command name","type":"string"},"subcommand":{"description":"Detected subcommand name","type":"string"},"currentToken":{"description":"Token currently being typed","type":"string"}}}},"required":["suggestions","context"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"suggestions":{"description":"Matching autocomplete suggestions","type":"array","items":{"type":"object","required":["value","label","type"],"properties":{"value":{"description":"Value to insert on completion","type":"string"},"label":{"description":"Display label for the suggestion","type":"string"},"type":{"description":"Category of the suggestion","anyOf":[{"const":"command","type":"string"},{"const":"subcommand","type":"string"},{"const":"param","type":"string"},{"const":"flag","type":"string"},{"const":"value","type":"string"},{"const":"path","type":"string"}]},"description":{"description":"Short help text for the suggestion","type":"string"},"completions":{"description":"Additional completion variants","type":"array","items":{"type":"string"}}}}},"context":{"description":"Parsed context of the input","type":"object","required":["currentToken"],"properties":{"command":{"description":"Detected command name","type":"string"},"subcommand":{"description":"Detected subcommand name","type":"string"},"currentToken":{"description":"Token currently being typed","type":"string"}}}},"required":["suggestions","context"]}},"text/plain":{"schema":{"type":"object","properties":{"suggestions":{"description":"Matching autocomplete suggestions","type":"array","items":{"type":"object","required":["value","label","type"],"properties":{"value":{"description":"Value to insert on completion","type":"string"},"label":{"description":"Display label for the suggestion","type":"string"},"type":{"description":"Category of the suggestion","anyOf":[{"const":"command","type":"string"},{"const":"subcommand","type":"string"},{"const":"param","type":"string"},{"const":"flag","type":"string"},{"const":"value","type":"string"},{"const":"path","type":"string"}]},"description":{"description":"Short help text for the suggestion","type":"string"},"completions":{"description":"Additional completion variants","type":"array","items":{"type":"string"}}}}},"context":{"description":"Parsed context of the input","type":"object","required":["currentToken"],"properties":{"command":{"description":"Detected command name","type":"string"},"subcommand":{"description":"Detected subcommand name","type":"string"},"currentToken":{"description":"Token currently being typed","type":"string"}}}},"required":["suggestions","context"]}}}}},"operationId":"getBffTerminalSuggest","tags":["Terminal"],"summary":"Get autocomplete suggestions"}},"/bff/terminal/commands":{"get":{"operationId":"getBffTerminalCommands","tags":["Terminal"],"summary":"Get available commands","responses":{"200":{}}}},"/bff/terminal/history":{"get":{"parameters":[{"description":"Maximum number of items to return","examples":["20"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Number of items to skip","examples":["0"],"schema":{"type":"string"},"in":"query","name":"offset","required":false},{"description":"Filter history by command text","schema":{"type":"string"},"in":"query","name":"search","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"History entries","type":"array","items":{"type":"object","required":["id","input","timestamp","status","duration"],"properties":{"id":{"description":"History entry ID","type":"string"},"input":{"description":"Executed command string","type":"string"},"timestamp":{"description":"ISO 8601 timestamp of execution","type":"string"},"status":{"description":"Final status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"duration":{"description":"Execution time in milliseconds","type":"number"}}}},"total":{"description":"Total number of matching entries","type":"number"},"limit":{"description":"Applied page size limit","type":"number"},"offset":{"description":"Applied offset","type":"number"}},"required":["items","total","limit","offset"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"History entries","type":"array","items":{"type":"object","required":["id","input","timestamp","status","duration"],"properties":{"id":{"description":"History entry ID","type":"string"},"input":{"description":"Executed command string","type":"string"},"timestamp":{"description":"ISO 8601 timestamp of execution","type":"string"},"status":{"description":"Final status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"duration":{"description":"Execution time in milliseconds","type":"number"}}}},"total":{"description":"Total number of matching entries","type":"number"},"limit":{"description":"Applied page size limit","type":"number"},"offset":{"description":"Applied offset","type":"number"}},"required":["items","total","limit","offset"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"History entries","type":"array","items":{"type":"object","required":["id","input","timestamp","status","duration"],"properties":{"id":{"description":"History entry ID","type":"string"},"input":{"description":"Executed command string","type":"string"},"timestamp":{"description":"ISO 8601 timestamp of execution","type":"string"},"status":{"description":"Final status of the command","anyOf":[{"const":"done","type":"string"},{"const":"awaiting_input","type":"string"},{"const":"running","type":"string"},{"const":"cancelled","type":"string"}]},"duration":{"description":"Execution time in milliseconds","type":"number"}}}},"total":{"description":"Total number of matching entries","type":"number"},"limit":{"description":"Applied page size limit","type":"number"},"offset":{"description":"Applied offset","type":"number"}},"required":["items","total","limit","offset"]}}}}},"operationId":"getBffTerminalHistory","tags":["Terminal"],"summary":"Get command history"},"delete":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"description":"Number of entries deleted","type":"number"}},"required":["deleted"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"deleted":{"description":"Number of entries deleted","type":"number"}},"required":["deleted"]}},"text/plain":{"schema":{"type":"object","properties":{"deleted":{"description":"Number of entries deleted","type":"number"}},"required":["deleted"]}}}}},"operationId":"deleteBffTerminalHistory","tags":["Terminal"],"summary":"Clear command history","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"description":"IDs of specific entries to delete; omit to clear all","type":"array","items":{"description":"History entry ID","type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"ids":{"description":"IDs of specific entries to delete; omit to clear all","type":"array","items":{"description":"History entry ID","type":"string"}}}}},"text/plain":{"schema":{"type":"object","properties":{"ids":{"description":"IDs of specific entries to delete; omit to clear all","type":"array","items":{"description":"History entry ID","type":"string"}}}}}}}}},"/bff/terminal/aliases":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"aliases":{"description":"List of user-defined aliases","type":"array","items":{"type":"object","required":["name","command","createdAt"],"properties":{"name":{"description":"Alias name","examples":["ll"],"type":"string"},"command":{"description":"Command the alias expands to","examples":["ls -la"],"type":"string"},"createdAt":{"description":"ISO 8601 creation timestamp","type":"string"}}}}},"required":["aliases"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"aliases":{"description":"List of user-defined aliases","type":"array","items":{"type":"object","required":["name","command","createdAt"],"properties":{"name":{"description":"Alias name","examples":["ll"],"type":"string"},"command":{"description":"Command the alias expands to","examples":["ls -la"],"type":"string"},"createdAt":{"description":"ISO 8601 creation timestamp","type":"string"}}}}},"required":["aliases"]}},"text/plain":{"schema":{"type":"object","properties":{"aliases":{"description":"List of user-defined aliases","type":"array","items":{"type":"object","required":["name","command","createdAt"],"properties":{"name":{"description":"Alias name","examples":["ll"],"type":"string"},"command":{"description":"Command the alias expands to","examples":["ls -la"],"type":"string"},"createdAt":{"description":"ISO 8601 creation timestamp","type":"string"}}}}},"required":["aliases"]}}}}},"operationId":"getBffTerminalAliases","tags":["Terminal"],"summary":"Get user aliases"},"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"alias":{"description":"The created or updated alias","type":"object","required":["name","command","createdAt"],"properties":{"name":{"description":"Alias name","type":"string"},"command":{"description":"Command the alias expands to","type":"string"},"createdAt":{"description":"ISO 8601 creation timestamp","type":"string"}}},"created":{"description":"True if a new alias was created, false if an existing one was updated","type":"boolean"}},"required":["alias","created"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"alias":{"description":"The created or updated alias","type":"object","required":["name","command","createdAt"],"properties":{"name":{"description":"Alias name","type":"string"},"command":{"description":"Command the alias expands to","type":"string"},"createdAt":{"description":"ISO 8601 creation timestamp","type":"string"}}},"created":{"description":"True if a new alias was created, false if an existing one was updated","type":"boolean"}},"required":["alias","created"]}},"text/plain":{"schema":{"type":"object","properties":{"alias":{"description":"The created or updated alias","type":"object","required":["name","command","createdAt"],"properties":{"name":{"description":"Alias name","type":"string"},"command":{"description":"Command the alias expands to","type":"string"},"createdAt":{"description":"ISO 8601 creation timestamp","type":"string"}}},"created":{"description":"True if a new alias was created, false if an existing one was updated","type":"boolean"}},"required":["alias","created"]}}}}},"operationId":"postBffTerminalAliases","tags":["Terminal"],"summary":"Create or update alias","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","command"],"properties":{"name":{"description":"Alias name","examples":["ll"],"type":"string"},"command":{"description":"Command the alias should expand to","examples":["ls -la"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["name","command"],"properties":{"name":{"description":"Alias name","examples":["ll"],"type":"string"},"command":{"description":"Command the alias should expand to","examples":["ls -la"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["name","command"],"properties":{"name":{"description":"Alias name","examples":["ll"],"type":"string"},"command":{"description":"Command the alias should expand to","examples":["ls -la"],"type":"string"}}}}}}},"delete":{"parameters":[{"description":"Name of the alias to delete","examples":["ll"],"schema":{"type":"string"},"in":"query","name":"name","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"description":"True if the alias existed and was removed","type":"boolean"}},"required":["deleted"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"deleted":{"description":"True if the alias existed and was removed","type":"boolean"}},"required":["deleted"]}},"text/plain":{"schema":{"type":"object","properties":{"deleted":{"description":"True if the alias existed and was removed","type":"boolean"}},"required":["deleted"]}}}}},"operationId":"deleteBffTerminalAliases","tags":["Terminal"],"summary":"Delete alias"}},"/bff/test/ping":{"get":{"operationId":"getBffTestPing","tags":["bff"],"responses":{"200":{}}}},"/bff/test/pdf":{"get":{"operationId":"getBffTestPdf","tags":["bff"],"responses":{"200":{}}}},"/bff/test/product-import-feed":{"get":{"operationId":"getBffTestProduct-import-feed","tags":["bff"],"responses":{"200":{}}}},"/bff/test/connect-import-feed":{"get":{"operationId":"getBffTestConnect-import-feed","tags":["bff"],"responses":{"200":{}}}},"/bff/time-tracker/running":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"running":{"anyOf":[{"type":"null"},{"type":"object","required":["id","note","startedAt"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"}}}]}},"required":["running"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"running":{"anyOf":[{"type":"null"},{"type":"object","required":["id","note","startedAt"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"}}}]}},"required":["running"]}},"text/plain":{"schema":{"type":"object","properties":{"running":{"anyOf":[{"type":"null"},{"type":"object","required":["id","note","startedAt"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"}}}]}},"required":["running"]}}}}},"operationId":"getBffTime-trackerRunning","tags":["TimeTracker"],"summary":"Currently running stopwatch entry","description":"Returns the running entry for the authenticated member, or null."}},"/bff/time-tracker/list":{"get":{"parameters":[{"description":"'mine' (default) or 'org' for the agency-wide view.","schema":{"type":"string"},"in":"query","name":"scope","required":false},{"schema":{"type":"string"},"in":"query","name":"memberId","required":false},{"description":"Inclusive lower bound for work_date (YYYY-MM-DD).","schema":{"type":"string"},"in":"query","name":"from","required":false},{"description":"Inclusive upper bound for work_date (YYYY-MM-DD).","schema":{"type":"string"},"in":"query","name":"to","required":false},{"schema":{"type":"string"},"in":"query","name":"projectId","required":false},{"description":"'true' / 'false' — filter by billable flag.","schema":{"type":"string"},"in":"query","name":"billable","required":false},{"description":"'true' / 'false' — filter by write_off flag.","schema":{"type":"string"},"in":"query","name":"writeOff","required":false},{"description":"'invoiced' | 'wip' | 'all'.","schema":{"type":"string"},"in":"query","name":"invoiceStatus","required":false},{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffTime-trackerList","tags":["TimeTracker"],"summary":"List time entries","description":"Paginated list with filters. Personal scope by default; org scope for the team report.","responses":{"200":{}}}},"/bff/time-tracker/start":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"running":{"type":"object","required":["id","note","startedAt"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"}}}},"required":["running"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"running":{"type":"object","required":["id","note","startedAt"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"}}}},"required":["running"]}},"text/plain":{"schema":{"type":"object","properties":{"running":{"type":"object","required":["id","note","startedAt"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"}}}},"required":["running"]}}}}},"operationId":"postBffTime-trackerStart","tags":["TimeTracker"],"summary":"Start a stopwatch measurement","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"description":"Optional free-form note. Trimmed; empty strings are stored as null.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"note":{"description":"Optional free-form note. Trimmed; empty strings are stored as null.","type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"note":{"description":"Optional free-form note. Trimmed; empty strings are stored as null.","type":"string"}}}}}}}},"/bff/time-tracker/stop":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"stopped":{"anyOf":[{"type":"null"},{"type":"object","required":["id","note","startedAt","stoppedAt","durationMs"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"stoppedAt":{"type":"string"},"durationMs":{"type":"number"}}}]}},"required":["stopped"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"stopped":{"anyOf":[{"type":"null"},{"type":"object","required":["id","note","startedAt","stoppedAt","durationMs"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"stoppedAt":{"type":"string"},"durationMs":{"type":"number"}}}]}},"required":["stopped"]}},"text/plain":{"schema":{"type":"object","properties":{"stopped":{"anyOf":[{"type":"null"},{"type":"object","required":["id","note","startedAt","stoppedAt","durationMs"],"properties":{"id":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"stoppedAt":{"type":"string"},"durationMs":{"type":"number"}}}]}},"required":["stopped"]}}}}},"operationId":"postBffTime-trackerStop","tags":["TimeTracker"],"summary":"Stop a stopwatch measurement","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"note":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"number"},"note":{"type":"string"}}}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"number"},"note":{"type":"string"}}}}}}}},"/bff/time-tracker/write":{"post":{"parameters":[],"operationId":"postBffTime-trackerWrite","tags":["TimeTracker"],"summary":"Create a manual time entry","description":"Logs work by day and minutes, with optional project link and billing fields. Snapshots the rate at create time.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["workDate","minutes"],"properties":{"workDate":{"description":"ISO date (YYYY-MM-DD) the work is booked into.","type":"string"},"minutes":{"description":"Total minutes for this entry (1–1440).","type":"number"},"memberId":{"description":"Defaults to the authenticated member.","type":"number"},"projectId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"billable":{"type":"boolean"},"writeOff":{"type":"boolean"},"writeOffReason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["workDate","minutes"],"properties":{"workDate":{"description":"ISO date (YYYY-MM-DD) the work is booked into.","type":"string"},"minutes":{"description":"Total minutes for this entry (1–1440).","type":"number"},"memberId":{"description":"Defaults to the authenticated member.","type":"number"},"projectId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"billable":{"type":"boolean"},"writeOff":{"type":"boolean"},"writeOffReason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["workDate","minutes"],"properties":{"workDate":{"description":"ISO date (YYYY-MM-DD) the work is booked into.","type":"string"},"minutes":{"description":"Total minutes for this entry (1–1440).","type":"number"},"memberId":{"description":"Defaults to the authenticated member.","type":"number"},"projectId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"billable":{"type":"boolean"},"writeOff":{"type":"boolean"},"writeOffReason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"responses":{"200":{}}}},"/bff/time-tracker/{id}":{"patch":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"operationId":"patchBffTime-trackerById","tags":["TimeTracker"],"summary":"Update a time entry","description":"Edit any field. Refuses when the entry is already invoiced or in a locked period.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"anyOf":[{"type":"number"},{"type":"null"}]},"workDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"minutes":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"billable":{"type":"boolean"},"writeOff":{"type":"boolean"},"writeOffReason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"projectId":{"anyOf":[{"type":"number"},{"type":"null"}]},"workDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"minutes":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"billable":{"type":"boolean"},"writeOff":{"type":"boolean"},"writeOffReason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","properties":{"projectId":{"anyOf":[{"type":"number"},{"type":"null"}]},"workDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"minutes":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"billable":{"type":"boolean"},"writeOff":{"type":"boolean"},"writeOffReason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"responses":{"200":{}}},"delete":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"text/plain":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}}}}},"operationId":"deleteBffTime-trackerById","tags":["TimeTracker"],"summary":"Delete a time entry (only when not invoiced)."}},"/bff/project/list":{"get":{"parameters":[{"description":"Fulltext over name / slug / project_key.","schema":{"type":"string"},"in":"query","name":"q","required":false},{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffProjectList","tags":["Project"],"summary":"List projects with WIP roll-up","responses":{"200":{}}}},"/bff/project/{id}":{"get":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"operationId":"getBffProjectById","tags":["Project"],"summary":"Project detail","responses":{"200":{}}},"delete":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"text/plain":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}}}}},"operationId":"deleteBffProjectById","tags":["Project"],"summary":"Delete a project (refused when time entries reference it)."}},"/bff/project/write":{"post":{"parameters":[],"operationId":"postBffProjectWrite","tags":["Project"],"summary":"Create or update a project","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"id":{"description":"When set, updates this row; otherwise creates a new project.","type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"slug":{"type":"string"},"projectKey":{"type":"string"},"managerId":{"type":"number"},"projectOwnerId":{"type":"number"},"priority":{"type":"number"},"budget":{"anyOf":[{"type":"string"},{"type":"null"}]},"startDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["name"],"properties":{"id":{"description":"When set, updates this row; otherwise creates a new project.","type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"slug":{"type":"string"},"projectKey":{"type":"string"},"managerId":{"type":"number"},"projectOwnerId":{"type":"number"},"priority":{"type":"number"},"budget":{"anyOf":[{"type":"string"},{"type":"null"}]},"startDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["name"],"properties":{"id":{"description":"When set, updates this row; otherwise creates a new project.","type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"slug":{"type":"string"},"projectKey":{"type":"string"},"managerId":{"type":"number"},"projectOwnerId":{"type":"number"},"priority":{"type":"number"},"budget":{"anyOf":[{"type":"string"},{"type":"null"}]},"startDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"responses":{"200":{}}}},"/bff/project-rate/list":{"get":{"parameters":[{"description":"Scope to one project.","schema":{"type":"string"},"in":"query","name":"projectId","required":false}],"operationId":"getBffProject-rateList","tags":["ProjectRate"],"summary":"List project-rate windows","responses":{"200":{}}}},"/bff/project-rate/write":{"post":{"parameters":[],"operationId":"postBffProject-rateWrite","tags":["ProjectRate"],"summary":"Create or update a project-rate window","description":"Validity windows must not overlap per (organisation, project). Overlap returns a 400 with guidance.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["projectId","validFrom"],"properties":{"id":{"type":"number"},"projectId":{"type":"number"},"costRatePerHour":{"anyOf":[{"type":"number"},{"type":"null"}]},"billingRatePerHour":{"anyOf":[{"type":"number"},{"type":"null"}]},"currency":{"type":"string"},"billingMode":{"type":"string"},"fixedPriceAmount":{"anyOf":[{"type":"number"},{"type":"null"}]},"billingIncrementMinutes":{"type":"number"},"roundingPolicy":{"type":"string"},"validFrom":{"description":"Inclusive lower bound (YYYY-MM-DD).","type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["projectId","validFrom"],"properties":{"id":{"type":"number"},"projectId":{"type":"number"},"costRatePerHour":{"anyOf":[{"type":"number"},{"type":"null"}]},"billingRatePerHour":{"anyOf":[{"type":"number"},{"type":"null"}]},"currency":{"type":"string"},"billingMode":{"type":"string"},"fixedPriceAmount":{"anyOf":[{"type":"number"},{"type":"null"}]},"billingIncrementMinutes":{"type":"number"},"roundingPolicy":{"type":"string"},"validFrom":{"description":"Inclusive lower bound (YYYY-MM-DD).","type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["projectId","validFrom"],"properties":{"id":{"type":"number"},"projectId":{"type":"number"},"costRatePerHour":{"anyOf":[{"type":"number"},{"type":"null"}]},"billingRatePerHour":{"anyOf":[{"type":"number"},{"type":"null"}]},"currency":{"type":"string"},"billingMode":{"type":"string"},"fixedPriceAmount":{"anyOf":[{"type":"number"},{"type":"null"}]},"billingIncrementMinutes":{"type":"number"},"roundingPolicy":{"type":"string"},"validFrom":{"description":"Inclusive lower bound (YYYY-MM-DD).","type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}},"responses":{"200":{}}}},"/bff/project-rate/{id}":{"delete":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}},"text/plain":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}}}}},"operationId":"deleteBffProject-rateById","tags":["ProjectRate"],"summary":"Delete a project-rate window."}},"/bff/project-rate/generate-invoice-from-time":{"post":{"parameters":[],"operationId":"postBffProject-rateGenerate-invoice-from-time","tags":["ProjectRate","Invoice"],"summary":"Generate invoice from billable time","description":"Locks billable, unbilled time entries within the range, rounds per project rate policy, creates an invoice + items, and attaches each line back to the entries it consumed. Reversing the invoice (delete) returns the entries to WIP automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["projectId","customerContactId","from","to"],"properties":{"projectId":{"type":"number"},"customerContactId":{"description":"The shop__contact row to bill.","type":"number"},"from":{"description":"Inclusive lower bound (YYYY-MM-DD).","type":"string"},"to":{"description":"Inclusive upper bound (YYYY-MM-DD).","type":"string"},"groupBy":{"description":"'flat' (one item) or 'day' (item per work_date).","type":"string"},"vatRate":{"description":"Override VAT percent; defaults from org VAT-payer flag.","type":"number"},"publicNotice":{"description":"Free-form text shown to the customer.","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["projectId","customerContactId","from","to"],"properties":{"projectId":{"type":"number"},"customerContactId":{"description":"The shop__contact row to bill.","type":"number"},"from":{"description":"Inclusive lower bound (YYYY-MM-DD).","type":"string"},"to":{"description":"Inclusive upper bound (YYYY-MM-DD).","type":"string"},"groupBy":{"description":"'flat' (one item) or 'day' (item per work_date).","type":"string"},"vatRate":{"description":"Override VAT percent; defaults from org VAT-payer flag.","type":"number"},"publicNotice":{"description":"Free-form text shown to the customer.","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["projectId","customerContactId","from","to"],"properties":{"projectId":{"type":"number"},"customerContactId":{"description":"The shop__contact row to bill.","type":"number"},"from":{"description":"Inclusive lower bound (YYYY-MM-DD).","type":"string"},"to":{"description":"Inclusive upper bound (YYYY-MM-DD).","type":"string"},"groupBy":{"description":"'flat' (one item) or 'day' (item per work_date).","type":"string"},"vatRate":{"description":"Override VAT percent; defaults from org VAT-payer flag.","type":"number"},"publicNotice":{"description":"Free-form text shown to the customer.","type":"string"}}}}}},"responses":{"200":{}}}},"/bff/translate/text":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"translated":{"description":"The translated text","type":"string"}},"required":["translated"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"translated":{"description":"The translated text","type":"string"}},"required":["translated"]}},"text/plain":{"schema":{"type":"object","properties":{"translated":{"description":"The translated text","type":"string"}},"required":["translated"]}}}}},"operationId":"postBffTranslateText","tags":["Translate"],"summary":"Translate text to a target language","description":"Translates the given text to the target locale using AI. Source locale is auto-detected if not provided. Token usage is tracked per organisation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text","targetLocale"],"properties":{"text":{"description":"The text to translate.","examples":["Dobrý den"],"type":"string"},"targetLocale":{"description":"Target locale code (e.g. \"en\", \"de\", \"cs\").","examples":["en"],"type":"string"},"sourceLocale":{"description":"Source locale code. If omitted, the language is auto-detected.","examples":["cs"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["text","targetLocale"],"properties":{"text":{"description":"The text to translate.","examples":["Dobrý den"],"type":"string"},"targetLocale":{"description":"Target locale code (e.g. \"en\", \"de\", \"cs\").","examples":["en"],"type":"string"},"sourceLocale":{"description":"Source locale code. If omitted, the language is auto-detected.","examples":["cs"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["text","targetLocale"],"properties":{"text":{"description":"The text to translate.","examples":["Dobrý den"],"type":"string"},"targetLocale":{"description":"Target locale code (e.g. \"en\", \"de\", \"cs\").","examples":["en"],"type":"string"},"sourceLocale":{"description":"Source locale code. If omitted, the language is auto-detected.","examples":["cs"],"type":"string"}}}}}}}},"/bff/transaction/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Filter transactions linked to a specific order.","examples":["abc123"],"schema":{"type":"string"},"in":"query","name":"orderHash","required":false},{"description":"Filter by bank account external ID.","examples":["2000123456"],"schema":{"type":"string"},"in":"query","name":"filterAccount","required":false}],"responses":{"200":{"description":"Paginated list of bank transactions.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Bank transaction record.","type":"object","required":["id","date","price"],"properties":{"id":{"description":"Bank transaction ID (unique within the bank).","type":"string"},"date":{"description":"Transaction date.","anyOf":[{"description":"Transaction date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"price":{"description":"Transaction amount. Positive = incoming, negative = outgoing.","type":"object","required":["priceWithoutVat","priceWithVat","vat","currency","currencyLocale"],"properties":{"priceWithoutVat":{"description":"Amount without VAT.","type":"number"},"priceWithVat":{"description":"Amount with VAT (the actual transferred amount).","type":"number"},"vat":{"description":"VAT amount.","type":"number"},"currency":{"description":"Currency code (e.g., \"CZK\").","type":"string"},"currencyLocale":{"description":"Locale string for currency formatting.","type":"string"}}},"toAccount":{"description":"Counterparty account number.","type":"string"},"toAccountName":{"description":"Counterparty account holder name.","type":"string"},"toBankCode":{"description":"Counterparty bank code.","type":"number"},"toBankName":{"description":"Counterparty bank name.","type":"string"},"constantSymbol":{"description":"Constant symbol (KS).","type":"number"},"variableSymbol":{"description":"Variable symbol (VS) - used for order matching.","type":"number"},"specificSymbol":{"description":"Specific symbol (SS).","type":"number"},"userNotice":{"description":"Notice for the recipient.","type":"string"},"toMessage":{"description":"Message for the recipient.","type":"string"},"type":{"description":"Raw transaction type from the bank.","type":"string"},"sender":{"description":"Sender identification.","type":"string"},"message":{"description":"Transaction message.","type":"string"},"comment":{"description":"Internal comment.","type":"string"},"bic":{"description":"Counterparty BIC/SWIFT code.","type":"string"},"idTransaction":{"description":"Internal transaction reference number.","type":"number"},"orderHash":{"description":"Matched order hash (for linking to order detail).","type":"string"},"orderNumber":{"description":"Matched order number.","type":"string"},"orderGroup":{"description":"Order group name.","type":"string"},"typeCode":{"description":"Transaction category code.","type":"string"},"typeLabel":{"description":"Transaction category label.","type":"string"},"typeColor":{"description":"Transaction category hex color.","type":"string"}}}},"itemCount":{"description":"Total number of transactions matching the filter (before pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Bank transaction record.","type":"object","required":["id","date","price"],"properties":{"id":{"description":"Bank transaction ID (unique within the bank).","type":"string"},"date":{"description":"Transaction date.","anyOf":[{"description":"Transaction date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"price":{"description":"Transaction amount. Positive = incoming, negative = outgoing.","type":"object","required":["priceWithoutVat","priceWithVat","vat","currency","currencyLocale"],"properties":{"priceWithoutVat":{"description":"Amount without VAT.","type":"number"},"priceWithVat":{"description":"Amount with VAT (the actual transferred amount).","type":"number"},"vat":{"description":"VAT amount.","type":"number"},"currency":{"description":"Currency code (e.g., \"CZK\").","type":"string"},"currencyLocale":{"description":"Locale string for currency formatting.","type":"string"}}},"toAccount":{"description":"Counterparty account number.","type":"string"},"toAccountName":{"description":"Counterparty account holder name.","type":"string"},"toBankCode":{"description":"Counterparty bank code.","type":"number"},"toBankName":{"description":"Counterparty bank name.","type":"string"},"constantSymbol":{"description":"Constant symbol (KS).","type":"number"},"variableSymbol":{"description":"Variable symbol (VS) - used for order matching.","type":"number"},"specificSymbol":{"description":"Specific symbol (SS).","type":"number"},"userNotice":{"description":"Notice for the recipient.","type":"string"},"toMessage":{"description":"Message for the recipient.","type":"string"},"type":{"description":"Raw transaction type from the bank.","type":"string"},"sender":{"description":"Sender identification.","type":"string"},"message":{"description":"Transaction message.","type":"string"},"comment":{"description":"Internal comment.","type":"string"},"bic":{"description":"Counterparty BIC/SWIFT code.","type":"string"},"idTransaction":{"description":"Internal transaction reference number.","type":"number"},"orderHash":{"description":"Matched order hash (for linking to order detail).","type":"string"},"orderNumber":{"description":"Matched order number.","type":"string"},"orderGroup":{"description":"Order group name.","type":"string"},"typeCode":{"description":"Transaction category code.","type":"string"},"typeLabel":{"description":"Transaction category label.","type":"string"},"typeColor":{"description":"Transaction category hex color.","type":"string"}}}},"itemCount":{"description":"Total number of transactions matching the filter (before pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Bank transaction record.","type":"object","required":["id","date","price"],"properties":{"id":{"description":"Bank transaction ID (unique within the bank).","type":"string"},"date":{"description":"Transaction date.","anyOf":[{"description":"Transaction date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"price":{"description":"Transaction amount. Positive = incoming, negative = outgoing.","type":"object","required":["priceWithoutVat","priceWithVat","vat","currency","currencyLocale"],"properties":{"priceWithoutVat":{"description":"Amount without VAT.","type":"number"},"priceWithVat":{"description":"Amount with VAT (the actual transferred amount).","type":"number"},"vat":{"description":"VAT amount.","type":"number"},"currency":{"description":"Currency code (e.g., \"CZK\").","type":"string"},"currencyLocale":{"description":"Locale string for currency formatting.","type":"string"}}},"toAccount":{"description":"Counterparty account number.","type":"string"},"toAccountName":{"description":"Counterparty account holder name.","type":"string"},"toBankCode":{"description":"Counterparty bank code.","type":"number"},"toBankName":{"description":"Counterparty bank name.","type":"string"},"constantSymbol":{"description":"Constant symbol (KS).","type":"number"},"variableSymbol":{"description":"Variable symbol (VS) - used for order matching.","type":"number"},"specificSymbol":{"description":"Specific symbol (SS).","type":"number"},"userNotice":{"description":"Notice for the recipient.","type":"string"},"toMessage":{"description":"Message for the recipient.","type":"string"},"type":{"description":"Raw transaction type from the bank.","type":"string"},"sender":{"description":"Sender identification.","type":"string"},"message":{"description":"Transaction message.","type":"string"},"comment":{"description":"Internal comment.","type":"string"},"bic":{"description":"Counterparty BIC/SWIFT code.","type":"string"},"idTransaction":{"description":"Internal transaction reference number.","type":"number"},"orderHash":{"description":"Matched order hash (for linking to order detail).","type":"string"},"orderNumber":{"description":"Matched order number.","type":"string"},"orderGroup":{"description":"Order group name.","type":"string"},"typeCode":{"description":"Transaction category code.","type":"string"},"typeLabel":{"description":"Transaction category label.","type":"string"},"typeColor":{"description":"Transaction category hex color.","type":"string"}}}},"itemCount":{"description":"Total number of transactions matching the filter (before pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffTransactionList","tags":["Transaction"],"summary":"List bank transactions","description":"Returns a paginated list of bank transactions. Supports filtering by order and bank account. Includes matched order info and transaction category when available."}},"/bff/transaction/category-list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Transaction category with aggregated financial data.","type":"object","required":["category_code","category_label","currency","color","total_income","total_expense","transaction_count","net_total"],"properties":{"category_code":{"description":"Category code identifier.","type":"string"},"category_label":{"description":"Category display label.","type":"string"},"currency":{"description":"Currency code (e.g., \"CZK\").","type":"string"},"color":{"description":"Category hex color (e.g., \"#FF5733\").","type":"string"},"total_income":{"description":"Sum of all incoming transactions in this category.","type":"number"},"total_expense":{"description":"Sum of all outgoing transactions in this category.","type":"number"},"transaction_count":{"description":"Number of transactions in this category.","type":"number"},"net_total":{"description":"Net total (income + expense). Negative if expense > income.","type":"number"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Transaction category with aggregated financial data.","type":"object","required":["category_code","category_label","currency","color","total_income","total_expense","transaction_count","net_total"],"properties":{"category_code":{"description":"Category code identifier.","type":"string"},"category_label":{"description":"Category display label.","type":"string"},"currency":{"description":"Currency code (e.g., \"CZK\").","type":"string"},"color":{"description":"Category hex color (e.g., \"#FF5733\").","type":"string"},"total_income":{"description":"Sum of all incoming transactions in this category.","type":"number"},"total_expense":{"description":"Sum of all outgoing transactions in this category.","type":"number"},"transaction_count":{"description":"Number of transactions in this category.","type":"number"},"net_total":{"description":"Net total (income + expense). Negative if expense > income.","type":"number"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"description":"Transaction category with aggregated financial data.","type":"object","required":["category_code","category_label","currency","color","total_income","total_expense","transaction_count","net_total"],"properties":{"category_code":{"description":"Category code identifier.","type":"string"},"category_label":{"description":"Category display label.","type":"string"},"currency":{"description":"Currency code (e.g., \"CZK\").","type":"string"},"color":{"description":"Category hex color (e.g., \"#FF5733\").","type":"string"},"total_income":{"description":"Sum of all incoming transactions in this category.","type":"number"},"total_expense":{"description":"Sum of all outgoing transactions in this category.","type":"number"},"transaction_count":{"description":"Number of transactions in this category.","type":"number"},"net_total":{"description":"Net total (income + expense). Negative if expense > income.","type":"number"}}}}},"required":["items"]}}}}},"operationId":"getBffTransactionCategory-list","tags":["Transaction"],"summary":"Transaction categories with totals","description":"Returns all transaction categories with aggregated income, expense, and net totals. Useful for a breakdown chart or category filter in the transaction list."}},"/bff/transaction/sync-all":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the sync completed without errors.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the sync completed without errors.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the sync completed without errors.","type":"boolean"}},"required":["success"]}}}}},"operationId":"getBffTransactionSync-all","tags":["Transaction"],"summary":"Sync all bank transactions","description":"Triggers a synchronization of transactions from all connected bank accounts (Fio API). Fetches new transactions since the last sync and automatically matches them to orders by variable symbol."}},"/bff/transaction/add-api-token":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was connected successfully.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was connected successfully.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the account was connected successfully.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffTransactionAdd-api-token","tags":["Transaction"],"summary":"Connect a bank account","description":"Adds a new Fio bank account by API token. The token is validated and the account is immediately synced. Throws an error if the token is invalid or already connected.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["apiToken"],"properties":{"apiToken":{"description":"Fio bank API token (from internetbanking settings).","examples":["abcdef1234567890"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["apiToken"],"properties":{"apiToken":{"description":"Fio bank API token (from internetbanking settings).","examples":["abcdef1234567890"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["apiToken"],"properties":{"apiToken":{"description":"Fio bank API token (from internetbanking settings).","examples":["abcdef1234567890"],"type":"string"}}}}}}}},"/bff/transaction/import-gpc":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"statementNumber":{"description":"Statement number from the 074 header.","type":"string"},"statementDate":{"description":"Statement date from the 074 header.","anyOf":[{"description":"Statement date from the 074 header.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"parsed":{"description":"Number of 075 transaction records found in the file.","type":"number"},"inserted":{"description":"Number of new transactions actually inserted.","type":"number"},"skippedDuplicates":{"description":"Number of transactions already present in the database.","type":"number"}},"required":["statementNumber","statementDate","parsed","inserted","skippedDuplicates"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"statementNumber":{"description":"Statement number from the 074 header.","type":"string"},"statementDate":{"description":"Statement date from the 074 header.","anyOf":[{"description":"Statement date from the 074 header.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"parsed":{"description":"Number of 075 transaction records found in the file.","type":"number"},"inserted":{"description":"Number of new transactions actually inserted.","type":"number"},"skippedDuplicates":{"description":"Number of transactions already present in the database.","type":"number"}},"required":["statementNumber","statementDate","parsed","inserted","skippedDuplicates"]}},"text/plain":{"schema":{"type":"object","properties":{"statementNumber":{"description":"Statement number from the 074 header.","type":"string"},"statementDate":{"description":"Statement date from the 074 header.","anyOf":[{"description":"Statement date from the 074 header.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"parsed":{"description":"Number of 075 transaction records found in the file.","type":"number"},"inserted":{"description":"Number of new transactions actually inserted.","type":"number"},"skippedDuplicates":{"description":"Number of transactions already present in the database.","type":"number"}},"required":["statementNumber","statementDate","parsed","inserted","skippedDuplicates"]}}}}},"operationId":"postBffTransactionImport-gpc","tags":["Transaction"],"summary":"Import a GPC/ABO bank statement","description":"Parses a Czech GPC/ABO fixed-width bank statement (074 header + 075 transaction lines) and inserts new transactions into the selected bank account. Idempotent: re-uploading the same statement only adds previously unseen transactions.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bankAccountExternalId","content"],"properties":{"bankAccountExternalId":{"description":"External ID of the destination bank account.","examples":["2000123456"],"type":"string"},"content":{"description":"Raw GPC/ABO statement file content (one line per record).","type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["bankAccountExternalId","content"],"properties":{"bankAccountExternalId":{"description":"External ID of the destination bank account.","examples":["2000123456"],"type":"string"},"content":{"description":"Raw GPC/ABO statement file content (one line per record).","type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["bankAccountExternalId","content"],"properties":{"bankAccountExternalId":{"description":"External ID of the destination bank account.","examples":["2000123456"],"type":"string"},"content":{"description":"Raw GPC/ABO statement file content (one line per record).","type":"string"}}}}}}}},"/bff/usage/summary":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"storage":{"description":"File storage usage breakdown.","type":"object","required":["totalBytes","categories"],"properties":{"totalBytes":{"description":"Total storage used in bytes.","type":"number"},"categories":{"description":"Breakdown of storage by file category.","type":"array","items":{"type":"object","required":["tag","count","sizeBytes"],"properties":{"tag":{"description":"Storage category tag (e.g. \"image\", \"document\").","type":"string"},"count":{"description":"Number of files in this category.","type":"number"},"sizeBytes":{"description":"Total size of files in this category, in bytes.","type":"number"}}}}}},"aiTokens":{"description":"AI token consumption statistics.","type":"object","required":["totalTokens","totalCost","byModel"],"properties":{"totalTokens":{"description":"Total AI tokens consumed.","type":"number"},"totalCost":{"description":"Total estimated cost of AI token usage.","type":"number"},"byModel":{"description":"Token usage grouped by AI model.","type":"object","patternProperties":{"^(.*)$":{"type":"object","required":["tokens","cost"],"properties":{"tokens":{"description":"Tokens consumed by this model.","type":"number"},"cost":{"description":"Estimated cost for this model.","type":"number"}}}}}}},"emails":{"description":"Email delivery statistics.","type":"object","required":["total","sent","failed","pending"],"properties":{"total":{"description":"Total emails processed.","type":"number"},"sent":{"description":"Successfully delivered emails.","type":"number"},"failed":{"description":"Emails that failed to send.","type":"number"},"pending":{"description":"Emails queued for delivery.","type":"number"}}},"counts":{"description":"Entity counts across the organisation.","type":"object","required":["products","orders","customers","members","invoices","forms","vouchers"],"properties":{"products":{"description":"Total products in the organisation.","type":"number"},"orders":{"description":"Total orders.","type":"number"},"customers":{"description":"Total customer contacts.","type":"number"},"members":{"description":"Active organisation members.","type":"number"},"invoices":{"description":"Total invoices.","type":"number"},"forms":{"description":"Total forms.","type":"number"},"vouchers":{"description":"Total vouchers.","type":"number"}}}},"required":["storage","aiTokens","emails","counts"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"storage":{"description":"File storage usage breakdown.","type":"object","required":["totalBytes","categories"],"properties":{"totalBytes":{"description":"Total storage used in bytes.","type":"number"},"categories":{"description":"Breakdown of storage by file category.","type":"array","items":{"type":"object","required":["tag","count","sizeBytes"],"properties":{"tag":{"description":"Storage category tag (e.g. \"image\", \"document\").","type":"string"},"count":{"description":"Number of files in this category.","type":"number"},"sizeBytes":{"description":"Total size of files in this category, in bytes.","type":"number"}}}}}},"aiTokens":{"description":"AI token consumption statistics.","type":"object","required":["totalTokens","totalCost","byModel"],"properties":{"totalTokens":{"description":"Total AI tokens consumed.","type":"number"},"totalCost":{"description":"Total estimated cost of AI token usage.","type":"number"},"byModel":{"description":"Token usage grouped by AI model.","type":"object","patternProperties":{"^(.*)$":{"type":"object","required":["tokens","cost"],"properties":{"tokens":{"description":"Tokens consumed by this model.","type":"number"},"cost":{"description":"Estimated cost for this model.","type":"number"}}}}}}},"emails":{"description":"Email delivery statistics.","type":"object","required":["total","sent","failed","pending"],"properties":{"total":{"description":"Total emails processed.","type":"number"},"sent":{"description":"Successfully delivered emails.","type":"number"},"failed":{"description":"Emails that failed to send.","type":"number"},"pending":{"description":"Emails queued for delivery.","type":"number"}}},"counts":{"description":"Entity counts across the organisation.","type":"object","required":["products","orders","customers","members","invoices","forms","vouchers"],"properties":{"products":{"description":"Total products in the organisation.","type":"number"},"orders":{"description":"Total orders.","type":"number"},"customers":{"description":"Total customer contacts.","type":"number"},"members":{"description":"Active organisation members.","type":"number"},"invoices":{"description":"Total invoices.","type":"number"},"forms":{"description":"Total forms.","type":"number"},"vouchers":{"description":"Total vouchers.","type":"number"}}}},"required":["storage","aiTokens","emails","counts"]}},"text/plain":{"schema":{"type":"object","properties":{"storage":{"description":"File storage usage breakdown.","type":"object","required":["totalBytes","categories"],"properties":{"totalBytes":{"description":"Total storage used in bytes.","type":"number"},"categories":{"description":"Breakdown of storage by file category.","type":"array","items":{"type":"object","required":["tag","count","sizeBytes"],"properties":{"tag":{"description":"Storage category tag (e.g. \"image\", \"document\").","type":"string"},"count":{"description":"Number of files in this category.","type":"number"},"sizeBytes":{"description":"Total size of files in this category, in bytes.","type":"number"}}}}}},"aiTokens":{"description":"AI token consumption statistics.","type":"object","required":["totalTokens","totalCost","byModel"],"properties":{"totalTokens":{"description":"Total AI tokens consumed.","type":"number"},"totalCost":{"description":"Total estimated cost of AI token usage.","type":"number"},"byModel":{"description":"Token usage grouped by AI model.","type":"object","patternProperties":{"^(.*)$":{"type":"object","required":["tokens","cost"],"properties":{"tokens":{"description":"Tokens consumed by this model.","type":"number"},"cost":{"description":"Estimated cost for this model.","type":"number"}}}}}}},"emails":{"description":"Email delivery statistics.","type":"object","required":["total","sent","failed","pending"],"properties":{"total":{"description":"Total emails processed.","type":"number"},"sent":{"description":"Successfully delivered emails.","type":"number"},"failed":{"description":"Emails that failed to send.","type":"number"},"pending":{"description":"Emails queued for delivery.","type":"number"}}},"counts":{"description":"Entity counts across the organisation.","type":"object","required":["products","orders","customers","members","invoices","forms","vouchers"],"properties":{"products":{"description":"Total products in the organisation.","type":"number"},"orders":{"description":"Total orders.","type":"number"},"customers":{"description":"Total customer contacts.","type":"number"},"members":{"description":"Active organisation members.","type":"number"},"invoices":{"description":"Total invoices.","type":"number"},"forms":{"description":"Total forms.","type":"number"},"vouchers":{"description":"Total vouchers.","type":"number"}}}},"required":["storage","aiTokens","emails","counts"]}}}}},"operationId":"getBffUsageSummary","tags":["Usage"],"summary":"Get organisation usage summary","description":"Returns a comprehensive usage summary for the authenticated organisation including storage consumption, AI token usage by model, email delivery statistics, and entity counts."}},"/bff/vat-rate/list":{"get":{"parameters":[{"description":"ISO 3166-1 alpha-2 country code filter (e.g. \"CZ\").","examples":["CZ"],"schema":{"type":"string"},"in":"query","name":"countryCode","required":false},{"description":"ISO date (YYYY-MM-DD). When provided, only rates valid on that day are returned — use this when populating a \"VAT rate\" dropdown for a specific invoice issue date.","examples":["2026-05-04"],"schema":{"type":"string"},"in":"query","name":"validOn","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","countryCode","ratePercent","validFrom","validTo","isDefault","isReverseCharge","labelCs","labelEn","displayOrder"],"properties":{"id":{"type":"number"},"code":{"description":"Logical code (e.g. \"CZ_BASIC\", \"CZ_REDUCED\", \"CZ_REVERSE\").","type":"string"},"countryCode":{"type":"string"},"ratePercent":{"description":"Numeric percent as decimal string (e.g. \"21.00\").","type":"string"},"validFrom":{"description":"ISO date (inclusive).","type":"string"},"validTo":{"description":"ISO date (exclusive). NULL = ongoing.","anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isReverseCharge":{"description":"When true, the rate is 0 % with the EU reverse-charge note.","type":"boolean"},"labelCs":{"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayOrder":{"description":"UI sort key (lower first).","type":"number"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","countryCode","ratePercent","validFrom","validTo","isDefault","isReverseCharge","labelCs","labelEn","displayOrder"],"properties":{"id":{"type":"number"},"code":{"description":"Logical code (e.g. \"CZ_BASIC\", \"CZ_REDUCED\", \"CZ_REVERSE\").","type":"string"},"countryCode":{"type":"string"},"ratePercent":{"description":"Numeric percent as decimal string (e.g. \"21.00\").","type":"string"},"validFrom":{"description":"ISO date (inclusive).","type":"string"},"validTo":{"description":"ISO date (exclusive). NULL = ongoing.","anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isReverseCharge":{"description":"When true, the rate is 0 % with the EU reverse-charge note.","type":"boolean"},"labelCs":{"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayOrder":{"description":"UI sort key (lower first).","type":"number"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","countryCode","ratePercent","validFrom","validTo","isDefault","isReverseCharge","labelCs","labelEn","displayOrder"],"properties":{"id":{"type":"number"},"code":{"description":"Logical code (e.g. \"CZ_BASIC\", \"CZ_REDUCED\", \"CZ_REVERSE\").","type":"string"},"countryCode":{"type":"string"},"ratePercent":{"description":"Numeric percent as decimal string (e.g. \"21.00\").","type":"string"},"validFrom":{"description":"ISO date (inclusive).","type":"string"},"validTo":{"description":"ISO date (exclusive). NULL = ongoing.","anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isReverseCharge":{"description":"When true, the rate is 0 % with the EU reverse-charge note.","type":"boolean"},"labelCs":{"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayOrder":{"description":"UI sort key (lower first).","type":"number"}}}}},"required":["items"]}}}}},"operationId":"getBffVat-rateList","tags":["VAT rate"],"summary":"List VAT rates","description":"Returns the time-bounded VAT rate master table. Filterable by country and \"valid on this date\". Use without `validOn` for the admin management screen, with `validOn` for invoice issue dropdowns."}},"/bff/vat-rate/resolve":{"get":{"parameters":[{"description":"Logical VAT rate code, e.g. \"CZ_BASIC\".","examples":["CZ_BASIC"],"schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"ISO 3166-1 alpha-2 country code.","examples":["CZ"],"schema":{"type":"string"},"in":"query","name":"countryCode","required":true},{"description":"ISO date the rate must be valid on (taxable supply date of the invoice).","examples":["2023-12-31"],"schema":{"type":"string"},"in":"query","name":"date","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"code":{"type":"string"},"countryCode":{"type":"string"},"ratePercent":{"description":"Numeric percent (e.g., 21 for \"21 %\", 12 for the post-2024 reduced rate).","type":"number"},"validFrom":{"type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]},"isReverseCharge":{"type":"boolean"},"labelCs":{"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","code","countryCode","ratePercent","validFrom","validTo","isReverseCharge","labelCs","labelEn"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"number"},"code":{"type":"string"},"countryCode":{"type":"string"},"ratePercent":{"description":"Numeric percent (e.g., 21 for \"21 %\", 12 for the post-2024 reduced rate).","type":"number"},"validFrom":{"type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]},"isReverseCharge":{"type":"boolean"},"labelCs":{"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","code","countryCode","ratePercent","validFrom","validTo","isReverseCharge","labelCs","labelEn"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"number"},"code":{"type":"string"},"countryCode":{"type":"string"},"ratePercent":{"description":"Numeric percent (e.g., 21 for \"21 %\", 12 for the post-2024 reduced rate).","type":"number"},"validFrom":{"type":"string"},"validTo":{"anyOf":[{"type":"string"},{"type":"null"}]},"isReverseCharge":{"type":"boolean"},"labelCs":{"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","code","countryCode","ratePercent","validFrom","validTo","isReverseCharge","labelCs","labelEn"]}}}}},"operationId":"getBffVat-rateResolve","tags":["VAT rate"],"summary":"Resolve the VAT rate in force on a given date","description":"Returns the single rate that was valid on `date` for the given country and logical code. Throws when no rate matches (admin must add a record to core__vat_rate). Use this when populating a VAT field on an invoice item — the date is the invoice's taxable supply date, not \"today\"."}},"/bff/vendor/of-current":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"vendor":{"description":"The white-label partner organisation that manages the calling org. Returned only when (a) parent_id is set AND (b) the parent holds an active cas__white_label_licence row. NULL otherwise — i.e. either we sell directly to the customer or the parent's licence is revoked.","anyOf":[{"type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug — used by /vendor/switch.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"description":"Vendor short description.","anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor (mirror of cas__white_label_licence.licence_key).","type":"string"},"contactPerson":{"description":"Vendor's nominated contact person. NULL when no support_person_id is set.","anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"description":"cas__organisation_member.id of the vendor's nominated contact.","type":"number"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"description":"Email customers should write to. Resolved as: vendor's default_send_from_email config → contact person login username → null.","anyOf":[{"type":"string"},{"type":"null"}]},"myTariff":{"type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"type":"string"},"monthlyPriceCzk":{"description":"Final monthly price the customer pays, in WHOLE CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"},"customPriceCzk":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"type":"number"},"expiresAt":{"description":"When the current paid period ends. NULL = no paid-until set.","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"}}}}},{"type":"null"}]}},"required":["vendor"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"vendor":{"description":"The white-label partner organisation that manages the calling org. Returned only when (a) parent_id is set AND (b) the parent holds an active cas__white_label_licence row. NULL otherwise — i.e. either we sell directly to the customer or the parent's licence is revoked.","anyOf":[{"type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug — used by /vendor/switch.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"description":"Vendor short description.","anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor (mirror of cas__white_label_licence.licence_key).","type":"string"},"contactPerson":{"description":"Vendor's nominated contact person. NULL when no support_person_id is set.","anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"description":"cas__organisation_member.id of the vendor's nominated contact.","type":"number"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"description":"Email customers should write to. Resolved as: vendor's default_send_from_email config → contact person login username → null.","anyOf":[{"type":"string"},{"type":"null"}]},"myTariff":{"type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"type":"string"},"monthlyPriceCzk":{"description":"Final monthly price the customer pays, in WHOLE CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"},"customPriceCzk":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"type":"number"},"expiresAt":{"description":"When the current paid period ends. NULL = no paid-until set.","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"}}}}},{"type":"null"}]}},"required":["vendor"]}},"text/plain":{"schema":{"type":"object","properties":{"vendor":{"description":"The white-label partner organisation that manages the calling org. Returned only when (a) parent_id is set AND (b) the parent holds an active cas__white_label_licence row. NULL otherwise — i.e. either we sell directly to the customer or the parent's licence is revoked.","anyOf":[{"type":"object","required":["organisation","whiteLabelLicenceId","contactPerson","contactEmail","myTariff"],"properties":{"organisation":{"type":"object","required":["id","slug","name","emoji","description"],"properties":{"id":{"description":"Vendor (parent) organisation id.","type":"number"},"slug":{"description":"Vendor slug — used by /vendor/switch.","type":"string"},"name":{"description":"Vendor display name (e.g. \"7 nápadů s.r.o.\").","type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"description":"Vendor short description.","anyOf":[{"type":"string"},{"type":"null"}]}}},"whiteLabelLicenceId":{"description":"16-character white-label licence id of the vendor (mirror of cas__white_label_licence.licence_key).","type":"string"},"contactPerson":{"description":"Vendor's nominated contact person. NULL when no support_person_id is set.","anyOf":[{"type":"object","required":["memberId","firstName","lastName"],"properties":{"memberId":{"description":"cas__organisation_member.id of the vendor's nominated contact.","type":"number"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]}}},{"type":"null"}]},"contactEmail":{"description":"Email customers should write to. Resolved as: vendor's default_send_from_email config → contact person login username → null.","anyOf":[{"type":"string"},{"type":"null"}]},"myTariff":{"type":"object","required":["id","code","name","monthlyPriceCzk","priceFrom","customPriceCzk","discountPercent","expiresAt","daysUntilExpiry","isExpired"],"properties":{"id":{"type":"number"},"code":{"description":"Tariff code (free, startup, business, enterprise).","type":"string"},"name":{"type":"string"},"monthlyPriceCzk":{"description":"Final monthly price the customer pays, in WHOLE CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"},"customPriceCzk":{"anyOf":[{"type":"number"},{"type":"null"}]},"discountPercent":{"type":"number"},"expiresAt":{"description":"When the current paid period ends. NULL = no paid-until set.","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"}}}}},{"type":"null"}]}},"required":["vendor"]}}}}},"operationId":"getBffVendorOf-current","tags":["Vendor"],"summary":"Get the vendor of the current organisation","description":"Returns the parent (vendor) organisation that resells / technically manages the calling organisation, including its technical manager. Use this in the customer admin to render the \"Můj technický správce\" widget."}},"/bff/vendor/managed-organisations":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"organisations":{"type":"array","items":{"type":"object","required":["vendor","organisation","tariff","billing","hasDirectMembership"],"properties":{"vendor":{"type":"object","required":["id","slug","name","emoji"],"properties":{"id":{"type":"number"},"slug":{"type":"string"},"name":{"type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"organisation":{"type":"object","required":["id","slug","name","emoji","insertedDate","memberCount","storageUsedMb"],"properties":{"id":{"type":"number"},"slug":{"description":"Use this with POST /vendor/switch.","type":"string"},"name":{"type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"memberCount":{"description":"Active members in the customer org.","type":"number"},"storageUsedMb":{"description":"Storage usage of the customer org, in MB.","type":"number"}}},"tariff":{"type":"object","required":["id","code","monthlyPriceCzk","priceFrom"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"monthlyPriceCzk":{"description":"Catalogue price in CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"}}},"billing":{"type":"object","required":["customPriceCzk","effectivePriceCzk","discountPercent","paidUntil","daysUntilExpiry","isExpired","expiringSoon"],"properties":{"customPriceCzk":{"description":"Negotiated price in CZK. NULL = use catalogue minus discount.","anyOf":[{"type":"number"},{"type":"null"}]},"effectivePriceCzk":{"description":"Final monthly price the customer actually pays, in CZK.","type":"number"},"discountPercent":{"type":"number"},"paidUntil":{"description":"Subscription expiry date.","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"description":"Negative when expired. NULL when paidUntil is unset.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"},"expiringSoon":{"description":"True when daysUntilExpiry ≤ 14 and not yet expired.","type":"boolean"}}},"hasDirectMembership":{"description":"True if the calling user already has a `cas__organisation_member` row in this customer org. When false, POST /vendor/switch will auto-create one before switching.","type":"boolean"}}}},"totals":{"type":"object","required":["count","monthlyRevenueCzk","expired","expiringSoon"],"properties":{"count":{"description":"Total managed organisations.","type":"number"},"monthlyRevenueCzk":{"description":"Sum of effective monthly prices, in CZK.","type":"number"},"expired":{"description":"How many are past their paidUntil.","type":"number"},"expiringSoon":{"description":"How many are within 14 days of expiry.","type":"number"}}}},"required":["organisations","totals"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"organisations":{"type":"array","items":{"type":"object","required":["vendor","organisation","tariff","billing","hasDirectMembership"],"properties":{"vendor":{"type":"object","required":["id","slug","name","emoji"],"properties":{"id":{"type":"number"},"slug":{"type":"string"},"name":{"type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"organisation":{"type":"object","required":["id","slug","name","emoji","insertedDate","memberCount","storageUsedMb"],"properties":{"id":{"type":"number"},"slug":{"description":"Use this with POST /vendor/switch.","type":"string"},"name":{"type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"memberCount":{"description":"Active members in the customer org.","type":"number"},"storageUsedMb":{"description":"Storage usage of the customer org, in MB.","type":"number"}}},"tariff":{"type":"object","required":["id","code","monthlyPriceCzk","priceFrom"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"monthlyPriceCzk":{"description":"Catalogue price in CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"}}},"billing":{"type":"object","required":["customPriceCzk","effectivePriceCzk","discountPercent","paidUntil","daysUntilExpiry","isExpired","expiringSoon"],"properties":{"customPriceCzk":{"description":"Negotiated price in CZK. NULL = use catalogue minus discount.","anyOf":[{"type":"number"},{"type":"null"}]},"effectivePriceCzk":{"description":"Final monthly price the customer actually pays, in CZK.","type":"number"},"discountPercent":{"type":"number"},"paidUntil":{"description":"Subscription expiry date.","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"description":"Negative when expired. NULL when paidUntil is unset.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"},"expiringSoon":{"description":"True when daysUntilExpiry ≤ 14 and not yet expired.","type":"boolean"}}},"hasDirectMembership":{"description":"True if the calling user already has a `cas__organisation_member` row in this customer org. When false, POST /vendor/switch will auto-create one before switching.","type":"boolean"}}}},"totals":{"type":"object","required":["count","monthlyRevenueCzk","expired","expiringSoon"],"properties":{"count":{"description":"Total managed organisations.","type":"number"},"monthlyRevenueCzk":{"description":"Sum of effective monthly prices, in CZK.","type":"number"},"expired":{"description":"How many are past their paidUntil.","type":"number"},"expiringSoon":{"description":"How many are within 14 days of expiry.","type":"number"}}}},"required":["organisations","totals"]}},"text/plain":{"schema":{"type":"object","properties":{"organisations":{"type":"array","items":{"type":"object","required":["vendor","organisation","tariff","billing","hasDirectMembership"],"properties":{"vendor":{"type":"object","required":["id","slug","name","emoji"],"properties":{"id":{"type":"number"},"slug":{"type":"string"},"name":{"type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"organisation":{"type":"object","required":["id","slug","name","emoji","insertedDate","memberCount","storageUsedMb"],"properties":{"id":{"type":"number"},"slug":{"description":"Use this with POST /vendor/switch.","type":"string"},"name":{"type":"string"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"memberCount":{"description":"Active members in the customer org.","type":"number"},"storageUsedMb":{"description":"Storage usage of the customer org, in MB.","type":"number"}}},"tariff":{"type":"object","required":["id","code","monthlyPriceCzk","priceFrom"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"monthlyPriceCzk":{"description":"Catalogue price in CZK.","type":"number"},"priceFrom":{"description":"True for Enterprise (variable pricing).","type":"boolean"}}},"billing":{"type":"object","required":["customPriceCzk","effectivePriceCzk","discountPercent","paidUntil","daysUntilExpiry","isExpired","expiringSoon"],"properties":{"customPriceCzk":{"description":"Negotiated price in CZK. NULL = use catalogue minus discount.","anyOf":[{"type":"number"},{"type":"null"}]},"effectivePriceCzk":{"description":"Final monthly price the customer actually pays, in CZK.","type":"number"},"discountPercent":{"type":"number"},"paidUntil":{"description":"Subscription expiry date.","anyOf":[{"type":"string"},{"type":"null"}]},"daysUntilExpiry":{"description":"Negative when expired. NULL when paidUntil is unset.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"type":"boolean"},"expiringSoon":{"description":"True when daysUntilExpiry ≤ 14 and not yet expired.","type":"boolean"}}},"hasDirectMembership":{"description":"True if the calling user already has a `cas__organisation_member` row in this customer org. When false, POST /vendor/switch will auto-create one before switching.","type":"boolean"}}}},"totals":{"type":"object","required":["count","monthlyRevenueCzk","expired","expiringSoon"],"properties":{"count":{"description":"Total managed organisations.","type":"number"},"monthlyRevenueCzk":{"description":"Sum of effective monthly prices, in CZK.","type":"number"},"expired":{"description":"How many are past their paidUntil.","type":"number"},"expiringSoon":{"description":"How many are within 14 days of expiry.","type":"number"}}}},"required":["organisations","totals"]}}}}},"operationId":"getBffVendorManaged-organisations","tags":["Vendor"],"summary":"List organisations managed by the calling user","description":"Returns all organisations whose `parent_id` points to an organisation in which the calling user is an active member — i.e. the orgs the user can manage as a technical manager / vendor support. Includes the tariff, billing snapshot, paid-until status, member count, and a `hasDirectMembership` flag indicating whether the user is already a direct member of each row (so the UI can decide between a \"Switch\" button and a \"Join + switch\" button)."}},"/bff/vendor/switch":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"identityId":{"anyOf":[{"type":"string"},{"type":"undefined"}]},"targetOrganisationId":{"type":"number"},"targetMemberId":{"description":"New or existing member row in the target org.","type":"number"},"vendorOrganisationId":{"description":"Vendor org through which access was granted.","type":"number"}},"required":["success","targetOrganisationId","targetMemberId","vendorOrganisationId"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"identityId":{"anyOf":[{"type":"string"},{"type":"undefined"}]},"targetOrganisationId":{"type":"number"},"targetMemberId":{"description":"New or existing member row in the target org.","type":"number"},"vendorOrganisationId":{"description":"Vendor org through which access was granted.","type":"number"}},"required":["success","targetOrganisationId","targetMemberId","vendorOrganisationId"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"identityId":{"anyOf":[{"type":"string"},{"type":"undefined"}]},"targetOrganisationId":{"type":"number"},"targetMemberId":{"description":"New or existing member row in the target org.","type":"number"},"vendorOrganisationId":{"description":"Vendor org through which access was granted.","type":"number"}},"required":["success","targetOrganisationId","targetMemberId","vendorOrganisationId"]}}}}},"operationId":"postBffVendorSwitch","tags":["Vendor"],"summary":"Switch into a managed organisation","description":"Lets a technical manager (member of a vendor organisation) switch their session into a managed customer organisation. If the caller is not yet a member of the target org, a `cas__organisation_member` row is auto-created first (idempotent). Throws PUBLIC_VENDOR_RELATION_NOT_FOUND when the target org is not a child of any org the caller belongs to.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the managed organisation to switch into.","examples":["my-shop"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the managed organisation to switch into.","examples":["my-shop"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["organisationSlug"],"properties":{"organisationSlug":{"description":"Slug of the managed organisation to switch into.","examples":["my-shop"],"type":"string"}}}}}}}},"/bff/voucher/list":{"get":{"parameters":[{"description":"Page number (1-based) for pagination.","examples":["1"],"schema":{"type":"string"},"in":"query","name":"page","required":false},{"description":"Maximum items per page (1–500, default 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Full-text search across voucher code and internal note.","examples":["SUMMER","WELCOME"],"schema":{"type":"string"},"in":"query","name":"filterFulltextQuery","required":false},{"description":"Filter by voucher type: fixed, percentage, free-credit, or free-product.","examples":["percentage"],"schema":{"type":"string"},"in":"query","name":"type","required":false},{"description":"Filter by computed status. Allowed values: active, inactive, expired, not-yet-valid, limit-reached.","examples":["active"],"schema":{"type":"string"},"in":"query","name":"status","required":false}],"responses":{"200":{"description":"Paginated list of vouchers with metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of voucher items matching the query criteria.","type":"array","items":{"description":"Single voucher item in the list.","type":"object","required":["id","type","value","usedCount","usedOrderCount","active","isOrderSingleton","note","insertedDate","updatedDate"],"properties":{"id":{"description":"Voucher code (unique identifier within organisation).","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value (amount for fixed, percentage for percentage type).","type":"string"},"usageLimit":{"description":"Maximum number of times voucher can be used. Null if unlimited.","type":"number"},"usedCount":{"description":"Number of times voucher has been used.","type":"number"},"usedOrderCount":{"description":"Number of orders that have used this voucher.","type":"number"},"active":{"description":"Whether voucher is currently active (computed from all conditions).","type":"boolean"},"isOrderSingleton":{"description":"If true, voucher can only be applied once per order.","type":"boolean"},"note":{"description":"Internal note (truncated to 100 characters in list view).","type":"string"},"lastUsedDate":{"description":"Date when voucher was last used.","anyOf":[{"description":"Date when voucher was last used.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validFrom":{"description":"Start date of validity period.","anyOf":[{"description":"Start date of validity period.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"End date of validity period.","anyOf":[{"description":"End date of validity period.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when voucher was created.","anyOf":[{"description":"Date when voucher was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when voucher was last modified.","anyOf":[{"description":"Date when voucher was last modified.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of vouchers matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of voucher items matching the query criteria.","type":"array","items":{"description":"Single voucher item in the list.","type":"object","required":["id","type","value","usedCount","usedOrderCount","active","isOrderSingleton","note","insertedDate","updatedDate"],"properties":{"id":{"description":"Voucher code (unique identifier within organisation).","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value (amount for fixed, percentage for percentage type).","type":"string"},"usageLimit":{"description":"Maximum number of times voucher can be used. Null if unlimited.","type":"number"},"usedCount":{"description":"Number of times voucher has been used.","type":"number"},"usedOrderCount":{"description":"Number of orders that have used this voucher.","type":"number"},"active":{"description":"Whether voucher is currently active (computed from all conditions).","type":"boolean"},"isOrderSingleton":{"description":"If true, voucher can only be applied once per order.","type":"boolean"},"note":{"description":"Internal note (truncated to 100 characters in list view).","type":"string"},"lastUsedDate":{"description":"Date when voucher was last used.","anyOf":[{"description":"Date when voucher was last used.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validFrom":{"description":"Start date of validity period.","anyOf":[{"description":"Start date of validity period.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"End date of validity period.","anyOf":[{"description":"End date of validity period.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when voucher was created.","anyOf":[{"description":"Date when voucher was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when voucher was last modified.","anyOf":[{"description":"Date when voucher was last modified.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of vouchers matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of voucher items matching the query criteria.","type":"array","items":{"description":"Single voucher item in the list.","type":"object","required":["id","type","value","usedCount","usedOrderCount","active","isOrderSingleton","note","insertedDate","updatedDate"],"properties":{"id":{"description":"Voucher code (unique identifier within organisation).","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value (amount for fixed, percentage for percentage type).","type":"string"},"usageLimit":{"description":"Maximum number of times voucher can be used. Null if unlimited.","type":"number"},"usedCount":{"description":"Number of times voucher has been used.","type":"number"},"usedOrderCount":{"description":"Number of orders that have used this voucher.","type":"number"},"active":{"description":"Whether voucher is currently active (computed from all conditions).","type":"boolean"},"isOrderSingleton":{"description":"If true, voucher can only be applied once per order.","type":"boolean"},"note":{"description":"Internal note (truncated to 100 characters in list view).","type":"string"},"lastUsedDate":{"description":"Date when voucher was last used.","anyOf":[{"description":"Date when voucher was last used.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validFrom":{"description":"Start date of validity period.","anyOf":[{"description":"Start date of validity period.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"End date of validity period.","anyOf":[{"description":"End date of validity period.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Date when voucher was created.","anyOf":[{"description":"Date when voucher was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Date when voucher was last modified.","anyOf":[{"description":"Date when voucher was last modified.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"itemCount":{"description":"Total number of vouchers matching the query (before pagination).","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffVoucherList","tags":["Voucher"],"summary":"List vouchers","description":"Returns a paginated list of vouchers for the authenticated organisation. Vouchers are sorted by creation date (newest first). Each voucher includes usage statistics and validity information. Supports full-text search on code/note and filtering by type and computed status."}},"/bff/voucher/detail":{"get":{"parameters":[{"description":"Voucher code to retrieve.","examples":["SUMMER2024"],"schema":{"type":"string"},"in":"query","name":"id","required":true}],"responses":{"200":{"description":"Voucher detail object.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Voucher code.","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"usageLimit":{"description":"Maximum usage count.","type":"number"},"usedCount":{"description":"Current usage count.","type":"number"},"usedOrderCount":{"description":"Number of orders using this voucher.","type":"number"},"active":{"description":"Whether voucher is active.","type":"boolean"},"isOrderSingleton":{"description":"Single use per order flag.","type":"boolean"},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"description":"Last usage date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"note":{"description":"Internal note.","type":"string"},"validFrom":{"description":"Validity start date.","anyOf":[{"description":"Validity start date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"Validity end date.","anyOf":[{"description":"Validity end date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","type","value","usedCount","usedOrderCount","active","isOrderSingleton","note","insertedDate","updatedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Voucher code.","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"usageLimit":{"description":"Maximum usage count.","type":"number"},"usedCount":{"description":"Current usage count.","type":"number"},"usedOrderCount":{"description":"Number of orders using this voucher.","type":"number"},"active":{"description":"Whether voucher is active.","type":"boolean"},"isOrderSingleton":{"description":"Single use per order flag.","type":"boolean"},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"description":"Last usage date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"note":{"description":"Internal note.","type":"string"},"validFrom":{"description":"Validity start date.","anyOf":[{"description":"Validity start date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"Validity end date.","anyOf":[{"description":"Validity end date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","type","value","usedCount","usedOrderCount","active","isOrderSingleton","note","insertedDate","updatedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Voucher code.","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"usageLimit":{"description":"Maximum usage count.","type":"number"},"usedCount":{"description":"Current usage count.","type":"number"},"usedOrderCount":{"description":"Number of orders using this voucher.","type":"number"},"active":{"description":"Whether voucher is active.","type":"boolean"},"isOrderSingleton":{"description":"Single use per order flag.","type":"boolean"},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"description":"Last usage date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"note":{"description":"Internal note.","type":"string"},"validFrom":{"description":"Validity start date.","anyOf":[{"description":"Validity start date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"validTo":{"description":"Validity end date.","anyOf":[{"description":"Validity end date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}},"required":["id","type","value","usedCount","usedOrderCount","active","isOrderSingleton","note","insertedDate","updatedDate"]}}}}},"operationId":"getBffVoucherDetail","tags":["Voucher"],"summary":"Get voucher detail","description":"Returns basic detail of a specific voucher identified by its code."}},"/bff/voucher/full-detail":{"get":{"parameters":[{"description":"Voucher code to retrieve full details for.","examples":["SUMMER2024"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"description":"Comprehensive voucher detail with context.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"Voucher code.","type":"string"},"internalId":{"description":"Internal database ID.","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"usageLimit":{"description":"Maximum usage count or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"usedCount":{"description":"Current usage count.","type":"number"},"usedOrderCount":{"description":"Number of orders using this voucher.","type":"number"},"active":{"description":"Database active flag.","type":"boolean"},"effectivelyActive":{"description":"Computed status considering expiration, usage limit, and validity period.","type":"boolean"},"isOrderSingleton":{"description":"Single use per order flag.","type":"boolean"},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"note":{"description":"Internal note (full content).","type":"string"},"validFrom":{"description":"Validity start date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"description":"Validity end date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"remainingUsage":{"description":"Remaining uses before limit is reached. Null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Whether the validity period has ended.","type":"boolean"},"isNotYetValid":{"description":"Whether the validity period has not started yet.","type":"boolean"},"daysUntilExpiration":{"description":"Days until voucher expires. Null if no expiration date or already expired.","anyOf":[{"type":"number"},{"type":"null"}]},"recentOrders":{"description":"Last 5 orders that used this voucher.","type":"array","items":{"description":"Order that used this voucher.","type":"object","required":["orderId","orderNumber","orderVariableSymbol","customerName","orderTotal","currencyCode","usedDate"],"properties":{"orderId":{"description":"Order ID.","type":"number"},"orderNumber":{"description":"Order number.","type":"string"},"orderVariableSymbol":{"description":"Variable symbol for payment.","type":"string"},"customerName":{"description":"Customer name or \"Anonymous\".","type":"string"},"orderTotal":{"description":"Total order value with VAT.","type":"string"},"currencyCode":{"description":"Currency code (e.g., CZK, EUR).","type":"string"},"usedDate":{"description":"When voucher was applied to this order.","anyOf":[{"description":"When voucher was applied to this order.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"linkedProducts":{"description":"Products that generate this voucher when purchased.","type":"array","items":{"description":"Product linked to this voucher template.","type":"object","required":["productId","productName","productCode","productActive"],"properties":{"productId":{"description":"Product ID.","type":"number"},"productName":{"description":"Product name.","type":"string"},"productCode":{"description":"Product SKU/code.","type":"string"},"productActive":{"description":"Whether product is active.","type":"boolean"}}}}},"required":["id","internalId","type","value","usageLimit","usedCount","usedOrderCount","active","effectivelyActive","isOrderSingleton","lastUsedDate","note","validFrom","validTo","insertedDate","updatedDate","remainingUsage","isExpired","isNotYetValid","daysUntilExpiration","recentOrders","linkedProducts"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"description":"Voucher code.","type":"string"},"internalId":{"description":"Internal database ID.","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"usageLimit":{"description":"Maximum usage count or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"usedCount":{"description":"Current usage count.","type":"number"},"usedOrderCount":{"description":"Number of orders using this voucher.","type":"number"},"active":{"description":"Database active flag.","type":"boolean"},"effectivelyActive":{"description":"Computed status considering expiration, usage limit, and validity period.","type":"boolean"},"isOrderSingleton":{"description":"Single use per order flag.","type":"boolean"},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"note":{"description":"Internal note (full content).","type":"string"},"validFrom":{"description":"Validity start date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"description":"Validity end date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"remainingUsage":{"description":"Remaining uses before limit is reached. Null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Whether the validity period has ended.","type":"boolean"},"isNotYetValid":{"description":"Whether the validity period has not started yet.","type":"boolean"},"daysUntilExpiration":{"description":"Days until voucher expires. Null if no expiration date or already expired.","anyOf":[{"type":"number"},{"type":"null"}]},"recentOrders":{"description":"Last 5 orders that used this voucher.","type":"array","items":{"description":"Order that used this voucher.","type":"object","required":["orderId","orderNumber","orderVariableSymbol","customerName","orderTotal","currencyCode","usedDate"],"properties":{"orderId":{"description":"Order ID.","type":"number"},"orderNumber":{"description":"Order number.","type":"string"},"orderVariableSymbol":{"description":"Variable symbol for payment.","type":"string"},"customerName":{"description":"Customer name or \"Anonymous\".","type":"string"},"orderTotal":{"description":"Total order value with VAT.","type":"string"},"currencyCode":{"description":"Currency code (e.g., CZK, EUR).","type":"string"},"usedDate":{"description":"When voucher was applied to this order.","anyOf":[{"description":"When voucher was applied to this order.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"linkedProducts":{"description":"Products that generate this voucher when purchased.","type":"array","items":{"description":"Product linked to this voucher template.","type":"object","required":["productId","productName","productCode","productActive"],"properties":{"productId":{"description":"Product ID.","type":"number"},"productName":{"description":"Product name.","type":"string"},"productCode":{"description":"Product SKU/code.","type":"string"},"productActive":{"description":"Whether product is active.","type":"boolean"}}}}},"required":["id","internalId","type","value","usageLimit","usedCount","usedOrderCount","active","effectivelyActive","isOrderSingleton","lastUsedDate","note","validFrom","validTo","insertedDate","updatedDate","remainingUsage","isExpired","isNotYetValid","daysUntilExpiration","recentOrders","linkedProducts"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"description":"Voucher code.","type":"string"},"internalId":{"description":"Internal database ID.","type":"string"},"type":{"description":"Discount type. \"fixed\" = fixed amount discount, \"percentage\" = percentage discount, \"free-credit\" = adds credit to customer account, \"free-product\" = adds free product to order.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"usageLimit":{"description":"Maximum usage count or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"usedCount":{"description":"Current usage count.","type":"number"},"usedOrderCount":{"description":"Number of orders using this voucher.","type":"number"},"active":{"description":"Database active flag.","type":"boolean"},"effectivelyActive":{"description":"Computed status considering expiration, usage limit, and validity period.","type":"boolean"},"isOrderSingleton":{"description":"Single use per order flag.","type":"boolean"},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"note":{"description":"Internal note (full content).","type":"string"},"validFrom":{"description":"Validity start date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"description":"Validity end date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"insertedDate":{"description":"Creation date.","anyOf":[{"description":"Creation date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"updatedDate":{"description":"Last modification date.","anyOf":[{"description":"Last modification date.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"remainingUsage":{"description":"Remaining uses before limit is reached. Null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Whether the validity period has ended.","type":"boolean"},"isNotYetValid":{"description":"Whether the validity period has not started yet.","type":"boolean"},"daysUntilExpiration":{"description":"Days until voucher expires. Null if no expiration date or already expired.","anyOf":[{"type":"number"},{"type":"null"}]},"recentOrders":{"description":"Last 5 orders that used this voucher.","type":"array","items":{"description":"Order that used this voucher.","type":"object","required":["orderId","orderNumber","orderVariableSymbol","customerName","orderTotal","currencyCode","usedDate"],"properties":{"orderId":{"description":"Order ID.","type":"number"},"orderNumber":{"description":"Order number.","type":"string"},"orderVariableSymbol":{"description":"Variable symbol for payment.","type":"string"},"customerName":{"description":"Customer name or \"Anonymous\".","type":"string"},"orderTotal":{"description":"Total order value with VAT.","type":"string"},"currencyCode":{"description":"Currency code (e.g., CZK, EUR).","type":"string"},"usedDate":{"description":"When voucher was applied to this order.","anyOf":[{"description":"When voucher was applied to this order.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"linkedProducts":{"description":"Products that generate this voucher when purchased.","type":"array","items":{"description":"Product linked to this voucher template.","type":"object","required":["productId","productName","productCode","productActive"],"properties":{"productId":{"description":"Product ID.","type":"number"},"productName":{"description":"Product name.","type":"string"},"productCode":{"description":"Product SKU/code.","type":"string"},"productActive":{"description":"Whether product is active.","type":"boolean"}}}}},"required":["id","internalId","type","value","usageLimit","usedCount","usedOrderCount","active","effectivelyActive","isOrderSingleton","lastUsedDate","note","validFrom","validTo","insertedDate","updatedDate","remainingUsage","isExpired","isNotYetValid","daysUntilExpiration","recentOrders","linkedProducts"]}}}}},"operationId":"getBffVoucherFull-detail","tags":["Voucher"],"summary":"Get comprehensive voucher detail","description":"Returns comprehensive detail of a voucher including usage context, recent orders that used it, linked products (for voucher templates), and computed status fields like effective activity and days until expiration."}},"/bff/voucher/usage-history":{"get":{"parameters":[{"description":"Voucher code to get usage history for.","examples":["SUMMER2024"],"schema":{"type":"string"},"in":"query","name":"code","required":true},{"description":"Maximum number of items to return (default: 50).","examples":["50"],"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"description":"Number of items to skip for pagination (default: 0).","examples":["0"],"schema":{"type":"string"},"in":"query","name":"offset","required":false}],"responses":{"200":{"description":"Paginated voucher usage history.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"Array of usage history records.","type":"array","items":{"description":"Single usage history record.","type":"object","required":["orderId","orderNumber","orderVariableSymbol","orderStatus","orderTotalPrice","currencyCode","customerName","customerEmail","usedDate","orderInsertedDate"],"properties":{"orderId":{"description":"Order ID.","type":"number"},"orderNumber":{"description":"Order number.","type":"string"},"orderVariableSymbol":{"description":"Variable symbol for payment identification.","type":"string"},"orderStatus":{"description":"Current order status label.","type":"string"},"orderTotalPrice":{"description":"Total order value with VAT.","type":"string"},"currencyCode":{"description":"Currency code.","type":"string"},"customerName":{"description":"Customer name or \"Anonymous\".","type":"string"},"customerEmail":{"description":"Customer email address.","type":"string"},"usedDate":{"description":"When the voucher was applied to this order.","anyOf":[{"description":"When the voucher was applied to this order.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderInsertedDate":{"description":"When the order was created.","anyOf":[{"description":"When the order was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"totalCount":{"description":"Total number of orders that used this voucher.","type":"number"}},"required":["items","totalCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"description":"Array of usage history records.","type":"array","items":{"description":"Single usage history record.","type":"object","required":["orderId","orderNumber","orderVariableSymbol","orderStatus","orderTotalPrice","currencyCode","customerName","customerEmail","usedDate","orderInsertedDate"],"properties":{"orderId":{"description":"Order ID.","type":"number"},"orderNumber":{"description":"Order number.","type":"string"},"orderVariableSymbol":{"description":"Variable symbol for payment identification.","type":"string"},"orderStatus":{"description":"Current order status label.","type":"string"},"orderTotalPrice":{"description":"Total order value with VAT.","type":"string"},"currencyCode":{"description":"Currency code.","type":"string"},"customerName":{"description":"Customer name or \"Anonymous\".","type":"string"},"customerEmail":{"description":"Customer email address.","type":"string"},"usedDate":{"description":"When the voucher was applied to this order.","anyOf":[{"description":"When the voucher was applied to this order.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderInsertedDate":{"description":"When the order was created.","anyOf":[{"description":"When the order was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"totalCount":{"description":"Total number of orders that used this voucher.","type":"number"}},"required":["items","totalCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"description":"Array of usage history records.","type":"array","items":{"description":"Single usage history record.","type":"object","required":["orderId","orderNumber","orderVariableSymbol","orderStatus","orderTotalPrice","currencyCode","customerName","customerEmail","usedDate","orderInsertedDate"],"properties":{"orderId":{"description":"Order ID.","type":"number"},"orderNumber":{"description":"Order number.","type":"string"},"orderVariableSymbol":{"description":"Variable symbol for payment identification.","type":"string"},"orderStatus":{"description":"Current order status label.","type":"string"},"orderTotalPrice":{"description":"Total order value with VAT.","type":"string"},"currencyCode":{"description":"Currency code.","type":"string"},"customerName":{"description":"Customer name or \"Anonymous\".","type":"string"},"customerEmail":{"description":"Customer email address.","type":"string"},"usedDate":{"description":"When the voucher was applied to this order.","anyOf":[{"description":"When the voucher was applied to this order.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},"orderInsertedDate":{"description":"When the order was created.","anyOf":[{"description":"When the order was created.","type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]}}}},"totalCount":{"description":"Total number of orders that used this voucher.","type":"number"}},"required":["items","totalCount"]}}}}},"operationId":"getBffVoucherUsage-history","tags":["Voucher"],"summary":"Get voucher usage history","description":"Returns paginated history of all orders that used a specific voucher. Includes order details, customer information, and usage timestamps."}},"/bff/voucher/statistics":{"get":{"parameters":[{"description":"Voucher code to get statistics for.","examples":["SUMMER2024"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"description":"Voucher statistics or null.","anyOf":[{"description":"Voucher statistics object.","type":"object","required":["totalOrders","totalRevenue","averageOrderValue","uniqueCustomers","firstUsedDate","lastUsedDate","usageByStatus","remainingUsage","isExpired","isActive","daysUntilExpiration"],"properties":{"totalOrders":{"description":"Total number of orders that used this voucher.","type":"number"},"totalRevenue":{"description":"Sum of all order totals where voucher was used.","type":"string"},"averageOrderValue":{"description":"Average order value when voucher was used.","type":"string"},"uniqueCustomers":{"description":"Number of distinct customers who used the voucher.","type":"number"},"firstUsedDate":{"description":"First time the voucher was used.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"lastUsedDate":{"description":"Most recent usage of the voucher.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"usageByStatus":{"description":"Breakdown of voucher usage by order status type.","type":"object","required":["paid","pending","cancelled"],"properties":{"paid":{"description":"Orders with paid/completed status.","type":"number"},"pending":{"description":"Orders with pending/processing status.","type":"number"},"cancelled":{"description":"Orders with cancelled/storno status.","type":"number"}}},"remainingUsage":{"description":"Remaining uses before limit. Null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Whether voucher validity period has ended.","type":"boolean"},"isActive":{"description":"Computed effective active status.","type":"boolean"},"daysUntilExpiration":{"description":"Days until expiration. Null if no expiration or already expired.","anyOf":[{"type":"number"},{"type":"null"}]}}},{"description":"Null if voucher not found.","type":"null"}],"content":{"application/json":{"schema":{"description":"Voucher statistics or null.","anyOf":[{"description":"Voucher statistics object.","type":"object","required":["totalOrders","totalRevenue","averageOrderValue","uniqueCustomers","firstUsedDate","lastUsedDate","usageByStatus","remainingUsage","isExpired","isActive","daysUntilExpiration"],"properties":{"totalOrders":{"description":"Total number of orders that used this voucher.","type":"number"},"totalRevenue":{"description":"Sum of all order totals where voucher was used.","type":"string"},"averageOrderValue":{"description":"Average order value when voucher was used.","type":"string"},"uniqueCustomers":{"description":"Number of distinct customers who used the voucher.","type":"number"},"firstUsedDate":{"description":"First time the voucher was used.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"lastUsedDate":{"description":"Most recent usage of the voucher.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"usageByStatus":{"description":"Breakdown of voucher usage by order status type.","type":"object","required":["paid","pending","cancelled"],"properties":{"paid":{"description":"Orders with paid/completed status.","type":"number"},"pending":{"description":"Orders with pending/processing status.","type":"number"},"cancelled":{"description":"Orders with cancelled/storno status.","type":"number"}}},"remainingUsage":{"description":"Remaining uses before limit. Null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Whether voucher validity period has ended.","type":"boolean"},"isActive":{"description":"Computed effective active status.","type":"boolean"},"daysUntilExpiration":{"description":"Days until expiration. Null if no expiration or already expired.","anyOf":[{"type":"number"},{"type":"null"}]}}},{"description":"Null if voucher not found.","type":"null"}]}},"multipart/form-data":{"schema":{"description":"Voucher statistics or null.","anyOf":[{"description":"Voucher statistics object.","type":"object","required":["totalOrders","totalRevenue","averageOrderValue","uniqueCustomers","firstUsedDate","lastUsedDate","usageByStatus","remainingUsage","isExpired","isActive","daysUntilExpiration"],"properties":{"totalOrders":{"description":"Total number of orders that used this voucher.","type":"number"},"totalRevenue":{"description":"Sum of all order totals where voucher was used.","type":"string"},"averageOrderValue":{"description":"Average order value when voucher was used.","type":"string"},"uniqueCustomers":{"description":"Number of distinct customers who used the voucher.","type":"number"},"firstUsedDate":{"description":"First time the voucher was used.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"lastUsedDate":{"description":"Most recent usage of the voucher.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"usageByStatus":{"description":"Breakdown of voucher usage by order status type.","type":"object","required":["paid","pending","cancelled"],"properties":{"paid":{"description":"Orders with paid/completed status.","type":"number"},"pending":{"description":"Orders with pending/processing status.","type":"number"},"cancelled":{"description":"Orders with cancelled/storno status.","type":"number"}}},"remainingUsage":{"description":"Remaining uses before limit. Null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Whether voucher validity period has ended.","type":"boolean"},"isActive":{"description":"Computed effective active status.","type":"boolean"},"daysUntilExpiration":{"description":"Days until expiration. Null if no expiration or already expired.","anyOf":[{"type":"number"},{"type":"null"}]}}},{"description":"Null if voucher not found.","type":"null"}]}},"text/plain":{"schema":{"description":"Voucher statistics or null.","anyOf":[{"description":"Voucher statistics object.","type":"object","required":["totalOrders","totalRevenue","averageOrderValue","uniqueCustomers","firstUsedDate","lastUsedDate","usageByStatus","remainingUsage","isExpired","isActive","daysUntilExpiration"],"properties":{"totalOrders":{"description":"Total number of orders that used this voucher.","type":"number"},"totalRevenue":{"description":"Sum of all order totals where voucher was used.","type":"string"},"averageOrderValue":{"description":"Average order value when voucher was used.","type":"string"},"uniqueCustomers":{"description":"Number of distinct customers who used the voucher.","type":"number"},"firstUsedDate":{"description":"First time the voucher was used.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"lastUsedDate":{"description":"Most recent usage of the voucher.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"usageByStatus":{"description":"Breakdown of voucher usage by order status type.","type":"object","required":["paid","pending","cancelled"],"properties":{"paid":{"description":"Orders with paid/completed status.","type":"number"},"pending":{"description":"Orders with pending/processing status.","type":"number"},"cancelled":{"description":"Orders with cancelled/storno status.","type":"number"}}},"remainingUsage":{"description":"Remaining uses before limit. Null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"isExpired":{"description":"Whether voucher validity period has ended.","type":"boolean"},"isActive":{"description":"Computed effective active status.","type":"boolean"},"daysUntilExpiration":{"description":"Days until expiration. Null if no expiration or already expired.","anyOf":[{"type":"number"},{"type":"null"}]}}},{"description":"Null if voucher not found.","type":"null"}]}}}}},"operationId":"getBffVoucherStatistics","tags":["Voucher"],"summary":"Get voucher statistics","description":"Returns analytics and statistics for a specific voucher including total revenue generated, average order value, unique customer count, and usage breakdown by order status."}},"/bff/voucher/analyze":{"get":{"parameters":[{"description":"Voucher code to analyze.","examples":["SUMMER2024"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"description":"Voucher analysis result.","anyOf":[{"description":"Voucher not found.","type":"object","required":["exists"],"properties":{"exists":{"description":"Voucher with this code does not exist.","const":false,"type":"boolean"}}},{"description":"Voucher exists — snapshot with computed status.","type":"object","required":["exists","code","type","value","active","effectivelyActive","isValid","status","usedCount","usageLimit","remainingUsage","validFrom","validTo","daysUntilExpiration","lastUsedDate","note"],"properties":{"exists":{"const":true,"type":"boolean"},"code":{"description":"Voucher code (canonical, uppercase).","type":"string"},"type":{"description":"Discount type.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"active":{"description":"Database active flag (does NOT consider expiration/limit).","type":"boolean"},"effectivelyActive":{"description":"True if voucher is currently usable (active + within validity + below limit).","type":"boolean"},"isValid":{"description":"Alias of effectivelyActive — convenient flag for UI consumers.","type":"boolean"},"status":{"description":"Computed status enum.","anyOf":[{"const":"active","type":"string"},{"const":"inactive","type":"string"},{"const":"expired","type":"string"},{"const":"not-yet-valid","type":"string"},{"const":"limit-reached","type":"string"}]},"usedCount":{"description":"Number of times voucher has been used.","type":"number"},"usageLimit":{"description":"Maximum number of uses, or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"remainingUsage":{"description":"Remaining uses, or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"validFrom":{"description":"Validity start date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"description":"Validity end date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"daysUntilExpiration":{"description":"Days remaining until expiration, or null if no expiration or already expired.","anyOf":[{"type":"number"},{"type":"null"}]},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"note":{"description":"Internal note (full content).","type":"string"}}}],"content":{"application/json":{"schema":{"description":"Voucher analysis result.","anyOf":[{"description":"Voucher not found.","type":"object","required":["exists"],"properties":{"exists":{"description":"Voucher with this code does not exist.","const":false,"type":"boolean"}}},{"description":"Voucher exists — snapshot with computed status.","type":"object","required":["exists","code","type","value","active","effectivelyActive","isValid","status","usedCount","usageLimit","remainingUsage","validFrom","validTo","daysUntilExpiration","lastUsedDate","note"],"properties":{"exists":{"const":true,"type":"boolean"},"code":{"description":"Voucher code (canonical, uppercase).","type":"string"},"type":{"description":"Discount type.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"active":{"description":"Database active flag (does NOT consider expiration/limit).","type":"boolean"},"effectivelyActive":{"description":"True if voucher is currently usable (active + within validity + below limit).","type":"boolean"},"isValid":{"description":"Alias of effectivelyActive — convenient flag for UI consumers.","type":"boolean"},"status":{"description":"Computed status enum.","anyOf":[{"const":"active","type":"string"},{"const":"inactive","type":"string"},{"const":"expired","type":"string"},{"const":"not-yet-valid","type":"string"},{"const":"limit-reached","type":"string"}]},"usedCount":{"description":"Number of times voucher has been used.","type":"number"},"usageLimit":{"description":"Maximum number of uses, or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"remainingUsage":{"description":"Remaining uses, or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"validFrom":{"description":"Validity start date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"description":"Validity end date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"daysUntilExpiration":{"description":"Days remaining until expiration, or null if no expiration or already expired.","anyOf":[{"type":"number"},{"type":"null"}]},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"note":{"description":"Internal note (full content).","type":"string"}}}]}},"multipart/form-data":{"schema":{"description":"Voucher analysis result.","anyOf":[{"description":"Voucher not found.","type":"object","required":["exists"],"properties":{"exists":{"description":"Voucher with this code does not exist.","const":false,"type":"boolean"}}},{"description":"Voucher exists — snapshot with computed status.","type":"object","required":["exists","code","type","value","active","effectivelyActive","isValid","status","usedCount","usageLimit","remainingUsage","validFrom","validTo","daysUntilExpiration","lastUsedDate","note"],"properties":{"exists":{"const":true,"type":"boolean"},"code":{"description":"Voucher code (canonical, uppercase).","type":"string"},"type":{"description":"Discount type.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"active":{"description":"Database active flag (does NOT consider expiration/limit).","type":"boolean"},"effectivelyActive":{"description":"True if voucher is currently usable (active + within validity + below limit).","type":"boolean"},"isValid":{"description":"Alias of effectivelyActive — convenient flag for UI consumers.","type":"boolean"},"status":{"description":"Computed status enum.","anyOf":[{"const":"active","type":"string"},{"const":"inactive","type":"string"},{"const":"expired","type":"string"},{"const":"not-yet-valid","type":"string"},{"const":"limit-reached","type":"string"}]},"usedCount":{"description":"Number of times voucher has been used.","type":"number"},"usageLimit":{"description":"Maximum number of uses, or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"remainingUsage":{"description":"Remaining uses, or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"validFrom":{"description":"Validity start date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"description":"Validity end date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"daysUntilExpiration":{"description":"Days remaining until expiration, or null if no expiration or already expired.","anyOf":[{"type":"number"},{"type":"null"}]},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"note":{"description":"Internal note (full content).","type":"string"}}}]}},"text/plain":{"schema":{"description":"Voucher analysis result.","anyOf":[{"description":"Voucher not found.","type":"object","required":["exists"],"properties":{"exists":{"description":"Voucher with this code does not exist.","const":false,"type":"boolean"}}},{"description":"Voucher exists — snapshot with computed status.","type":"object","required":["exists","code","type","value","active","effectivelyActive","isValid","status","usedCount","usageLimit","remainingUsage","validFrom","validTo","daysUntilExpiration","lastUsedDate","note"],"properties":{"exists":{"const":true,"type":"boolean"},"code":{"description":"Voucher code (canonical, uppercase).","type":"string"},"type":{"description":"Discount type.","anyOf":[{"const":"fixed","type":"string"},{"const":"percentage","type":"string"},{"const":"free-credit","type":"string"},{"const":"free-product","type":"string"}]},"value":{"description":"Discount value.","type":"string"},"active":{"description":"Database active flag (does NOT consider expiration/limit).","type":"boolean"},"effectivelyActive":{"description":"True if voucher is currently usable (active + within validity + below limit).","type":"boolean"},"isValid":{"description":"Alias of effectivelyActive — convenient flag for UI consumers.","type":"boolean"},"status":{"description":"Computed status enum.","anyOf":[{"const":"active","type":"string"},{"const":"inactive","type":"string"},{"const":"expired","type":"string"},{"const":"not-yet-valid","type":"string"},{"const":"limit-reached","type":"string"}]},"usedCount":{"description":"Number of times voucher has been used.","type":"number"},"usageLimit":{"description":"Maximum number of uses, or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"remainingUsage":{"description":"Remaining uses, or null if unlimited.","anyOf":[{"type":"number"},{"type":"null"}]},"validFrom":{"description":"Validity start date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"validTo":{"description":"Validity end date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"daysUntilExpiration":{"description":"Days remaining until expiration, or null if no expiration or already expired.","anyOf":[{"type":"number"},{"type":"null"}]},"lastUsedDate":{"description":"Last usage date.","anyOf":[{"anyOf":[{"type":"Date"},{"format":"date-time","type":"string"},{"format":"date","type":"string"},{"type":"number"}]},{"type":"null"}]},"note":{"description":"Internal note (full content).","type":"string"}}}]}}}}},"operationId":"getBffVoucherAnalyze","tags":["Voucher"],"summary":"Analyze voucher code","description":"Returns a lightweight snapshot of a voucher: whether it exists in the organisation and, if it does, its computed status (active / inactive / expired / not-yet-valid / limit-reached). Unlike /full-detail, this endpoint does NOT throw when the voucher is missing."}},"/bff/voucher/check-code-available":{"get":{"parameters":[{"description":"Voucher code to check availability for.","examples":["WELCOME10"],"schema":{"type":"string"},"in":"query","name":"code","required":true}],"responses":{"200":{"description":"Code availability result.","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"description":"True if the code is available, false if already taken.","type":"boolean"}},"required":["available"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"available":{"description":"True if the code is available, false if already taken.","type":"boolean"}},"required":["available"]}},"text/plain":{"schema":{"type":"object","properties":{"available":{"description":"True if the code is available, false if already taken.","type":"boolean"}},"required":["available"]}}}}},"operationId":"getBffVoucherCheck-code-available","tags":["Voucher"],"summary":"Check voucher code availability","description":"Checks if a voucher code is available (not already taken) within the organisation. Use this before creating a new voucher to ensure uniqueness."}},"/bff/voucher/add":{"post":{"parameters":[],"responses":{"200":{"description":"Created voucher confirmation.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"description":"The created voucher code.","type":"string"}},"required":["code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"code":{"description":"The created voucher code.","type":"string"}},"required":["code"]}},"text/plain":{"schema":{"type":"object","properties":{"code":{"description":"The created voucher code.","type":"string"}},"required":["code"]}}}}},"operationId":"postBffVoucherAdd","tags":["Voucher"],"summary":"Create new voucher","description":"Creates a new voucher with the specified parameters. The voucher code must be unique within the organisation and will be converted to uppercase.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","type","value"],"properties":{"code":{"description":"Unique voucher code (will be converted to uppercase).","examples":["SUMMER2024"],"type":"string"},"type":{"description":"Discount type: fixed, percentage, free-credit, or free-product.","examples":["percentage"],"type":"string"},"value":{"description":"Discount value (e.g., \"100\" for fixed, \"10\" for 10% percentage).","examples":["10"],"type":"string"},"usageLimit":{"description":"Maximum number of uses. Omit for unlimited.","examples":[100],"type":"number"},"note":{"description":"Internal note for administrative purposes.","examples":["Summer campaign"],"type":"string"},"active":{"description":"Whether voucher is active immediately (default: false).","type":"boolean"},"isOrderSingleton":{"description":"Limit to one use per order (default: false).","type":"boolean"},"validFrom":{"description":"ISO date string for validity start.","examples":["2024-01-01T00:00:00Z"],"type":"string"},"validTo":{"description":"ISO date string for validity end.","examples":["2024-12-31T23:59:59Z"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","type","value"],"properties":{"code":{"description":"Unique voucher code (will be converted to uppercase).","examples":["SUMMER2024"],"type":"string"},"type":{"description":"Discount type: fixed, percentage, free-credit, or free-product.","examples":["percentage"],"type":"string"},"value":{"description":"Discount value (e.g., \"100\" for fixed, \"10\" for 10% percentage).","examples":["10"],"type":"string"},"usageLimit":{"description":"Maximum number of uses. Omit for unlimited.","examples":[100],"type":"number"},"note":{"description":"Internal note for administrative purposes.","examples":["Summer campaign"],"type":"string"},"active":{"description":"Whether voucher is active immediately (default: false).","type":"boolean"},"isOrderSingleton":{"description":"Limit to one use per order (default: false).","type":"boolean"},"validFrom":{"description":"ISO date string for validity start.","examples":["2024-01-01T00:00:00Z"],"type":"string"},"validTo":{"description":"ISO date string for validity end.","examples":["2024-12-31T23:59:59Z"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code","type","value"],"properties":{"code":{"description":"Unique voucher code (will be converted to uppercase).","examples":["SUMMER2024"],"type":"string"},"type":{"description":"Discount type: fixed, percentage, free-credit, or free-product.","examples":["percentage"],"type":"string"},"value":{"description":"Discount value (e.g., \"100\" for fixed, \"10\" for 10% percentage).","examples":["10"],"type":"string"},"usageLimit":{"description":"Maximum number of uses. Omit for unlimited.","examples":[100],"type":"number"},"note":{"description":"Internal note for administrative purposes.","examples":["Summer campaign"],"type":"string"},"active":{"description":"Whether voucher is active immediately (default: false).","type":"boolean"},"isOrderSingleton":{"description":"Limit to one use per order (default: false).","type":"boolean"},"validFrom":{"description":"ISO date string for validity start.","examples":["2024-01-01T00:00:00Z"],"type":"string"},"validTo":{"description":"ISO date string for validity end.","examples":["2024-12-31T23:59:59Z"],"type":"string"}}}}}}}},"/bff/voucher/update":{"post":{"parameters":[],"responses":{"200":{"description":"Update result.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"},"code":{"description":"The updated voucher code.","type":"string"}},"required":["success","code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"},"code":{"description":"The updated voucher code.","type":"string"}},"required":["success","code"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether the update was successful.","type":"boolean"},"code":{"description":"The updated voucher code.","type":"string"}},"required":["success","code"]}}}}},"operationId":"postBffVoucherUpdate","tags":["Voucher"],"summary":"Update existing voucher","description":"Updates an existing voucher. Only provided fields will be updated; omitted fields remain unchanged. Use null to explicitly remove optional values.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Voucher code to update (identifier, cannot be changed).","examples":["SUMMER2024"],"type":"string"},"type":{"description":"New discount type.","examples":["percentage"],"type":"string"},"value":{"description":"New discount value.","examples":["15"],"type":"string"},"usageLimit":{"description":"New usage limit. Set to null to remove limit.","anyOf":[{"type":"number"},{"type":"null"}]},"note":{"description":"New internal note.","type":"string"},"active":{"description":"New active status.","type":"boolean"},"isOrderSingleton":{"description":"New singleton flag.","type":"boolean"},"hasValidityPeriod":{"description":"UI-only flag from the admin form: when false, validFrom/validTo are cleared regardless of their values.","type":"boolean"},"validFrom":{"description":"New validity start. Set to null to remove.","anyOf":[{"type":"string"},{"type":"null"}]},"validTo":{"description":"New validity end. Set to null to remove.","anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Voucher code to update (identifier, cannot be changed).","examples":["SUMMER2024"],"type":"string"},"type":{"description":"New discount type.","examples":["percentage"],"type":"string"},"value":{"description":"New discount value.","examples":["15"],"type":"string"},"usageLimit":{"description":"New usage limit. Set to null to remove limit.","anyOf":[{"type":"number"},{"type":"null"}]},"note":{"description":"New internal note.","type":"string"},"active":{"description":"New active status.","type":"boolean"},"isOrderSingleton":{"description":"New singleton flag.","type":"boolean"},"hasValidityPeriod":{"description":"UI-only flag from the admin form: when false, validFrom/validTo are cleared regardless of their values.","type":"boolean"},"validFrom":{"description":"New validity start. Set to null to remove.","anyOf":[{"type":"string"},{"type":"null"}]},"validTo":{"description":"New validity end. Set to null to remove.","anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Voucher code to update (identifier, cannot be changed).","examples":["SUMMER2024"],"type":"string"},"type":{"description":"New discount type.","examples":["percentage"],"type":"string"},"value":{"description":"New discount value.","examples":["15"],"type":"string"},"usageLimit":{"description":"New usage limit. Set to null to remove limit.","anyOf":[{"type":"number"},{"type":"null"}]},"note":{"description":"New internal note.","type":"string"},"active":{"description":"New active status.","type":"boolean"},"isOrderSingleton":{"description":"New singleton flag.","type":"boolean"},"hasValidityPeriod":{"description":"UI-only flag from the admin form: when false, validFrom/validTo are cleared regardless of their values.","type":"boolean"},"validFrom":{"description":"New validity start. Set to null to remove.","anyOf":[{"type":"string"},{"type":"null"}]},"validTo":{"description":"New validity end. Set to null to remove.","anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/voucher/deactivate":{"post":{"parameters":[],"responses":{"200":{"description":"Deactivation result.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"description":"Whether deactivation was successful.","type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"description":"Whether deactivation was successful.","type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"description":"Whether deactivation was successful.","type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffVoucherDeactivate","tags":["Voucher"],"summary":"Deactivate voucher","description":"Deactivates a voucher by setting its active flag to false. This is a soft delete - the voucher remains in the database but cannot be used. Use update endpoint with active: true to reactivate.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Voucher code to deactivate.","examples":["SUMMER2024"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Voucher code to deactivate.","examples":["SUMMER2024"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Voucher code to deactivate.","examples":["SUMMER2024"],"type":"string"}}}}}}}},"/bff/warehouse/list":{"get":{"parameters":[{"description":"\"true\" to hide inactive warehouses.","schema":{"type":"string"},"in":"query","name":"onlyActive","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","name","description","addressStreet","addressCity","addressZip","addressCountry","isDefault","isActive","allowNegativeStock","managerMemberId","stockItemCount","totalQuantity","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"description":"When true (default), outbound / transfer / adjustment may drive the cell to negative quantity.","type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stockItemCount":{"type":"number"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","name","description","addressStreet","addressCity","addressZip","addressCountry","isDefault","isActive","allowNegativeStock","managerMemberId","stockItemCount","totalQuantity","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"description":"When true (default), outbound / transfer / adjustment may drive the cell to negative quantity.","type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stockItemCount":{"type":"number"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","name","description","addressStreet","addressCity","addressZip","addressCountry","isDefault","isActive","allowNegativeStock","managerMemberId","stockItemCount","totalQuantity","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"description":"When true (default), outbound / transfer / adjustment may drive the cell to negative quantity.","type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stockItemCount":{"type":"number"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffWarehouseList","tags":["Warehouse"],"summary":"List warehouses"}},"/bff/warehouse/detail":{"get":{"parameters":[{"description":"Numeric id.","schema":{"type":"string"},"in":"query","name":"id","required":false},{"description":"String code.","schema":{"type":"string"},"in":"query","name":"code","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"description":"When true (default), outbound / transfer / adjustment may drive the cell to negative quantity.","type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stockItemCount":{"type":"number"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}},"required":["id","code","name","description","addressStreet","addressCity","addressZip","addressCountry","isDefault","isActive","allowNegativeStock","managerMemberId","stockItemCount","totalQuantity","insertedDate","updatedDate"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"description":"When true (default), outbound / transfer / adjustment may drive the cell to negative quantity.","type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stockItemCount":{"type":"number"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}},"required":["id","code","name","description","addressStreet","addressCity","addressZip","addressCountry","isDefault","isActive","allowNegativeStock","managerMemberId","stockItemCount","totalQuantity","insertedDate","updatedDate"]}},"text/plain":{"schema":{"type":"object","properties":{"id":{"type":"number"},"code":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"description":"When true (default), outbound / transfer / adjustment may drive the cell to negative quantity.","type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stockItemCount":{"type":"number"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}},"required":["id","code","name","description","addressStreet","addressCity","addressZip","addressCountry","isDefault","isActive","allowNegativeStock","managerMemberId","stockItemCount","totalQuantity","insertedDate","updatedDate"]}}}}},"operationId":"getBffWarehouseDetail","tags":["Warehouse"],"summary":"Get warehouse detail by id or code"}},"/bff/warehouse/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"},"isDefault":{"type":"boolean"}},"required":["success","id","isDefault"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"},"isDefault":{"type":"boolean"}},"required":["success","id","isDefault"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"},"isDefault":{"type":"boolean"}},"required":["success","id","isDefault"]}}}}},"operationId":"postBffWarehouseCreate","tags":["Warehouse"],"summary":"Create warehouse","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","name"],"properties":{"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"minLength":1,"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"maxLength":2,"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","name"],"properties":{"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"minLength":1,"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"maxLength":2,"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code","name"],"properties":{"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"minLength":1,"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"maxLength":2,"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"isActive":{"type":"boolean"},"allowNegativeStock":{"type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehouseUpdate","tags":["Warehouse"],"summary":"Update warehouse","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"allowNegativeStock":{"type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"allowNegativeStock":{"type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressStreet":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCity":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressZip":{"anyOf":[{"type":"string"},{"type":"null"}]},"addressCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"allowNegativeStock":{"type":"boolean"},"managerMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/set-default":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehouseSet-default","tags":["Warehouse"],"summary":"Promote a warehouse to organisation default","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"}}}}}}}},"/bff/warehouse/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehouseDelete","tags":["Warehouse"],"summary":"Delete an empty warehouse","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"}}}}}}}},"/bff/warehouse/location/list":{"get":{"parameters":[{"description":"Numeric warehouse id.","schema":{"type":"string"},"in":"query","name":"warehouseId","required":true}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","parentLocationId","code","name","note","isActive","totalQuantity","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"code":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","parentLocationId","code","name","note","isActive","totalQuantity","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"code":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","parentLocationId","code","name","note","isActive","totalQuantity","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"code":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"totalQuantity":{"type":"number"},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}}},"required":["items"]}}}}},"operationId":"getBffWarehouseLocationList","tags":["Warehouse"],"summary":"List locations in a warehouse"}},"/bff/warehouse/location/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"}},"required":["success","id"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"}},"required":["success","id"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"}},"required":["success","id"]}}}}},"operationId":"postBffWarehouseLocationCreate","tags":["Warehouse"],"summary":"Create a location","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warehouseId","code"],"properties":{"warehouseId":{"type":"number"},"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"isActive":{"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["warehouseId","code"],"properties":{"warehouseId":{"type":"number"},"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"isActive":{"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["warehouseId","code"],"properties":{"warehouseId":{"type":"number"},"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"isActive":{"type":"boolean"}}}}}}}},"/bff/warehouse/location/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehouseLocationUpdate","tags":["Warehouse"],"summary":"Update a location","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["locationId"],"properties":{"locationId":{"type":"number"},"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"isActive":{"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["locationId"],"properties":{"locationId":{"type":"number"},"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"isActive":{"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["locationId"],"properties":{"locationId":{"type":"number"},"code":{"minLength":1,"maxLength":64,"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"isActive":{"type":"boolean"}}}}}}}},"/bff/warehouse/location/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehouseLocationDelete","tags":["Warehouse"],"summary":"Delete an empty location","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["locationId"],"properties":{"locationId":{"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["locationId"],"properties":{"locationId":{"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["locationId"],"properties":{"locationId":{"type":"number"}}}}}}}},"/bff/warehouse/stock/list":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"warehouseId","required":false},{"schema":{"type":"string"},"in":"query","name":"locationId","required":false},{"schema":{"type":"string"},"in":"query","name":"productId","required":false},{"schema":{"type":"string"},"in":"query","name":"productVariantId","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false},{"schema":{"type":"string"},"in":"query","name":"onlyPositive","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"offset","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","warehouseCode","locationId","locationCode","locationName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","lowStockThreshold","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"warehouseCode":{"type":"string"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"locationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"description":"Active reservations against this cell (Tier 1 #1).","type":"number"},"available":{"description":"quantity - quantityReserved.","type":"number"},"lowStockThreshold":{"anyOf":[{"type":"number"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","warehouseCode","locationId","locationCode","locationName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","lowStockThreshold","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"warehouseCode":{"type":"string"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"locationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"description":"Active reservations against this cell (Tier 1 #1).","type":"number"},"available":{"description":"quantity - quantityReserved.","type":"number"},"lowStockThreshold":{"anyOf":[{"type":"number"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","warehouseCode","locationId","locationCode","locationName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","lowStockThreshold","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"warehouseCode":{"type":"string"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"locationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"description":"Active reservations against this cell (Tier 1 #1).","type":"number"},"available":{"description":"quantity - quantityReserved.","type":"number"},"lowStockThreshold":{"anyOf":[{"type":"number"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffWarehouseStockList","tags":["Warehouse"],"summary":"List stock items"}},"/bff/warehouse/stock/inbound":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}}}}},"operationId":"postBffWarehouseStockInbound","tags":["Warehouse"],"summary":"Inbound (naskladnění)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetWarehouseId","quantity"],"properties":{"targetWarehouseId":{"type":"number"},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["targetWarehouseId","quantity"],"properties":{"targetWarehouseId":{"type":"number"},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["targetWarehouseId","quantity"],"properties":{"targetWarehouseId":{"type":"number"},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stock/outbound":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}}}}},"operationId":"postBffWarehouseStockOutbound","tags":["Warehouse"],"summary":"Outbound (vyskladnění)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sourceWarehouseId","quantity"],"properties":{"sourceWarehouseId":{"type":"number"},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["sourceWarehouseId","quantity"],"properties":{"sourceWarehouseId":{"type":"number"},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["sourceWarehouseId","quantity"],"properties":{"sourceWarehouseId":{"type":"number"},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stock/transfer":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"sourceNewQuantity":{"type":"number"},"targetNewQuantity":{"type":"number"}},"required":["success","movementId","sourceNewQuantity","targetNewQuantity"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"sourceNewQuantity":{"type":"number"},"targetNewQuantity":{"type":"number"}},"required":["success","movementId","sourceNewQuantity","targetNewQuantity"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"sourceNewQuantity":{"type":"number"},"targetNewQuantity":{"type":"number"}},"required":["success","movementId","sourceNewQuantity","targetNewQuantity"]}}}}},"operationId":"postBffWarehouseStockTransfer","tags":["Warehouse"],"summary":"Transfer between warehouses/locations","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sourceWarehouseId","targetWarehouseId","quantity"],"properties":{"sourceWarehouseId":{"type":"number"},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetWarehouseId":{"type":"number"},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["sourceWarehouseId","targetWarehouseId","quantity"],"properties":{"sourceWarehouseId":{"type":"number"},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetWarehouseId":{"type":"number"},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["sourceWarehouseId","targetWarehouseId","quantity"],"properties":{"sourceWarehouseId":{"type":"number"},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetWarehouseId":{"type":"number"},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stock/adjust":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}},"required":["success","movementId","newQuantity"]}}}}},"operationId":"postBffWarehouseStockAdjust","tags":["Warehouse"],"summary":"Adjustment (inventory / write-off)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warehouseId","delta"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"delta":{"description":"Non-zero signed delta. Positive = correction up, negative = write-off.","type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["warehouseId","delta"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"delta":{"description":"Non-zero signed delta. Positive = correction up, negative = write-off.","type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["warehouseId","delta"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"delta":{"description":"Non-zero signed delta. Positive = correction up, negative = write-off.","type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/movement/list":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"warehouseId","required":false},{"description":"Numeric product id (alternative to productCode).","schema":{"type":"string"},"in":"query","name":"productId","required":false},{"description":"Product code (preferred over productId).","schema":{"type":"string"},"in":"query","name":"productCode","required":false},{"description":"Numeric variant id (alternative to productVariantCode).","schema":{"type":"string"},"in":"query","name":"productVariantId","required":false},{"description":"Variant code; requires productCode.","schema":{"type":"string"},"in":"query","name":"productVariantCode","required":false},{"description":"inbound | outbound | transfer | adjustment | reservation | reservation_release | reservation_commit","schema":{"type":"string"},"in":"query","name":"type","required":false},{"description":"Filter movements coupled to one order (Tier 1 reservation/commit linkage).","schema":{"type":"string"},"in":"query","name":"orderId","required":false},{"description":"ISO datetime — lower bound (inclusive).","schema":{"type":"string"},"in":"query","name":"dateFrom","required":false},{"description":"ISO datetime — upper bound (exclusive).","schema":{"type":"string"},"in":"query","name":"dateTo","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"offset","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","type","sourceWarehouseId","sourceWarehouseName","sourceLocationId","sourceLocationCode","targetWarehouseId","targetWarehouseName","targetLocationId","targetLocationCode","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","note","performedByMemberId","performedByMemberName","performedDate","orderId","orderItemId","linkedMovementId","reservationId","stocktakeSessionId","expiresAt"],"properties":{"id":{"type":"number"},"type":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"},{"const":"reservation","type":"string"},{"const":"reservation_release","type":"string"},{"const":"reservation_commit","type":"string"}]},"sourceWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"sourceWarehouseName":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"sourceLocationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetWarehouseName":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetLocationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"performedByMemberName":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedDate":{"type":"string"},"orderId":{"anyOf":[{"type":"number"},{"type":"null"}]},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"linkedMovementId":{"anyOf":[{"type":"number"},{"type":"null"}]},"reservationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stocktakeSessionId":{"anyOf":[{"type":"number"},{"type":"null"}]},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","type","sourceWarehouseId","sourceWarehouseName","sourceLocationId","sourceLocationCode","targetWarehouseId","targetWarehouseName","targetLocationId","targetLocationCode","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","note","performedByMemberId","performedByMemberName","performedDate","orderId","orderItemId","linkedMovementId","reservationId","stocktakeSessionId","expiresAt"],"properties":{"id":{"type":"number"},"type":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"},{"const":"reservation","type":"string"},{"const":"reservation_release","type":"string"},{"const":"reservation_commit","type":"string"}]},"sourceWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"sourceWarehouseName":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"sourceLocationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetWarehouseName":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetLocationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"performedByMemberName":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedDate":{"type":"string"},"orderId":{"anyOf":[{"type":"number"},{"type":"null"}]},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"linkedMovementId":{"anyOf":[{"type":"number"},{"type":"null"}]},"reservationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stocktakeSessionId":{"anyOf":[{"type":"number"},{"type":"null"}]},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","type","sourceWarehouseId","sourceWarehouseName","sourceLocationId","sourceLocationCode","targetWarehouseId","targetWarehouseName","targetLocationId","targetLocationCode","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","note","performedByMemberId","performedByMemberName","performedDate","orderId","orderItemId","linkedMovementId","reservationId","stocktakeSessionId","expiresAt"],"properties":{"id":{"type":"number"},"type":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"},{"const":"reservation","type":"string"},{"const":"reservation_release","type":"string"},{"const":"reservation_commit","type":"string"}]},"sourceWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"sourceWarehouseName":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"sourceLocationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetWarehouseName":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"targetLocationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"performedByMemberName":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedDate":{"type":"string"},"orderId":{"anyOf":[{"type":"number"},{"type":"null"}]},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"linkedMovementId":{"anyOf":[{"type":"number"},{"type":"null"}]},"reservationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"stocktakeSessionId":{"anyOf":[{"type":"number"},{"type":"null"}]},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffWarehouseMovementList","tags":["Warehouse"],"summary":"List movements (audit log)"}},"/bff/warehouse/product-stock":{"get":{"parameters":[{"description":"Numeric product id (alternative to productCode).","schema":{"type":"string"},"in":"query","name":"productId","required":false},{"description":"Human-readable product code, e.g. from /bff/product/product-detail.","schema":{"type":"string"},"in":"query","name":"productCode","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"productId":{"type":"number"},"productCode":{"type":"string"},"productName":{"type":"string"},"productSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"hasVariants":{"type":"boolean"},"totalQuantity":{"type":"number"},"totalReserved":{"type":"number"},"totalAvailable":{"type":"number"},"perWarehouse":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseCode","warehouseName","quantity","quantityReserved","available","isDefault"],"properties":{"warehouseId":{"type":"number"},"warehouseCode":{"type":"string"},"warehouseName":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"isDefault":{"type":"boolean"}}}},"variants":{"type":"array","items":{"type":"object","required":["variantId","variantCode","variantName","totalQuantity","totalReserved","totalAvailable","perWarehouse"],"properties":{"variantId":{"type":"number"},"variantCode":{"type":"string"},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"totalQuantity":{"type":"number"},"totalReserved":{"type":"number"},"totalAvailable":{"type":"number"},"perWarehouse":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseCode","warehouseName","quantity","isDefault"],"properties":{"warehouseId":{"type":"number"},"warehouseCode":{"type":"string"},"warehouseName":{"type":"string"},"quantity":{"type":"number"},"isDefault":{"type":"boolean"}}}}}}},"lowStockWarnings":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseName","variantId","variantName","quantity","threshold"],"properties":{"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"variantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"threshold":{"type":"number"}}}}},"required":["productId","productCode","productName","productSku","hasVariants","totalQuantity","totalReserved","totalAvailable","perWarehouse","variants","lowStockWarnings"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"productId":{"type":"number"},"productCode":{"type":"string"},"productName":{"type":"string"},"productSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"hasVariants":{"type":"boolean"},"totalQuantity":{"type":"number"},"totalReserved":{"type":"number"},"totalAvailable":{"type":"number"},"perWarehouse":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseCode","warehouseName","quantity","quantityReserved","available","isDefault"],"properties":{"warehouseId":{"type":"number"},"warehouseCode":{"type":"string"},"warehouseName":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"isDefault":{"type":"boolean"}}}},"variants":{"type":"array","items":{"type":"object","required":["variantId","variantCode","variantName","totalQuantity","totalReserved","totalAvailable","perWarehouse"],"properties":{"variantId":{"type":"number"},"variantCode":{"type":"string"},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"totalQuantity":{"type":"number"},"totalReserved":{"type":"number"},"totalAvailable":{"type":"number"},"perWarehouse":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseCode","warehouseName","quantity","isDefault"],"properties":{"warehouseId":{"type":"number"},"warehouseCode":{"type":"string"},"warehouseName":{"type":"string"},"quantity":{"type":"number"},"isDefault":{"type":"boolean"}}}}}}},"lowStockWarnings":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseName","variantId","variantName","quantity","threshold"],"properties":{"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"variantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"threshold":{"type":"number"}}}}},"required":["productId","productCode","productName","productSku","hasVariants","totalQuantity","totalReserved","totalAvailable","perWarehouse","variants","lowStockWarnings"]}},"text/plain":{"schema":{"type":"object","properties":{"productId":{"type":"number"},"productCode":{"type":"string"},"productName":{"type":"string"},"productSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"hasVariants":{"type":"boolean"},"totalQuantity":{"type":"number"},"totalReserved":{"type":"number"},"totalAvailable":{"type":"number"},"perWarehouse":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseCode","warehouseName","quantity","quantityReserved","available","isDefault"],"properties":{"warehouseId":{"type":"number"},"warehouseCode":{"type":"string"},"warehouseName":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"isDefault":{"type":"boolean"}}}},"variants":{"type":"array","items":{"type":"object","required":["variantId","variantCode","variantName","totalQuantity","totalReserved","totalAvailable","perWarehouse"],"properties":{"variantId":{"type":"number"},"variantCode":{"type":"string"},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"totalQuantity":{"type":"number"},"totalReserved":{"type":"number"},"totalAvailable":{"type":"number"},"perWarehouse":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseCode","warehouseName","quantity","isDefault"],"properties":{"warehouseId":{"type":"number"},"warehouseCode":{"type":"string"},"warehouseName":{"type":"string"},"quantity":{"type":"number"},"isDefault":{"type":"boolean"}}}}}}},"lowStockWarnings":{"type":"array","items":{"type":"object","required":["warehouseId","warehouseName","variantId","variantName","quantity","threshold"],"properties":{"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"variantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"threshold":{"type":"number"}}}}},"required":["productId","productCode","productName","productSku","hasVariants","totalQuantity","totalReserved","totalAvailable","perWarehouse","variants","lowStockWarnings"]}}}}},"operationId":"getBffWarehouseProduct-stock","tags":["Warehouse"],"summary":"Aggregate stock breakdown for one product","description":"Returns total + per-warehouse + per-variant stock for a product. The Product detail \"Stock\" tab uses this as a single round-trip."}},"/bff/warehouse/alerts/low-stock":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["organisationId","organisationName","stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","threshold","fromPolicy","reorderPoint"],"properties":{"organisationId":{"type":"number"},"organisationName":{"type":"string"},"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"threshold":{"type":"number"},"fromPolicy":{"type":"boolean"},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["organisationId","organisationName","stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","threshold","fromPolicy","reorderPoint"],"properties":{"organisationId":{"type":"number"},"organisationName":{"type":"string"},"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"threshold":{"type":"number"},"fromPolicy":{"type":"boolean"},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["organisationId","organisationName","stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","threshold","fromPolicy","reorderPoint"],"properties":{"organisationId":{"type":"number"},"organisationName":{"type":"string"},"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"threshold":{"type":"number"},"fromPolicy":{"type":"boolean"},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffWarehouseAlertsLow-stock","tags":["Warehouse"],"summary":"List stock cells under the configured low-stock threshold","description":"Same data the cron daemon scans. Ordered by severity (how far below the threshold). The dashboard surfaces the count as a notification badge; the warehouse list page renders the full list as a dedicated tab."}},"/bff/warehouse/reports/dead-stock":{"get":{"parameters":[{"description":"Idle days that disqualify the item from being live stock. Default 90.","schema":{"type":"string"},"in":"query","name":"thresholdDays","required":false},{"schema":{"type":"string"},"in":"query","name":"warehouseId","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","lastMovementDate","daysSinceLastMovement"],"properties":{"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"lastMovementDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"daysSinceLastMovement":{"type":"number"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","lastMovementDate","daysSinceLastMovement"],"properties":{"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"lastMovementDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"daysSinceLastMovement":{"type":"number"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","lastMovementDate","daysSinceLastMovement"],"properties":{"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"lastMovementDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"daysSinceLastMovement":{"type":"number"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffWarehouseReportsDead-stock","tags":["Warehouse"],"summary":"List stock with no movement for N days (\"dead stock\")","description":"Surfaces capital tied up in inventory that has not moved recently. The default threshold of 90 days matches the e-commerce industry norm for fast-moving goods. Sortable by `daysSinceLastMovement` to show the worst offenders first."}},"/bff/warehouse/reservation/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"reservationId":{"type":"number"},"movementId":{"type":"number"},"newQuantity":{"type":"number"},"newReserved":{"type":"number"},"available":{"type":"number"},"deduped":{"type":"boolean"}},"required":["success","reservationId","movementId","newQuantity","newReserved","available","deduped"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"reservationId":{"type":"number"},"movementId":{"type":"number"},"newQuantity":{"type":"number"},"newReserved":{"type":"number"},"available":{"type":"number"},"deduped":{"type":"boolean"}},"required":["success","reservationId","movementId","newQuantity","newReserved","available","deduped"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"reservationId":{"type":"number"},"movementId":{"type":"number"},"newQuantity":{"type":"number"},"newReserved":{"type":"number"},"available":{"type":"number"},"deduped":{"type":"boolean"}},"required":["success","reservationId","movementId","newQuantity","newReserved","available","deduped"]}}}}},"operationId":"postBffWarehouseReservationCreate","tags":["Warehouse"],"summary":"Reserve stock (Tier 1 #1)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warehouseId","quantity"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"mode":{"anyOf":[{"const":"soft","type":"string"},{"const":"hard","type":"string"}]},"orderId":{"anyOf":[{"type":"number"},{"type":"null"}]},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"externalKey":{"anyOf":[{"maxLength":120,"type":"string"},{"type":"null"}]},"expiresAt":{"anyOf":[{"description":"ISO datetime; required for `soft` reservations to be auto-released.","type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["warehouseId","quantity"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"mode":{"anyOf":[{"const":"soft","type":"string"},{"const":"hard","type":"string"}]},"orderId":{"anyOf":[{"type":"number"},{"type":"null"}]},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"externalKey":{"anyOf":[{"maxLength":120,"type":"string"},{"type":"null"}]},"expiresAt":{"anyOf":[{"description":"ISO datetime; required for `soft` reservations to be auto-released.","type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["warehouseId","quantity"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"quantity":{"minimum":1,"type":"number"},"mode":{"anyOf":[{"const":"soft","type":"string"},{"const":"hard","type":"string"}]},"orderId":{"anyOf":[{"type":"number"},{"type":"null"}]},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"externalKey":{"anyOf":[{"maxLength":120,"type":"string"},{"type":"null"}]},"expiresAt":{"anyOf":[{"description":"ISO datetime; required for `soft` reservations to be auto-released.","type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/reservation/release":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"released":{"type":"array","items":{"type":"object","required":["reservationId","warehouseId","productId","productVariantId","virtualItemSku","quantity","newReserved","newQuantity","movementId"],"properties":{"reservationId":{"type":"number"},"warehouseId":{"type":"number"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"newReserved":{"type":"number"},"newQuantity":{"type":"number"},"movementId":{"type":"number"}}}},"alreadyResolved":{"type":"boolean"}},"required":["success","released","alreadyResolved"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"released":{"type":"array","items":{"type":"object","required":["reservationId","warehouseId","productId","productVariantId","virtualItemSku","quantity","newReserved","newQuantity","movementId"],"properties":{"reservationId":{"type":"number"},"warehouseId":{"type":"number"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"newReserved":{"type":"number"},"newQuantity":{"type":"number"},"movementId":{"type":"number"}}}},"alreadyResolved":{"type":"boolean"}},"required":["success","released","alreadyResolved"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"released":{"type":"array","items":{"type":"object","required":["reservationId","warehouseId","productId","productVariantId","virtualItemSku","quantity","newReserved","newQuantity","movementId"],"properties":{"reservationId":{"type":"number"},"warehouseId":{"type":"number"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"newReserved":{"type":"number"},"newQuantity":{"type":"number"},"movementId":{"type":"number"}}}},"alreadyResolved":{"type":"boolean"}},"required":["success","released","alreadyResolved"]}}}}},"operationId":"postBffWarehouseReservationRelease","tags":["Warehouse"],"summary":"Release reservation(s) (Tier 1 #1)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reservationId":{"type":"number"},"orderId":{"type":"number"},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"externalKey":{"maxLength":120,"type":"string"},"reason":{"anyOf":[{"const":"storno","type":"string"},{"const":"expired","type":"string"},{"const":"manual","type":"string"},{"const":"cart_abandoned","type":"string"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"reservationId":{"type":"number"},"orderId":{"type":"number"},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"externalKey":{"maxLength":120,"type":"string"},"reason":{"anyOf":[{"const":"storno","type":"string"},{"const":"expired","type":"string"},{"const":"manual","type":"string"},{"const":"cart_abandoned","type":"string"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","properties":{"reservationId":{"type":"number"},"orderId":{"type":"number"},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"externalKey":{"maxLength":120,"type":"string"},"reason":{"anyOf":[{"const":"storno","type":"string"},{"const":"expired","type":"string"},{"const":"manual","type":"string"},{"const":"cart_abandoned","type":"string"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/reservation/commit":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"committed":{"type":"array","items":{"type":"object","required":["reservationId","warehouseId","productId","productVariantId","virtualItemSku","quantity","newQuantity","newReserved","movementId"],"properties":{"reservationId":{"type":"number"},"warehouseId":{"type":"number"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"newQuantity":{"type":"number"},"newReserved":{"type":"number"},"movementId":{"type":"number"}}}},"alreadyResolved":{"type":"boolean"}},"required":["success","committed","alreadyResolved"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"committed":{"type":"array","items":{"type":"object","required":["reservationId","warehouseId","productId","productVariantId","virtualItemSku","quantity","newQuantity","newReserved","movementId"],"properties":{"reservationId":{"type":"number"},"warehouseId":{"type":"number"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"newQuantity":{"type":"number"},"newReserved":{"type":"number"},"movementId":{"type":"number"}}}},"alreadyResolved":{"type":"boolean"}},"required":["success","committed","alreadyResolved"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"committed":{"type":"array","items":{"type":"object","required":["reservationId","warehouseId","productId","productVariantId","virtualItemSku","quantity","newQuantity","newReserved","movementId"],"properties":{"reservationId":{"type":"number"},"warehouseId":{"type":"number"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"newQuantity":{"type":"number"},"newReserved":{"type":"number"},"movementId":{"type":"number"}}}},"alreadyResolved":{"type":"boolean"}},"required":["success","committed","alreadyResolved"]}}}}},"operationId":"postBffWarehouseReservationCommit","tags":["Warehouse"],"summary":"Commit reservation(s) to outbound (Tier 1 #1)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reservationId":{"type":"number"},"quantity":{"anyOf":[{"minimum":1,"type":"number"},{"type":"null"}]},"orderId":{"type":"number"},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","properties":{"reservationId":{"type":"number"},"quantity":{"anyOf":[{"minimum":1,"type":"number"},{"type":"null"}]},"orderId":{"type":"number"},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","properties":{"reservationId":{"type":"number"},"quantity":{"anyOf":[{"minimum":1,"type":"number"},{"type":"null"}]},"orderId":{"type":"number"},"orderItemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"idempotencyKey":{"anyOf":[{"maxLength":80,"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stocktake/list":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"warehouseId","required":false},{"description":"draft | in_progress | review | approved | cancelled","schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"offset","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","locationId","locationCode","locationName","name","status","lockScope","filterNote","note","startedByMemberId","startedByMemberName","startedDate","submittedDate","approvedDate","cancelledDate","insertedDate","updatedDate","itemCount","countedItemCount","discrepancyCount","totalAbsDiscrepancy"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"locationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"},"status":{"type":"string"},"lockScope":{"type":"boolean"},"filterNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"startedByMemberName":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"submittedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"approvedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"cancelledDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"},"itemCount":{"type":"number"},"countedItemCount":{"type":"number"},"discrepancyCount":{"type":"number"},"totalAbsDiscrepancy":{"type":"number"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","locationId","locationCode","locationName","name","status","lockScope","filterNote","note","startedByMemberId","startedByMemberName","startedDate","submittedDate","approvedDate","cancelledDate","insertedDate","updatedDate","itemCount","countedItemCount","discrepancyCount","totalAbsDiscrepancy"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"locationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"},"status":{"type":"string"},"lockScope":{"type":"boolean"},"filterNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"startedByMemberName":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"submittedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"approvedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"cancelledDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"},"itemCount":{"type":"number"},"countedItemCount":{"type":"number"},"discrepancyCount":{"type":"number"},"totalAbsDiscrepancy":{"type":"number"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","locationId","locationCode","locationName","name","status","lockScope","filterNote","note","startedByMemberId","startedByMemberName","startedDate","submittedDate","approvedDate","cancelledDate","insertedDate","updatedDate","itemCount","countedItemCount","discrepancyCount","totalAbsDiscrepancy"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"locationCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"locationName":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"},"status":{"type":"string"},"lockScope":{"type":"boolean"},"filterNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"startedByMemberName":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"submittedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"approvedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"cancelledDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"},"itemCount":{"type":"number"},"countedItemCount":{"type":"number"},"discrepancyCount":{"type":"number"},"totalAbsDiscrepancy":{"type":"number"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffWarehouseStocktakeList","tags":["Warehouse"],"summary":"List stocktake sessions (Tier 1 #2)"}},"/bff/warehouse/stocktake/detail":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"sessionId","required":true},{"schema":{"type":"string"},"in":"query","name":"onlyDiscrepancies","required":false},{"schema":{"type":"string"},"in":"query","name":"onlyPending","required":false}],"operationId":"getBffWarehouseStocktakeDetail","tags":["Warehouse"],"summary":"Stocktake session detail (Tier 1 #2)","responses":{"200":{}}}},"/bff/warehouse/stocktake/create":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sessionId":{"type":"number"},"itemCount":{"type":"number"}},"required":["success","sessionId","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sessionId":{"type":"number"},"itemCount":{"type":"number"}},"required":["success","sessionId","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sessionId":{"type":"number"},"itemCount":{"type":"number"}},"required":["success","sessionId","itemCount"]}}}}},"operationId":"postBffWarehouseStocktakeCreate","tags":["Warehouse"],"summary":"Create stocktake session (Tier 1 #2)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warehouseId","name"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"name":{"minLength":1,"type":"string"},"filterNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"lockScope":{"type":"boolean"},"snapshot":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["warehouseId","name"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"name":{"minLength":1,"type":"string"},"filterNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"lockScope":{"type":"boolean"},"snapshot":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["warehouseId","name"],"properties":{"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"name":{"minLength":1,"type":"string"},"filterNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"lockScope":{"type":"boolean"},"snapshot":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stocktake/start":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehouseStocktakeStart","tags":["Warehouse"],"summary":"Start stocktake session (Tier 1 #2)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"startedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stocktake/count":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"itemId":{"type":"number"},"expectedQuantity":{"type":"number"},"countedQuantity":{"type":"number"},"discrepancy":{"type":"number"}},"required":["success","itemId","expectedQuantity","countedQuantity","discrepancy"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"itemId":{"type":"number"},"expectedQuantity":{"type":"number"},"countedQuantity":{"type":"number"},"discrepancy":{"type":"number"}},"required":["success","itemId","expectedQuantity","countedQuantity","discrepancy"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"itemId":{"type":"number"},"expectedQuantity":{"type":"number"},"countedQuantity":{"type":"number"},"discrepancy":{"type":"number"}},"required":["success","itemId","expectedQuantity","countedQuantity","discrepancy"]}}}}},"operationId":"postBffWarehouseStocktakeCount","tags":["Warehouse"],"summary":"Record counted quantity (Tier 1 #2)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId","countedQuantity"],"properties":{"sessionId":{"type":"number"},"itemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"countedQuantity":{"minimum":0,"type":"number"},"discrepancyReason":{"anyOf":[{"maxLength":40,"type":"string"},{"type":"null"}]},"countedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["sessionId","countedQuantity"],"properties":{"sessionId":{"type":"number"},"itemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"countedQuantity":{"minimum":0,"type":"number"},"discrepancyReason":{"anyOf":[{"maxLength":40,"type":"string"},{"type":"null"}]},"countedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["sessionId","countedQuantity"],"properties":{"sessionId":{"type":"number"},"itemId":{"anyOf":[{"type":"number"},{"type":"null"}]},"warehouseId":{"type":"number"},"locationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"countedQuantity":{"minimum":0,"type":"number"},"discrepancyReason":{"anyOf":[{"maxLength":40,"type":"string"},{"type":"null"}]},"countedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stocktake/submit":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehouseStocktakeSubmit","tags":["Warehouse"],"summary":"Submit stocktake for review (Tier 1 #2)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"submittedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"submittedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"submittedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stocktake/approve":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sessionId":{"type":"number"},"approved":{"type":"array","items":{"type":"object","required":["itemId","warehouseId","expectedQuantity","countedQuantity","delta","movementId","newQuantity"],"properties":{"itemId":{"type":"number"},"warehouseId":{"type":"number"},"expectedQuantity":{"type":"number"},"countedQuantity":{"type":"number"},"delta":{"type":"number"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}}}},"skipped":{"type":"number"},"noDelta":{"type":"number"}},"required":["success","sessionId","approved","skipped","noDelta"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sessionId":{"type":"number"},"approved":{"type":"array","items":{"type":"object","required":["itemId","warehouseId","expectedQuantity","countedQuantity","delta","movementId","newQuantity"],"properties":{"itemId":{"type":"number"},"warehouseId":{"type":"number"},"expectedQuantity":{"type":"number"},"countedQuantity":{"type":"number"},"delta":{"type":"number"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}}}},"skipped":{"type":"number"},"noDelta":{"type":"number"}},"required":["success","sessionId","approved","skipped","noDelta"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sessionId":{"type":"number"},"approved":{"type":"array","items":{"type":"object","required":["itemId","warehouseId","expectedQuantity","countedQuantity","delta","movementId","newQuantity"],"properties":{"itemId":{"type":"number"},"warehouseId":{"type":"number"},"expectedQuantity":{"type":"number"},"countedQuantity":{"type":"number"},"delta":{"type":"number"},"movementId":{"type":"number"},"newQuantity":{"type":"number"}}}},"skipped":{"type":"number"},"noDelta":{"type":"number"}},"required":["success","sessionId","approved","skipped","noDelta"]}}}}},"operationId":"postBffWarehouseStocktakeApprove","tags":["Warehouse"],"summary":"Approve stocktake — produces adjustment movements (Tier 1 #2)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"approvedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"approvedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"approvedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/stocktake/cancel":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehouseStocktakeCancel","tags":["Warehouse"],"summary":"Cancel stocktake session (Tier 1 #2)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"cancelledByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"cancelledByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"number"},"cancelledByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/warehouse/scanner/resolve":{"post":{"parameters":[],"operationId":"postBffWarehouseScannerResolve","tags":["Warehouse"],"summary":"Resolve a scanned code to one or more entities (Tier 1 #3)","description":"Returns every match across warehouse / location / variant / product / virtual SKU and a `best` pick from the caller-supplied preference order.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"minLength":1,"description":"Raw scanner string (EAN / SKU / product / location / warehouse code).","type":"string"},"preference":{"type":"array","items":{"anyOf":[{"const":"warehouse","type":"string"},{"const":"location","type":"string"},{"const":"variant","type":"string"},{"const":"product","type":"string"},{"const":"virtual","type":"string"}]}}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"minLength":1,"description":"Raw scanner string (EAN / SKU / product / location / warehouse code).","type":"string"},"preference":{"type":"array","items":{"anyOf":[{"const":"warehouse","type":"string"},{"const":"location","type":"string"},{"const":"variant","type":"string"},{"const":"product","type":"string"},{"const":"virtual","type":"string"}]}}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"minLength":1,"description":"Raw scanner string (EAN / SKU / product / location / warehouse code).","type":"string"},"preference":{"type":"array","items":{"anyOf":[{"const":"warehouse","type":"string"},{"const":"location","type":"string"},{"const":"variant","type":"string"},{"const":"product","type":"string"},{"const":"virtual","type":"string"}]}}}}}}},"responses":{"200":{}}}},"/bff/warehouse/scanner/quick-op":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"kind":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"}]},"newSourceQuantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"newTargetQuantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedSourceWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedSourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedTargetWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedTargetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"replayed":{"type":"boolean"}},"required":["success","movementId","kind","newSourceQuantity","newTargetQuantity","resolvedSourceWarehouseId","resolvedSourceLocationId","resolvedTargetWarehouseId","resolvedTargetLocationId","replayed"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"kind":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"}]},"newSourceQuantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"newTargetQuantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedSourceWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedSourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedTargetWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedTargetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"replayed":{"type":"boolean"}},"required":["success","movementId","kind","newSourceQuantity","newTargetQuantity","resolvedSourceWarehouseId","resolvedSourceLocationId","resolvedTargetWarehouseId","resolvedTargetLocationId","replayed"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"movementId":{"type":"number"},"kind":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"}]},"newSourceQuantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"newTargetQuantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedSourceWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedSourceLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedTargetWarehouseId":{"anyOf":[{"type":"number"},{"type":"null"}]},"resolvedTargetLocationId":{"anyOf":[{"type":"number"},{"type":"null"}]},"replayed":{"type":"boolean"}},"required":["success","movementId","kind","newSourceQuantity","newTargetQuantity","resolvedSourceWarehouseId","resolvedSourceLocationId","resolvedTargetWarehouseId","resolvedTargetLocationId","replayed"]}}}}},"operationId":"postBffWarehouseScannerQuick-op","tags":["Warehouse"],"summary":"Mobile/scanner quick stock operation with idempotent offline-queue support (Tier 1 #3)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind","quantity"],"properties":{"kind":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"}]},"clientOperationId":{"anyOf":[{"maxLength":80,"description":"Idempotency token; format suggestion `{deviceId}:{counter}`.","type":"string"},{"type":"null"}]},"itemCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["kind","quantity"],"properties":{"kind":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"}]},"clientOperationId":{"anyOf":[{"maxLength":80,"description":"Idempotency token; format suggestion `{deviceId}:{counter}`.","type":"string"},{"type":"null"}]},"itemCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["kind","quantity"],"properties":{"kind":{"anyOf":[{"const":"inbound","type":"string"},{"const":"outbound","type":"string"},{"const":"transfer","type":"string"},{"const":"adjustment","type":"string"}]},"clientOperationId":{"anyOf":[{"maxLength":80,"description":"Idempotency token; format suggestion `{deviceId}:{counter}`.","type":"string"},{"type":"null"}]},"itemCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"targetCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"type":"number"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"performedByMemberId":{"anyOf":[{"type":"number"},{"type":"null"}]}}}}}}}},"/bff/warehouse/policy/list":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"warehouseId","required":false},{"schema":{"type":"string"},"in":"query","name":"productId","required":false},{"schema":{"type":"string"},"in":"query","name":"productVariantId","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"offset","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","minThreshold","reorderPoint","maxCapacity","allowBackorder","notifyChannels","isActive","note","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"minThreshold":{"anyOf":[{"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]},"maxCapacity":{"anyOf":[{"type":"number"},{"type":"null"}]},"allowBackorder":{"type":"boolean"},"notifyChannels":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","minThreshold","reorderPoint","maxCapacity","allowBackorder","notifyChannels","isActive","note","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"minThreshold":{"anyOf":[{"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]},"maxCapacity":{"anyOf":[{"type":"number"},{"type":"null"}]},"allowBackorder":{"type":"boolean"},"notifyChannels":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","minThreshold","reorderPoint","maxCapacity","allowBackorder","notifyChannels","isActive","note","insertedDate","updatedDate"],"properties":{"id":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"minThreshold":{"anyOf":[{"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]},"maxCapacity":{"anyOf":[{"type":"number"},{"type":"null"}]},"allowBackorder":{"type":"boolean"},"notifyChannels":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"insertedDate":{"type":"string"},"updatedDate":{"type":"string"}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffWarehousePolicyList","tags":["Warehouse"],"summary":"List stock policies (Tier 1 #4)"}},"/bff/warehouse/policy/upsert":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"},"created":{"type":"boolean"}},"required":["success","id","created"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"},"created":{"type":"boolean"}},"required":["success","id","created"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"number"},"created":{"type":"boolean"}},"required":["success","id","created"]}}}}},"operationId":"postBffWarehousePolicyUpsert","tags":["Warehouse"],"summary":"Create or update a stock policy (Tier 1 #4)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"minThreshold":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"maxCapacity":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"allowBackorder":{"type":"boolean"},"notifyChannels":{"anyOf":[{"maxLength":120,"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"minThreshold":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"maxCapacity":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"allowBackorder":{"type":"boolean"},"notifyChannels":{"anyOf":[{"maxLength":120,"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["warehouseId"],"properties":{"warehouseId":{"type":"number"},"productCode":{"description":"Human-readable product code (mutually exclusive with virtualItemSku).","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"productVariantCode":{"description":"Variant code, requires productCode.","anyOf":[{"maxLength":64,"type":"string"},{"type":"null"}]},"virtualItemSku":{"description":"Free-form virtual SKU for non-catalogue items.","anyOf":[{"maxLength":100,"type":"string"},{"type":"null"}]},"minThreshold":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"maxCapacity":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}]},"allowBackorder":{"type":"boolean"},"notifyChannels":{"anyOf":[{"maxLength":120,"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}}}}}}}},"/bff/warehouse/policy/delete":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWarehousePolicyDelete","tags":["Warehouse"],"summary":"Delete a stock policy (Tier 1 #4)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["policyId"],"properties":{"policyId":{"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["policyId"],"properties":{"policyId":{"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["policyId"],"properties":{"policyId":{"type":"number"}}}}}}}},"/bff/warehouse/dashboard/health":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"deadStockDays","required":false},{"schema":{"type":"string"},"in":"query","name":"shrinkageWindowDays","required":false},{"schema":{"type":"string"},"in":"query","name":"topMoversLimit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"generatedAt":{"type":"string"},"totalActiveCells":{"type":"number"},"lowStockCount":{"type":"number"},"reorderPointBreachCount":{"type":"number"},"negativeAvailableCount":{"type":"number"},"deadStockValue":{"type":"number"},"deadStockCurrency":{"anyOf":[{"type":"string"},{"type":"null"}]},"shrinkageRate":{"type":"number"},"totalReservedUnits":{"type":"number"},"activeSoftReservations":{"type":"number"},"topMovers":{"type":"array","items":{"type":"object","required":["productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","unitsMoved"],"properties":{"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"unitsMoved":{"type":"number"}}}}},"required":["generatedAt","totalActiveCells","lowStockCount","reorderPointBreachCount","negativeAvailableCount","deadStockValue","deadStockCurrency","shrinkageRate","totalReservedUnits","activeSoftReservations","topMovers"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"generatedAt":{"type":"string"},"totalActiveCells":{"type":"number"},"lowStockCount":{"type":"number"},"reorderPointBreachCount":{"type":"number"},"negativeAvailableCount":{"type":"number"},"deadStockValue":{"type":"number"},"deadStockCurrency":{"anyOf":[{"type":"string"},{"type":"null"}]},"shrinkageRate":{"type":"number"},"totalReservedUnits":{"type":"number"},"activeSoftReservations":{"type":"number"},"topMovers":{"type":"array","items":{"type":"object","required":["productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","unitsMoved"],"properties":{"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"unitsMoved":{"type":"number"}}}}},"required":["generatedAt","totalActiveCells","lowStockCount","reorderPointBreachCount","negativeAvailableCount","deadStockValue","deadStockCurrency","shrinkageRate","totalReservedUnits","activeSoftReservations","topMovers"]}},"text/plain":{"schema":{"type":"object","properties":{"generatedAt":{"type":"string"},"totalActiveCells":{"type":"number"},"lowStockCount":{"type":"number"},"reorderPointBreachCount":{"type":"number"},"negativeAvailableCount":{"type":"number"},"deadStockValue":{"type":"number"},"deadStockCurrency":{"anyOf":[{"type":"string"},{"type":"null"}]},"shrinkageRate":{"type":"number"},"totalReservedUnits":{"type":"number"},"activeSoftReservations":{"type":"number"},"topMovers":{"type":"array","items":{"type":"object","required":["productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","unitsMoved"],"properties":{"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"unitsMoved":{"type":"number"}}}}},"required":["generatedAt","totalActiveCells","lowStockCount","reorderPointBreachCount","negativeAvailableCount","deadStockValue","deadStockCurrency","shrinkageRate","totalReservedUnits","activeSoftReservations","topMovers"]}}}}},"operationId":"getBffWarehouseDashboardHealth","tags":["Warehouse"],"summary":"Stock health dashboard (Tier 1 #4)","description":"One round-trip for the admin dashboard widget. Returns alert counts, dead-stock value, shrinkage rate, top movers, and reservation totals."}},"/bff/warehouse/reports/days-of-stock":{"get":{"parameters":[{"description":"Moving-average window in days. Default 30.","schema":{"type":"string"},"in":"query","name":"windowDays","required":false},{"schema":{"type":"string"},"in":"query","name":"warehouseId","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","avgDailyConsumption","daysOfStock","reorderPoint"],"properties":{"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"avgDailyConsumption":{"type":"number"},"daysOfStock":{"anyOf":[{"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","avgDailyConsumption","daysOfStock","reorderPoint"],"properties":{"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"avgDailyConsumption":{"type":"number"},"daysOfStock":{"anyOf":[{"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["stockItemId","warehouseId","warehouseName","productId","productCode","productName","productVariantId","variantCode","variantName","virtualItemSku","itemLabel","quantity","quantityReserved","available","avgDailyConsumption","daysOfStock","reorderPoint"],"properties":{"stockItemId":{"type":"number"},"warehouseId":{"type":"number"},"warehouseName":{"type":"string"},"productId":{"anyOf":[{"type":"number"},{"type":"null"}]},"productCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"productName":{"anyOf":[{"type":"string"},{"type":"null"}]},"productVariantId":{"anyOf":[{"type":"number"},{"type":"null"}]},"variantCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"variantName":{"anyOf":[{"type":"string"},{"type":"null"}]},"virtualItemSku":{"anyOf":[{"type":"string"},{"type":"null"}]},"itemLabel":{"type":"string"},"quantity":{"type":"number"},"quantityReserved":{"type":"number"},"available":{"type":"number"},"avgDailyConsumption":{"type":"number"},"daysOfStock":{"anyOf":[{"type":"number"},{"type":"null"}]},"reorderPoint":{"anyOf":[{"type":"number"},{"type":"null"}]}}}},"itemCount":{"type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffWarehouseReportsDays-of-stock","tags":["Warehouse"],"summary":"Days-of-stock report (Tier 1 #4)","description":"Per-cell \"how many days does current available last given the moving-average consumption\"."}},"/bff/workflow/status":{"get":{"parameters":[{"description":"Optional order group code to filter statuses by group.","examples":["default"],"schema":{"type":"string"},"in":"query","name":"groupCode","required":false}],"operationId":"getBffWorkflowStatus","tags":["Workflow"],"summary":"Get workflow status list","description":"Returns all order workflow statuses for the organisation with their rules, colors, redirect logic and linked email templates. Optionally filtered by order group.","responses":{"200":{}}}},"/bff/workflow/add-status":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowAdd-status","tags":["Workflow"],"summary":"Add workflow status","description":"Creates a new order workflow status at the end of the specified phase group.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label","code","color","type"],"properties":{"label":{"description":"Display label for the status.","examples":["Odesláno"],"type":"string"},"code":{"description":"Unique status code (slug). If empty, generated from label.","examples":["odeslano"],"type":"string"},"color":{"description":"Hex color for the status badge.","examples":["#22c55e"],"type":"string"},"type":{"description":"Workflow phase: new, processing, storno or done.","examples":["processing"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["label","code","color","type"],"properties":{"label":{"description":"Display label for the status.","examples":["Odesláno"],"type":"string"},"code":{"description":"Unique status code (slug). If empty, generated from label.","examples":["odeslano"],"type":"string"},"color":{"description":"Hex color for the status badge.","examples":["#22c55e"],"type":"string"},"type":{"description":"Workflow phase: new, processing, storno or done.","examples":["processing"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["label","code","color","type"],"properties":{"label":{"description":"Display label for the status.","examples":["Odesláno"],"type":"string"},"code":{"description":"Unique status code (slug). If empty, generated from label.","examples":["odeslano"],"type":"string"},"color":{"description":"Hex color for the status badge.","examples":["#22c55e"],"type":"string"},"type":{"description":"Workflow phase: new, processing, storno or done.","examples":["processing"],"type":"string"}}}}}}}},"/bff/workflow/update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowUpdate","tags":["Workflow"],"summary":"Update workflow status","description":"Updates an existing workflow status including its automation rules (auto-pay, invoice, redirect).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label","code","color","markAsPaid","createInvoice","createReceipt"],"properties":{"label":{"description":"Display label for the status.","examples":["Odesláno"],"type":"string"},"code":{"description":"Status code to update (identifies the status).","examples":["odeslano"],"type":"string"},"internalName":{"description":"Internal name visible only to staff.","type":"string"},"publicLabel":{"description":"Public-facing label shown to customers.","type":"string"},"color":{"description":"Hex color for the status badge.","examples":["#22c55e"],"type":"string"},"markAsPaid":{"description":"Automatically mark order as paid when entering this status.","type":"boolean"},"createInvoice":{"description":"Automatically create invoice when entering this status.","type":"boolean"},"createReceipt":{"description":"Automatically create receipt when entering this status.","type":"boolean"},"redirectToCode":{"description":"Status code to auto-redirect to after timeout.","examples":["done"],"type":"string"},"redirectTimeout":{"description":"Relative time before redirect (e.g. \"2h\", \"1d\").","examples":["2h"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["label","code","color","markAsPaid","createInvoice","createReceipt"],"properties":{"label":{"description":"Display label for the status.","examples":["Odesláno"],"type":"string"},"code":{"description":"Status code to update (identifies the status).","examples":["odeslano"],"type":"string"},"internalName":{"description":"Internal name visible only to staff.","type":"string"},"publicLabel":{"description":"Public-facing label shown to customers.","type":"string"},"color":{"description":"Hex color for the status badge.","examples":["#22c55e"],"type":"string"},"markAsPaid":{"description":"Automatically mark order as paid when entering this status.","type":"boolean"},"createInvoice":{"description":"Automatically create invoice when entering this status.","type":"boolean"},"createReceipt":{"description":"Automatically create receipt when entering this status.","type":"boolean"},"redirectToCode":{"description":"Status code to auto-redirect to after timeout.","examples":["done"],"type":"string"},"redirectTimeout":{"description":"Relative time before redirect (e.g. \"2h\", \"1d\").","examples":["2h"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["label","code","color","markAsPaid","createInvoice","createReceipt"],"properties":{"label":{"description":"Display label for the status.","examples":["Odesláno"],"type":"string"},"code":{"description":"Status code to update (identifies the status).","examples":["odeslano"],"type":"string"},"internalName":{"description":"Internal name visible only to staff.","type":"string"},"publicLabel":{"description":"Public-facing label shown to customers.","type":"string"},"color":{"description":"Hex color for the status badge.","examples":["#22c55e"],"type":"string"},"markAsPaid":{"description":"Automatically mark order as paid when entering this status.","type":"boolean"},"createInvoice":{"description":"Automatically create invoice when entering this status.","type":"boolean"},"createReceipt":{"description":"Automatically create receipt when entering this status.","type":"boolean"},"redirectToCode":{"description":"Status code to auto-redirect to after timeout.","examples":["done"],"type":"string"},"redirectTimeout":{"description":"Relative time before redirect (e.g. \"2h\", \"1d\").","examples":["2h"],"type":"string"}}}}}}}},"/bff/workflow/set-status-position":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowSet-status-position","tags":["Workflow"],"summary":"Change workflow status position","description":"Moves a workflow status up or down in the ordering within its phase group.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","direction"],"properties":{"code":{"description":"Status code to reorder.","examples":["odeslano"],"type":"string"},"direction":{"description":"Direction to move: \"up\" or \"down\".","examples":["up"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","direction"],"properties":{"code":{"description":"Status code to reorder.","examples":["odeslano"],"type":"string"},"direction":{"description":"Direction to move: \"up\" or \"down\".","examples":["up"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code","direction"],"properties":{"code":{"description":"Status code to reorder.","examples":["odeslano"],"type":"string"},"direction":{"description":"Direction to move: \"up\" or \"down\".","examples":["up"],"type":"string"}}}}}}}},"/bff/workflow/assign-group-status":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowAssign-group-status","tags":["Workflow"],"summary":"Assign status to order group","description":"Links a workflow status to an order group so that orders in this group only show the assigned statuses.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["groupCode","statusCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to assign to the group.","examples":["odeslano"],"type":"string"},"position":{"description":"Position within the group. Auto-assigned if omitted.","type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["groupCode","statusCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to assign to the group.","examples":["odeslano"],"type":"string"},"position":{"description":"Position within the group. Auto-assigned if omitted.","type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["groupCode","statusCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to assign to the group.","examples":["odeslano"],"type":"string"},"position":{"description":"Position within the group. Auto-assigned if omitted.","type":"number"}}}}}}}},"/bff/workflow/remove-group-status":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowRemove-group-status","tags":["Workflow"],"summary":"Remove status from order group","description":"Unlinks a workflow status from an order group.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["groupCode","statusCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to remove from the group.","examples":["odeslano"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["groupCode","statusCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to remove from the group.","examples":["odeslano"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["groupCode","statusCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to remove from the group.","examples":["odeslano"],"type":"string"}}}}}}}},"/bff/workflow/assign-group-template":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowAssign-group-template","tags":["Workflow"],"summary":"Assign email template to group status","description":"Links an email template to a specific status within an order group for status change notifications.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["groupCode","statusCode","templateCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code the template is linked to.","examples":["odeslano"],"type":"string"},"templateCode":{"description":"Email template code to assign.","examples":["order-shipped-cs"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["groupCode","statusCode","templateCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code the template is linked to.","examples":["odeslano"],"type":"string"},"templateCode":{"description":"Email template code to assign.","examples":["order-shipped-cs"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["groupCode","statusCode","templateCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code the template is linked to.","examples":["odeslano"],"type":"string"},"templateCode":{"description":"Email template code to assign.","examples":["order-shipped-cs"],"type":"string"}}}}}}}},"/bff/workflow/remove-group-template":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowRemove-group-template","tags":["Workflow"],"summary":"Remove email template from group status","description":"Unlinks an email template from a specific status within an order group.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["groupCode","statusCode","templateCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to unlink the template from.","examples":["odeslano"],"type":"string"},"templateCode":{"description":"Email template code to remove.","examples":["order-shipped-cs"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["groupCode","statusCode","templateCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to unlink the template from.","examples":["odeslano"],"type":"string"},"templateCode":{"description":"Email template code to remove.","examples":["order-shipped-cs"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["groupCode","statusCode","templateCode"],"properties":{"groupCode":{"description":"Order group code.","examples":["default"],"type":"string"},"statusCode":{"description":"Status code to unlink the template from.","examples":["odeslano"],"type":"string"},"templateCode":{"description":"Email template code to remove.","examples":["order-shipped-cs"],"type":"string"}}}}}}}},"/bff/workflow/group-templates":{"get":{"parameters":[{"description":"Order group code to list templates for.","examples":["default"],"schema":{"type":"string"},"in":"query","name":"groupCode","required":true}],"operationId":"getBffWorkflowGroup-templates","tags":["Workflow"],"summary":"List group email templates","description":"Returns all email templates linked to statuses within the specified order group.","responses":{"200":{}}}},"/bff/workflow/group-list":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","name","description","default","active","position","dueDateRelativeTime","invoicePrefix","invoiceIssuerId","invoiceIssuer","insertedDate","orderCount","statusCount","statuses","paymentGatewayPreference"],"properties":{"id":{"description":"Internal numeric group ID.","type":"number"},"code":{"description":"Stable group code (slug, unique per organisation).","examples":["default"],"type":"string"},"name":{"description":"Display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Free-form admin description.","type":"string"},{"type":"null"}]},"default":{"description":"Whether this group is the organisation default.","type":"boolean"},"active":{"description":"Whether new orders can be assigned to this group.","type":"boolean"},"position":{"description":"Sort order within the organisation.","type":"number"},"dueDateRelativeTime":{"description":"Default due-date offset for new orders, e.g. \"7d\".","examples":["7d"],"type":"string"},"invoicePrefix":{"nullable":true,"anyOf":[{"description":"Optional invoice number prefix (1–3 chars).","examples":["A"],"type":"string"},{"type":"null"}]},"invoiceIssuerId":{"nullable":true,"anyOf":[{"description":"Contact ID of the invoice issuer override, or null to use the org default.","type":"number"},{"type":"null"}]},"invoiceIssuer":{"nullable":true,"anyOf":[{"description":"Override contact who issues invoices for this group. `null` means the organisation's internal contact is used (default behaviour).","type":"object","required":["cuRefNo","name","companyName","personalName","email"],"properties":{"cuRefNo":{"description":"shop__contact.external_id (16-char) — admin-facing contact reference.","type":"string"},"name":{"description":"Display label. Company name with personal name in parens when both exist, otherwise whichever is set, otherwise email.","type":"string"},"companyName":{"nullable":true,"anyOf":[{"description":"Trading / legal name of the company, if set on the contact.","type":"string"},{"type":"null"}]},"personalName":{"nullable":true,"anyOf":[{"description":"Trimmed `first last` of the contact, or `null` when neither is set.","type":"string"},{"type":"null"}]},"email":{"nullable":true,"anyOf":[{"description":"Invoice issuer e-mail. `null` for phone-only contacts; in that case the issuer block on the invoice falls back to `name` and `cuRefNo`.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"insertedDate":{"description":"ISO timestamp when the group was created.","type":"string"},"orderCount":{"description":"Total number of orders ever assigned to this group.","type":"number"},"statusCount":{"description":"Number of workflow statuses linked via shop__order_group_status.","type":"number"},"statuses":{"description":"Statuses enabled for this group, ordered by their group position then global workflow position.","type":"array","items":{"type":"object","required":["id","code","label","color","workflowPosition","position"],"properties":{"id":{"description":"Status internal ID.","type":"number"},"code":{"description":"Status code.","examples":["paid"],"type":"string"},"label":{"description":"Status display label.","type":"string"},"color":{"description":"Hex color including leading #.","examples":["#3c78d8"],"type":"string"},"workflowPosition":{"description":"Global workflow position within the organisation.","type":"number"},"position":{"description":"Position of the status within this group.","type":"number"}}}},"paymentGatewayPreference":{"description":"How online payments resolve for orders in this group.","type":"object","required":["mode","gatewayCode","gatewayInstanceId"],"properties":{"mode":{"description":"\"fallback\" — group has no specific preference, resolver uses the org-wide active gateway. \"specific\" — group is bound to a single gateway instance (see gatewayCode). \"none\" — online payments are explicitly disabled for this group; no redirect, no fallback.","anyOf":[{"const":"fallback","type":"string"},{"const":"specific","type":"string"},{"const":"none","type":"string"}]},"gatewayCode":{"nullable":true,"anyOf":[{"description":"Gateway instance code when mode is \"specific\".","type":"string"},{"type":"null"}]},"gatewayInstanceId":{"nullable":true,"anyOf":[{"description":"Gateway instance internal ID when mode is \"specific\".","type":"number"},{"type":"null"}]}}}}}},"itemCount":{"description":"Total number of groups returned.","type":"number"}},"required":["items","itemCount"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","name","description","default","active","position","dueDateRelativeTime","invoicePrefix","invoiceIssuerId","invoiceIssuer","insertedDate","orderCount","statusCount","statuses","paymentGatewayPreference"],"properties":{"id":{"description":"Internal numeric group ID.","type":"number"},"code":{"description":"Stable group code (slug, unique per organisation).","examples":["default"],"type":"string"},"name":{"description":"Display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Free-form admin description.","type":"string"},{"type":"null"}]},"default":{"description":"Whether this group is the organisation default.","type":"boolean"},"active":{"description":"Whether new orders can be assigned to this group.","type":"boolean"},"position":{"description":"Sort order within the organisation.","type":"number"},"dueDateRelativeTime":{"description":"Default due-date offset for new orders, e.g. \"7d\".","examples":["7d"],"type":"string"},"invoicePrefix":{"nullable":true,"anyOf":[{"description":"Optional invoice number prefix (1–3 chars).","examples":["A"],"type":"string"},{"type":"null"}]},"invoiceIssuerId":{"nullable":true,"anyOf":[{"description":"Contact ID of the invoice issuer override, or null to use the org default.","type":"number"},{"type":"null"}]},"invoiceIssuer":{"nullable":true,"anyOf":[{"description":"Override contact who issues invoices for this group. `null` means the organisation's internal contact is used (default behaviour).","type":"object","required":["cuRefNo","name","companyName","personalName","email"],"properties":{"cuRefNo":{"description":"shop__contact.external_id (16-char) — admin-facing contact reference.","type":"string"},"name":{"description":"Display label. Company name with personal name in parens when both exist, otherwise whichever is set, otherwise email.","type":"string"},"companyName":{"nullable":true,"anyOf":[{"description":"Trading / legal name of the company, if set on the contact.","type":"string"},{"type":"null"}]},"personalName":{"nullable":true,"anyOf":[{"description":"Trimmed `first last` of the contact, or `null` when neither is set.","type":"string"},{"type":"null"}]},"email":{"nullable":true,"anyOf":[{"description":"Invoice issuer e-mail. `null` for phone-only contacts; in that case the issuer block on the invoice falls back to `name` and `cuRefNo`.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"insertedDate":{"description":"ISO timestamp when the group was created.","type":"string"},"orderCount":{"description":"Total number of orders ever assigned to this group.","type":"number"},"statusCount":{"description":"Number of workflow statuses linked via shop__order_group_status.","type":"number"},"statuses":{"description":"Statuses enabled for this group, ordered by their group position then global workflow position.","type":"array","items":{"type":"object","required":["id","code","label","color","workflowPosition","position"],"properties":{"id":{"description":"Status internal ID.","type":"number"},"code":{"description":"Status code.","examples":["paid"],"type":"string"},"label":{"description":"Status display label.","type":"string"},"color":{"description":"Hex color including leading #.","examples":["#3c78d8"],"type":"string"},"workflowPosition":{"description":"Global workflow position within the organisation.","type":"number"},"position":{"description":"Position of the status within this group.","type":"number"}}}},"paymentGatewayPreference":{"description":"How online payments resolve for orders in this group.","type":"object","required":["mode","gatewayCode","gatewayInstanceId"],"properties":{"mode":{"description":"\"fallback\" — group has no specific preference, resolver uses the org-wide active gateway. \"specific\" — group is bound to a single gateway instance (see gatewayCode). \"none\" — online payments are explicitly disabled for this group; no redirect, no fallback.","anyOf":[{"const":"fallback","type":"string"},{"const":"specific","type":"string"},{"const":"none","type":"string"}]},"gatewayCode":{"nullable":true,"anyOf":[{"description":"Gateway instance code when mode is \"specific\".","type":"string"},{"type":"null"}]},"gatewayInstanceId":{"nullable":true,"anyOf":[{"description":"Gateway instance internal ID when mode is \"specific\".","type":"number"},{"type":"null"}]}}}}}},"itemCount":{"description":"Total number of groups returned.","type":"number"}},"required":["items","itemCount"]}},"text/plain":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","required":["id","code","name","description","default","active","position","dueDateRelativeTime","invoicePrefix","invoiceIssuerId","invoiceIssuer","insertedDate","orderCount","statusCount","statuses","paymentGatewayPreference"],"properties":{"id":{"description":"Internal numeric group ID.","type":"number"},"code":{"description":"Stable group code (slug, unique per organisation).","examples":["default"],"type":"string"},"name":{"description":"Display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"Free-form admin description.","type":"string"},{"type":"null"}]},"default":{"description":"Whether this group is the organisation default.","type":"boolean"},"active":{"description":"Whether new orders can be assigned to this group.","type":"boolean"},"position":{"description":"Sort order within the organisation.","type":"number"},"dueDateRelativeTime":{"description":"Default due-date offset for new orders, e.g. \"7d\".","examples":["7d"],"type":"string"},"invoicePrefix":{"nullable":true,"anyOf":[{"description":"Optional invoice number prefix (1–3 chars).","examples":["A"],"type":"string"},{"type":"null"}]},"invoiceIssuerId":{"nullable":true,"anyOf":[{"description":"Contact ID of the invoice issuer override, or null to use the org default.","type":"number"},{"type":"null"}]},"invoiceIssuer":{"nullable":true,"anyOf":[{"description":"Override contact who issues invoices for this group. `null` means the organisation's internal contact is used (default behaviour).","type":"object","required":["cuRefNo","name","companyName","personalName","email"],"properties":{"cuRefNo":{"description":"shop__contact.external_id (16-char) — admin-facing contact reference.","type":"string"},"name":{"description":"Display label. Company name with personal name in parens when both exist, otherwise whichever is set, otherwise email.","type":"string"},"companyName":{"nullable":true,"anyOf":[{"description":"Trading / legal name of the company, if set on the contact.","type":"string"},{"type":"null"}]},"personalName":{"nullable":true,"anyOf":[{"description":"Trimmed `first last` of the contact, or `null` when neither is set.","type":"string"},{"type":"null"}]},"email":{"nullable":true,"anyOf":[{"description":"Invoice issuer e-mail. `null` for phone-only contacts; in that case the issuer block on the invoice falls back to `name` and `cuRefNo`.","type":"string"},{"type":"null"}]}}},{"type":"null"}]},"insertedDate":{"description":"ISO timestamp when the group was created.","type":"string"},"orderCount":{"description":"Total number of orders ever assigned to this group.","type":"number"},"statusCount":{"description":"Number of workflow statuses linked via shop__order_group_status.","type":"number"},"statuses":{"description":"Statuses enabled for this group, ordered by their group position then global workflow position.","type":"array","items":{"type":"object","required":["id","code","label","color","workflowPosition","position"],"properties":{"id":{"description":"Status internal ID.","type":"number"},"code":{"description":"Status code.","examples":["paid"],"type":"string"},"label":{"description":"Status display label.","type":"string"},"color":{"description":"Hex color including leading #.","examples":["#3c78d8"],"type":"string"},"workflowPosition":{"description":"Global workflow position within the organisation.","type":"number"},"position":{"description":"Position of the status within this group.","type":"number"}}}},"paymentGatewayPreference":{"description":"How online payments resolve for orders in this group.","type":"object","required":["mode","gatewayCode","gatewayInstanceId"],"properties":{"mode":{"description":"\"fallback\" — group has no specific preference, resolver uses the org-wide active gateway. \"specific\" — group is bound to a single gateway instance (see gatewayCode). \"none\" — online payments are explicitly disabled for this group; no redirect, no fallback.","anyOf":[{"const":"fallback","type":"string"},{"const":"specific","type":"string"},{"const":"none","type":"string"}]},"gatewayCode":{"nullable":true,"anyOf":[{"description":"Gateway instance code when mode is \"specific\".","type":"string"},{"type":"null"}]},"gatewayInstanceId":{"nullable":true,"anyOf":[{"description":"Gateway instance internal ID when mode is \"specific\".","type":"number"},{"type":"null"}]}}}}}},"itemCount":{"description":"Total number of groups returned.","type":"number"}},"required":["items","itemCount"]}}}}},"operationId":"getBffWorkflowGroup-list","tags":["Workflow"],"summary":"List order groups","description":"Returns all order groups for the organisation with related data: order count, status count, and the list of workflow statuses linked to each group via the N:M shop__order_group_status table. Always invokes the bootstrap function first — guarantees that the organisation has the default order group and the default workflow status set, and that the default group has all statuses linked."}},"/bff/workflow/group-set-payment-gateway":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowGroup-set-payment-gateway","tags":["Workflow"],"summary":"Set payment-gateway preference for an order group","description":"Configures how online payments resolve for a given order group. \"fallback\" deletes any explicit preference (resolver picks the org-wide active gateway). \"specific\" binds the group to one gateway instance. \"none\" disables online payments for the group entirely — createPayment() will skip without redirect or fallback.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["groupCode","mode"],"properties":{"groupCode":{"description":"Order group code to configure.","examples":["rezervace-smichov"],"type":"string"},"mode":{"description":"\"fallback\" — clears any preference; resolver will use the org-wide active gateway. \"specific\" — bind the group to a single gateway instance (gatewayCode required). \"none\" — explicitly disable online payments for this group; resolver returns null, no fallback.","anyOf":[{"const":"fallback","type":"string"},{"const":"specific","type":"string"},{"const":"none","type":"string"}]},"gatewayCode":{"nullable":true,"anyOf":[{"description":"Gateway instance code. Required when mode is \"specific\", ignored otherwise.","examples":["gopay-production"],"type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["groupCode","mode"],"properties":{"groupCode":{"description":"Order group code to configure.","examples":["rezervace-smichov"],"type":"string"},"mode":{"description":"\"fallback\" — clears any preference; resolver will use the org-wide active gateway. \"specific\" — bind the group to a single gateway instance (gatewayCode required). \"none\" — explicitly disable online payments for this group; resolver returns null, no fallback.","anyOf":[{"const":"fallback","type":"string"},{"const":"specific","type":"string"},{"const":"none","type":"string"}]},"gatewayCode":{"nullable":true,"anyOf":[{"description":"Gateway instance code. Required when mode is \"specific\", ignored otherwise.","examples":["gopay-production"],"type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["groupCode","mode"],"properties":{"groupCode":{"description":"Order group code to configure.","examples":["rezervace-smichov"],"type":"string"},"mode":{"description":"\"fallback\" — clears any preference; resolver will use the org-wide active gateway. \"specific\" — bind the group to a single gateway instance (gatewayCode required). \"none\" — explicitly disable online payments for this group; resolver returns null, no fallback.","anyOf":[{"const":"fallback","type":"string"},{"const":"specific","type":"string"},{"const":"none","type":"string"}]},"gatewayCode":{"nullable":true,"anyOf":[{"description":"Gateway instance code. Required when mode is \"specific\", ignored otherwise.","examples":["gopay-production"],"type":"string"},{"type":"null"}]}}}}}}}},"/bff/workflow/group-set-invoice-issuer":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowGroup-set-invoice-issuer","tags":["Workflow"],"summary":"Set invoice-issuer contact for an order group","description":"Overrides the contact used as the invoice-issuing party for orders in this group. When `null`, the override is cleared and the organisation's internal contact (the default) is used.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["groupCode","contactCuRefNo"],"properties":{"groupCode":{"description":"Order group code to configure.","examples":["default"],"type":"string"},"contactCuRefNo":{"nullable":true,"anyOf":[{"description":"shop__contact.external_id (16-char) of the contact who should issue invoices for this group. `null` clears the override — the organisation's internal contact is used as before.","type":"string"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["groupCode","contactCuRefNo"],"properties":{"groupCode":{"description":"Order group code to configure.","examples":["default"],"type":"string"},"contactCuRefNo":{"nullable":true,"anyOf":[{"description":"shop__contact.external_id (16-char) of the contact who should issue invoices for this group. `null` clears the override — the organisation's internal contact is used as before.","type":"string"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["groupCode","contactCuRefNo"],"properties":{"groupCode":{"description":"Order group code to configure.","examples":["default"],"type":"string"},"contactCuRefNo":{"nullable":true,"anyOf":[{"description":"shop__contact.external_id (16-char) of the contact who should issue invoices for this group. `null` clears the override — the organisation's internal contact is used as before.","type":"string"},{"type":"null"}]}}}}}}}},"/bff/workflow/group-add":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"description":"Resolved group code (slugified).","type":"string"}},"required":["success","code"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"description":"Resolved group code (slugified).","type":"string"}},"required":["success","code"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"},"code":{"description":"Resolved group code (slugified).","type":"string"}},"required":["success","code"]}}}}},"operationId":"postBffWorkflowGroup-add","tags":["Workflow"],"summary":"Create order group","description":"Creates a new order group for the organisation and attaches a workflow-status set to it via shop__order_group_status. Code uniqueness and invoice-prefix uniqueness are enforced. The group is created at the end of the position order.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"description":"Display name of the new group.","examples":["Reservations"],"type":"string"},"code":{"description":"Optional stable code (slug). Auto-generated from name when omitted.","type":"string"},"description":{"description":"Free-form admin description.","type":"string"},"dueDateRelativeTime":{"description":"Default due-date offset for new orders.","examples":["7d"],"type":"string"},"invoicePrefix":{"description":"Optional invoice prefix (1–3 chars), unique per organisation.","type":"string"},"statusCodes":{"description":"Optional explicit list of status codes to attach to the new group. When omitted, the link set is copied from the default group, or all org statuses are linked if no default group has links.","type":"array","items":{"type":"string"}}}}},"multipart/form-data":{"schema":{"type":"object","required":["name"],"properties":{"name":{"description":"Display name of the new group.","examples":["Reservations"],"type":"string"},"code":{"description":"Optional stable code (slug). Auto-generated from name when omitted.","type":"string"},"description":{"description":"Free-form admin description.","type":"string"},"dueDateRelativeTime":{"description":"Default due-date offset for new orders.","examples":["7d"],"type":"string"},"invoicePrefix":{"description":"Optional invoice prefix (1–3 chars), unique per organisation.","type":"string"},"statusCodes":{"description":"Optional explicit list of status codes to attach to the new group. When omitted, the link set is copied from the default group, or all org statuses are linked if no default group has links.","type":"array","items":{"type":"string"}}}}},"text/plain":{"schema":{"type":"object","required":["name"],"properties":{"name":{"description":"Display name of the new group.","examples":["Reservations"],"type":"string"},"code":{"description":"Optional stable code (slug). Auto-generated from name when omitted.","type":"string"},"description":{"description":"Free-form admin description.","type":"string"},"dueDateRelativeTime":{"description":"Default due-date offset for new orders.","examples":["7d"],"type":"string"},"invoicePrefix":{"description":"Optional invoice prefix (1–3 chars), unique per organisation.","type":"string"},"statusCodes":{"description":"Optional explicit list of status codes to attach to the new group. When omitted, the link set is copied from the default group, or all org statuses are linked if no default group has links.","type":"array","items":{"type":"string"}}}}}}}}},"/bff/workflow/group-update":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowGroup-update","tags":["Workflow"],"summary":"Update order group","description":"Updates editable fields of an order group. Only provided fields are touched.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to update.","examples":["default"],"type":"string"},"name":{"description":"New display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"New description, or null to clear.","type":"string"},{"type":"null"}]},"active":{"description":"Activate or deactivate the group. Default group cannot be deactivated.","type":"boolean"},"dueDateRelativeTime":{"description":"New due-date offset.","examples":["14d"],"type":"string"},"invoicePrefix":{"nullable":true,"anyOf":[{"description":"New invoice prefix, or null to clear.","type":"string"},{"type":"null"}]},"invoiceIssuerId":{"nullable":true,"anyOf":[{"description":"Contact ID of the invoice issuer override, or null to clear.","type":"number"},{"type":"null"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to update.","examples":["default"],"type":"string"},"name":{"description":"New display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"New description, or null to clear.","type":"string"},{"type":"null"}]},"active":{"description":"Activate or deactivate the group. Default group cannot be deactivated.","type":"boolean"},"dueDateRelativeTime":{"description":"New due-date offset.","examples":["14d"],"type":"string"},"invoicePrefix":{"nullable":true,"anyOf":[{"description":"New invoice prefix, or null to clear.","type":"string"},{"type":"null"}]},"invoiceIssuerId":{"nullable":true,"anyOf":[{"description":"Contact ID of the invoice issuer override, or null to clear.","type":"number"},{"type":"null"}]}}}},"text/plain":{"schema":{"type":"object","required":["code"],"properties":{"code":{"description":"Code of the group to update.","examples":["default"],"type":"string"},"name":{"description":"New display name.","type":"string"},"description":{"nullable":true,"anyOf":[{"description":"New description, or null to clear.","type":"string"},{"type":"null"}]},"active":{"description":"Activate or deactivate the group. Default group cannot be deactivated.","type":"boolean"},"dueDateRelativeTime":{"description":"New due-date offset.","examples":["14d"],"type":"string"},"invoicePrefix":{"nullable":true,"anyOf":[{"description":"New invoice prefix, or null to clear.","type":"string"},{"type":"null"}]},"invoiceIssuerId":{"nullable":true,"anyOf":[{"description":"Contact ID of the invoice issuer override, or null to clear.","type":"number"},{"type":"null"}]}}}}}}}},"/bff/workflow/group-set-position":{"post":{"parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}},"text/plain":{"schema":{"type":"object","properties":{"success":{"default":true,"type":"boolean"}},"required":["success"]}}}}},"operationId":"postBffWorkflowGroup-set-position","tags":["Workflow"],"summary":"Reorder order group","description":"Swaps the position of an order group with its neighbour. No-op at the boundary.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","direction"],"properties":{"code":{"description":"Code of the group to reorder.","examples":["reservations"],"type":"string"},"direction":{"description":"Direction to move: \"up\" or \"down\".","examples":["up"],"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","direction"],"properties":{"code":{"description":"Code of the group to reorder.","examples":["reservations"],"type":"string"},"direction":{"description":"Direction to move: \"up\" or \"down\".","examples":["up"],"type":"string"}}}},"text/plain":{"schema":{"type":"object","required":["code","direction"],"properties":{"code":{"description":"Code of the group to reorder.","examples":["reservations"],"type":"string"},"direction":{"description":"Direction to move: \"up\" or \"down\".","examples":["up"],"type":"string"}}}}}}}},"/bff/purchase-invoice/list":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false},{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"operationId":"getBffPurchase-invoiceList","tags":["PurchaseInvoice"],"summary":"List purchase (received) invoices","responses":{"200":{}}}},"/bff/purchase-invoice/detail":{"get":{"parameters":[{"description":"Numeric purchase-invoice id.","schema":{"type":"string"},"in":"query","name":"id","required":true}],"operationId":"getBffPurchase-invoiceDetail","tags":["PurchaseInvoice"],"summary":"Purchase invoice detail (header + items + log)","responses":{"200":{}}}},"/bff/purchase-invoice/stats":{"get":{"operationId":"getBffPurchase-invoiceStats","tags":["PurchaseInvoice"],"summary":"KPI breakdown — counts/sums per status + overdue + YTD.","responses":{"200":{}}}},"/bff/purchase-invoice/create":{"post":{"parameters":[],"operationId":"postBffPurchase-invoiceCreate","tags":["PurchaseInvoice"],"summary":"Create a new purchase invoice (draft) with items","description":"Header + items are persisted in one transaction. Items without an explicit `vatClassificationId` are auto-classified server-side (country-aware + rate-based). CNB exchange rate to CZK is resolved against `taxDate` (or `issueDate` as fallback) and snapshotted on the row, so EPO reports always use the original posting rate.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["currencyCode","issueDate","items"],"properties":{"vendorExternalNumber":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"recipientId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"currencyCode":{"description":"ISO-4217 currency code (e.g. CZK, EUR).","type":"string"},"issueDate":{"description":"Issue date (YYYY-MM-DD).","type":"string"},"dueDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"taxDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"receivedDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"variableSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"constantSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"specificSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorIban":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorSwift":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"internalNotice":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"publicNotice":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"rounding":{"default":0,"type":"number"},"isReverseCharge":{"default":false,"type":"boolean"},"isCreditNote":{"default":false,"type":"boolean"},"parentId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"items":{"minItems":1,"description":"At least one line is required.","type":"array","items":{"type":"object","required":["description","quantity","unitPrice","vatRate"],"properties":{"description":{"description":"Item description (free text).","type":"string"},"quantity":{"description":"Quantity, ≥ 0.","type":"number"},"unitPrice":{"description":"Unit price (without VAT) in invoice currency.","type":"number"},"vatRate":{"description":"VAT rate in percent (e.g. 21, 12, 0).","type":"number"},"vatClassificationId":{"nullable":true,"anyOf":[{"description":"Explicit classification id (auto-classify if null).","type":"number"},{"type":"null"}]}}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["currencyCode","issueDate","items"],"properties":{"vendorExternalNumber":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"recipientId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"currencyCode":{"description":"ISO-4217 currency code (e.g. CZK, EUR).","type":"string"},"issueDate":{"description":"Issue date (YYYY-MM-DD).","type":"string"},"dueDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"taxDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"receivedDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"variableSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"constantSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"specificSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorIban":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorSwift":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"internalNotice":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"publicNotice":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"rounding":{"default":0,"type":"number"},"isReverseCharge":{"default":false,"type":"boolean"},"isCreditNote":{"default":false,"type":"boolean"},"parentId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"items":{"minItems":1,"description":"At least one line is required.","type":"array","items":{"type":"object","required":["description","quantity","unitPrice","vatRate"],"properties":{"description":{"description":"Item description (free text).","type":"string"},"quantity":{"description":"Quantity, ≥ 0.","type":"number"},"unitPrice":{"description":"Unit price (without VAT) in invoice currency.","type":"number"},"vatRate":{"description":"VAT rate in percent (e.g. 21, 12, 0).","type":"number"},"vatClassificationId":{"nullable":true,"anyOf":[{"description":"Explicit classification id (auto-classify if null).","type":"number"},{"type":"null"}]}}}}}}},"text/plain":{"schema":{"type":"object","required":["currencyCode","issueDate","items"],"properties":{"vendorExternalNumber":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"recipientId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"currencyCode":{"description":"ISO-4217 currency code (e.g. CZK, EUR).","type":"string"},"issueDate":{"description":"Issue date (YYYY-MM-DD).","type":"string"},"dueDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"taxDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"receivedDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"variableSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"constantSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"specificSymbol":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorIban":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"vendorSwift":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"internalNotice":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"publicNotice":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"rounding":{"default":0,"type":"number"},"isReverseCharge":{"default":false,"type":"boolean"},"isCreditNote":{"default":false,"type":"boolean"},"parentId":{"nullable":true,"anyOf":[{"type":"number"},{"type":"null"}]},"items":{"minItems":1,"description":"At least one line is required.","type":"array","items":{"type":"object","required":["description","quantity","unitPrice","vatRate"],"properties":{"description":{"description":"Item description (free text).","type":"string"},"quantity":{"description":"Quantity, ≥ 0.","type":"number"},"unitPrice":{"description":"Unit price (without VAT) in invoice currency.","type":"number"},"vatRate":{"description":"VAT rate in percent (e.g. 21, 12, 0).","type":"number"},"vatClassificationId":{"nullable":true,"anyOf":[{"description":"Explicit classification id (auto-classify if null).","type":"number"},{"type":"null"}]}}}}}}}}},"responses":{"200":{}}}},"/bff/purchase-invoice/status":{"post":{"parameters":[],"operationId":"postBffPurchase-invoiceStatus","tags":["PurchaseInvoice"],"summary":"Transition status (draft → received → booked → paid)","description":"Standard transitions follow the lifecycle. Backwards moves (e.g. paid → booked) require `force: true` and are recorded in coreAuditLog as `force_edit`. The shop__purchase_invoice_log timeline also captures every change for the per-invoice detail page.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","nextStatus"],"properties":{"id":{"type":"number"},"nextStatus":{"description":"Lifecycle status of a purchase invoice.","anyOf":[{"const":"draft","type":"string"},{"const":"received","type":"string"},{"const":"booked","type":"string"},{"const":"paid","type":"string"},{"const":"cancelled","type":"string"}]},"paidDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"force":{"default":false,"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id","nextStatus"],"properties":{"id":{"type":"number"},"nextStatus":{"description":"Lifecycle status of a purchase invoice.","anyOf":[{"const":"draft","type":"string"},{"const":"received","type":"string"},{"const":"booked","type":"string"},{"const":"paid","type":"string"},{"const":"cancelled","type":"string"}]},"paidDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"force":{"default":false,"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["id","nextStatus"],"properties":{"id":{"type":"number"},"nextStatus":{"description":"Lifecycle status of a purchase invoice.","anyOf":[{"const":"draft","type":"string"},{"const":"received","type":"string"},{"const":"booked","type":"string"},{"const":"paid","type":"string"},{"const":"cancelled","type":"string"}]},"paidDate":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"force":{"default":false,"type":"boolean"}}}}}},"responses":{"200":{}}}},"/bff/purchase-invoice/delete":{"post":{"parameters":[],"operationId":"postBffPurchase-invoiceDelete","tags":["PurchaseInvoice"],"summary":"Force-delete a purchase invoice (irreversible)","description":"Hard delete + audit log. Attachments are NOT cascaded; they become orphans in core__blob and are cleaned up by the periodic orphan-blob sweep. Prefer status=\"cancelled\" instead.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"number"}}}}}},"responses":{"200":{}}}},"/bff/vat-classification/list":{"get":{"operationId":"getBffVat-classificationList","tags":["VatClassification"],"summary":"List VAT classification codes (seeded on first use).","responses":{"200":{}}}},"/bff/vat-classification/seed":{"post":{"operationId":"postBffVat-classificationSeed","tags":["VatClassification"],"summary":"Force-seed the canonical Czech classification catalog (idempotent).","responses":{"200":{}}}},"/bff/vat-classification/upsert":{"post":{"parameters":[],"operationId":"postBffVat-classificationUpsert","tags":["VatClassification"],"summary":"Create or update a VAT classification code.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","category"],"properties":{"id":{"type":"number"},"code":{"minLength":1,"maxLength":32,"type":"string"},"labelCs":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"anyOf":[{"const":"domestic","type":"string"},{"const":"eu_supply","type":"string"},{"const":"eu_acquisition","type":"string"},{"const":"third_country","type":"string"},{"const":"reverse_charge","type":"string"},{"const":"exempt","type":"string"},{"const":"not_subject","type":"string"}]},"dphFormRow":{"nullable":true,"anyOf":[{"maxLength":8,"type":"string"},{"type":"null"}]},"khSection":{"nullable":true,"anyOf":[{"maxLength":8,"type":"string"},{"type":"null"}]},"isReverseCharge":{"default":false,"type":"boolean"},"rateCode":{"nullable":true,"anyOf":[{"maxLength":32,"type":"string"},{"type":"null"}]},"isDefault":{"default":false,"type":"boolean"},"active":{"default":true,"type":"boolean"},"displayOrder":{"default":0,"type":"number"}}}},"multipart/form-data":{"schema":{"type":"object","required":["code","category"],"properties":{"id":{"type":"number"},"code":{"minLength":1,"maxLength":32,"type":"string"},"labelCs":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"anyOf":[{"const":"domestic","type":"string"},{"const":"eu_supply","type":"string"},{"const":"eu_acquisition","type":"string"},{"const":"third_country","type":"string"},{"const":"reverse_charge","type":"string"},{"const":"exempt","type":"string"},{"const":"not_subject","type":"string"}]},"dphFormRow":{"nullable":true,"anyOf":[{"maxLength":8,"type":"string"},{"type":"null"}]},"khSection":{"nullable":true,"anyOf":[{"maxLength":8,"type":"string"},{"type":"null"}]},"isReverseCharge":{"default":false,"type":"boolean"},"rateCode":{"nullable":true,"anyOf":[{"maxLength":32,"type":"string"},{"type":"null"}]},"isDefault":{"default":false,"type":"boolean"},"active":{"default":true,"type":"boolean"},"displayOrder":{"default":0,"type":"number"}}}},"text/plain":{"schema":{"type":"object","required":["code","category"],"properties":{"id":{"type":"number"},"code":{"minLength":1,"maxLength":32,"type":"string"},"labelCs":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"labelEn":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"anyOf":[{"const":"domestic","type":"string"},{"const":"eu_supply","type":"string"},{"const":"eu_acquisition","type":"string"},{"const":"third_country","type":"string"},{"const":"reverse_charge","type":"string"},{"const":"exempt","type":"string"},{"const":"not_subject","type":"string"}]},"dphFormRow":{"nullable":true,"anyOf":[{"maxLength":8,"type":"string"},{"type":"null"}]},"khSection":{"nullable":true,"anyOf":[{"maxLength":8,"type":"string"},{"type":"null"}]},"isReverseCharge":{"default":false,"type":"boolean"},"rateCode":{"nullable":true,"anyOf":[{"maxLength":32,"type":"string"},{"type":"null"}]},"isDefault":{"default":false,"type":"boolean"},"active":{"default":true,"type":"boolean"},"displayOrder":{"default":0,"type":"number"}}}}}},"responses":{"200":{}}}},"/bff/tax/epo/preview":{"post":{"parameters":[],"operationId":"postBffTaxEpoPreview","tags":["Tax"],"summary":"Build an EPO XML preview without archiving (used for the \"Preview\" tab in /tax/epo).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind","period"],"properties":{"kind":{"description":"Which EPO XML to build: DPH přiznání, Kontrolní hlášení, or Souhrnné hlášení.","anyOf":[{"const":"dphdp3","type":"string"},{"const":"dphkh1","type":"string"},{"const":"dphshv","type":"string"}]},"period":{"type":"object","required":["year","month","kind"],"properties":{"year":{"minimum":2020,"maximum":2099,"type":"number"},"month":{"minimum":1,"maximum":12,"type":"number"},"kind":{"anyOf":[{"const":"monthly","type":"string"},{"const":"quarterly","type":"string"}]}}}}}},"multipart/form-data":{"schema":{"type":"object","required":["kind","period"],"properties":{"kind":{"description":"Which EPO XML to build: DPH přiznání, Kontrolní hlášení, or Souhrnné hlášení.","anyOf":[{"const":"dphdp3","type":"string"},{"const":"dphkh1","type":"string"},{"const":"dphshv","type":"string"}]},"period":{"type":"object","required":["year","month","kind"],"properties":{"year":{"minimum":2020,"maximum":2099,"type":"number"},"month":{"minimum":1,"maximum":12,"type":"number"},"kind":{"anyOf":[{"const":"monthly","type":"string"},{"const":"quarterly","type":"string"}]}}}}}},"text/plain":{"schema":{"type":"object","required":["kind","period"],"properties":{"kind":{"description":"Which EPO XML to build: DPH přiznání, Kontrolní hlášení, or Souhrnné hlášení.","anyOf":[{"const":"dphdp3","type":"string"},{"const":"dphkh1","type":"string"},{"const":"dphshv","type":"string"}]},"period":{"type":"object","required":["year","month","kind"],"properties":{"year":{"minimum":2020,"maximum":2099,"type":"number"},"month":{"minimum":1,"maximum":12,"type":"number"},"kind":{"anyOf":[{"const":"monthly","type":"string"},{"const":"quarterly","type":"string"}]}}}}}}}},"responses":{"200":{}}}},"/bff/tax/epo/generate":{"post":{"parameters":[],"operationId":"postBffTaxEpoGenerate","tags":["Tax"],"summary":"Build + archive an EPO XML; runs XSD validation, persists to core__tax_submission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind","period"],"properties":{"kind":{"description":"Which EPO XML to build: DPH přiznání, Kontrolní hlášení, or Souhrnné hlášení.","anyOf":[{"const":"dphdp3","type":"string"},{"const":"dphkh1","type":"string"},{"const":"dphshv","type":"string"}]},"period":{"type":"object","required":["year","month","kind"],"properties":{"year":{"minimum":2020,"maximum":2099,"type":"number"},"month":{"minimum":1,"maximum":12,"type":"number"},"kind":{"anyOf":[{"const":"monthly","type":"string"},{"const":"quarterly","type":"string"}]}}},"notes":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"isTest":{"default":false,"type":"boolean"}}}},"multipart/form-data":{"schema":{"type":"object","required":["kind","period"],"properties":{"kind":{"description":"Which EPO XML to build: DPH přiznání, Kontrolní hlášení, or Souhrnné hlášení.","anyOf":[{"const":"dphdp3","type":"string"},{"const":"dphkh1","type":"string"},{"const":"dphshv","type":"string"}]},"period":{"type":"object","required":["year","month","kind"],"properties":{"year":{"minimum":2020,"maximum":2099,"type":"number"},"month":{"minimum":1,"maximum":12,"type":"number"},"kind":{"anyOf":[{"const":"monthly","type":"string"},{"const":"quarterly","type":"string"}]}}},"notes":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"isTest":{"default":false,"type":"boolean"}}}},"text/plain":{"schema":{"type":"object","required":["kind","period"],"properties":{"kind":{"description":"Which EPO XML to build: DPH přiznání, Kontrolní hlášení, or Souhrnné hlášení.","anyOf":[{"const":"dphdp3","type":"string"},{"const":"dphkh1","type":"string"},{"const":"dphshv","type":"string"}]},"period":{"type":"object","required":["year","month","kind"],"properties":{"year":{"minimum":2020,"maximum":2099,"type":"number"},"month":{"minimum":1,"maximum":12,"type":"number"},"kind":{"anyOf":[{"const":"monthly","type":"string"},{"const":"quarterly","type":"string"}]}}},"notes":{"nullable":true,"anyOf":[{"type":"string"},{"type":"null"}]},"isTest":{"default":false,"type":"boolean"}}}}}},"responses":{"200":{}}}},"/bff/tax/epo/list":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"kind","required":false}],"operationId":"getBffTaxEpoList","tags":["Tax"],"summary":"List archived tax submissions.","responses":{"200":{}}}},"/bff/tax/vat-book/rows":{"get":{"parameters":[{"description":"Inclusive lower bound (YYYY-MM-DD).","schema":{"type":"string"},"in":"query","name":"from","required":true},{"description":"Exclusive upper bound (YYYY-MM-DD).","schema":{"type":"string"},"in":"query","name":"to","required":true},{"schema":{"type":"string"},"in":"query","name":"includeDrafts","required":false}],"operationId":"getBffTaxVat-bookRows","tags":["Tax"],"summary":"VAT book rows for the admin browser.","responses":{"200":{}}}},"/bff/tax/vat-book/pdf":{"get":{"parameters":[{"schema":{"type":"string"},"in":"query","name":"from","required":true},{"schema":{"type":"string"},"in":"query","name":"to","required":true},{"schema":{"type":"string"},"in":"query","name":"title","required":false},{"schema":{"type":"string"},"in":"query","name":"includeDrafts","required":false}],"operationId":"getBffTaxVat-bookPdf","tags":["Tax"],"summary":"Download the VAT book as a landscape A4 PDF.","responses":{"200":{}}}},"/bff/crm/aging-receivables":{"get":{"operationId":"getBffCrmAging-receivables","tags":["crm-dashboard"],"summary":"Aging of receivables","description":"Unpaid invoices grouped into 5 buckets (notDue, 1-30, 31-60, 61-90, 91+ days past due). Amounts are in base currency (CZK) so multi-currency organisations sum correctly.","responses":{"200":{}}}},"/bff/crm/aging-payables":{"get":{"operationId":"getBffCrmAging-payables","tags":["crm-dashboard"],"summary":"Aging of payables","description":"Same shape as /aging-receivables but over shop__purchase_invoice (what we owe vendors).","responses":{"200":{}}}},"/bff/crm/payment-health":{"get":{"parameters":[{"schema":{"type":"number","minimum":1,"maximum":60,"default":12},"in":"query","name":"monthsBack","required":false}],"operationId":"getBffCrmPayment-health","tags":["crm-dashboard"],"summary":"DSO + punctuality + payment-time histogram","description":"Days Sales Outstanding (amount-weighted), punctuality rate (% paid by due), median and p90 days-to-pay, and a 5-bucket histogram.","responses":{"200":{}}}},"/bff/crm/concentration":{"get":{"parameters":[{"schema":{"type":"number","minimum":1,"maximum":60,"default":12},"in":"query","name":"monthsBack","required":false}],"operationId":"getBffCrmConcentration","tags":["crm-dashboard"],"summary":"Customer concentration risk (Pareto)","description":"top1Share, top3Share, top5Share, Pareto count for the clients covering 80% of revenue, and a risk badge.","responses":{"200":{}}}},"/bff/crm/churn-risk":{"get":{"parameters":[{"schema":{"type":"number","minimum":1,"maximum":730,"default":60},"in":"query","name":"thresholdDays","required":false},{"schema":{"type":"number","minimum":1,"maximum":200,"default":25},"in":"query","name":"limit","required":false}],"operationId":"getBffCrmChurn-risk","tags":["crm-dashboard"],"summary":"Clients at risk of churn","description":"Clients whose last paid invoice is ≥ thresholdDays old (default 60). Sorted by lifetime revenue desc.","responses":{"200":{}}}},"/bff/crm/top-clients":{"get":{"parameters":[{"schema":{"type":"number","minimum":1,"maximum":60,"default":12},"in":"query","name":"monthsBack","required":false},{"schema":{"type":"number","minimum":1,"maximum":100,"default":10},"in":"query","name":"limit","required":false}],"operationId":"getBffCrmTop-clients","tags":["crm-dashboard"],"summary":"Top clients ranked by CZK revenue","description":"Multi-currency aware: sums `total_base` so a 1000 EUR invoice outranks a 20 000 CZK one.","responses":{"200":{}}}},"/bff/crm/top-vendors":{"get":{"parameters":[{"schema":{"type":"number","minimum":1,"maximum":60,"default":12},"in":"query","name":"monthsBack","required":false},{"schema":{"type":"number","minimum":1,"maximum":100,"default":10},"in":"query","name":"limit","required":false}],"operationId":"getBffCrmTop-vendors","tags":["crm-dashboard"],"summary":"Top vendors ranked by CZK costs","description":"Multi-currency aware: sums `total_base` on shop__purchase_invoice.","responses":{"200":{}}}},"/bff/crm/action-items":{"get":{"operationId":"getBffCrmAction-items","tags":["crm-dashboard"],"summary":"List the operator's action items (Akce pro tebe)","description":"Composed from overdue receivables, overdue payables and churn risk. Dismissed categories are filtered out; historical-baseline dismissals only surface NEW items.","responses":{"200":{}}}},"/bff/crm/action-items/dismiss":{"post":{"parameters":[],"operationId":"postBffCrmAction-itemsDismiss","tags":["crm-dashboard"],"summary":"Dismiss an action-item category","description":"Modes: day (24h), week (7d), forever, historical (snapshot current item IDs, only show NEW ones).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["itemType","mode"],"properties":{"itemType":{"anyOf":[{"const":"overdue_invoices","type":"string"},{"const":"overdue_payables","type":"string"},{"const":"churn_risk","type":"string"},{"const":"tax_deadline","type":"string"}]},"mode":{"anyOf":[{"const":"day","type":"string"},{"const":"week","type":"string"},{"const":"forever","type":"string"},{"const":"historical","type":"string"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["itemType","mode"],"properties":{"itemType":{"anyOf":[{"const":"overdue_invoices","type":"string"},{"const":"overdue_payables","type":"string"},{"const":"churn_risk","type":"string"},{"const":"tax_deadline","type":"string"}]},"mode":{"anyOf":[{"const":"day","type":"string"},{"const":"week","type":"string"},{"const":"forever","type":"string"},{"const":"historical","type":"string"}]}}}},"text/plain":{"schema":{"type":"object","required":["itemType","mode"],"properties":{"itemType":{"anyOf":[{"const":"overdue_invoices","type":"string"},{"const":"overdue_payables","type":"string"},{"const":"churn_risk","type":"string"},{"const":"tax_deadline","type":"string"}]},"mode":{"anyOf":[{"const":"day","type":"string"},{"const":"week","type":"string"},{"const":"forever","type":"string"},{"const":"historical","type":"string"}]}}}}}},"responses":{"200":{}}}},"/bff/crm/action-items/restore":{"post":{"parameters":[],"operationId":"postBffCrmAction-itemsRestore","tags":["crm-dashboard"],"summary":"Restore a previously dismissed action-item category","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["itemType"],"properties":{"itemType":{"anyOf":[{"const":"overdue_invoices","type":"string"},{"const":"overdue_payables","type":"string"},{"const":"churn_risk","type":"string"},{"const":"tax_deadline","type":"string"}]}}}},"multipart/form-data":{"schema":{"type":"object","required":["itemType"],"properties":{"itemType":{"anyOf":[{"const":"overdue_invoices","type":"string"},{"const":"overdue_payables","type":"string"},{"const":"churn_risk","type":"string"},{"const":"tax_deadline","type":"string"}]}}}},"text/plain":{"schema":{"type":"object","required":["itemType"],"properties":{"itemType":{"anyOf":[{"const":"overdue_invoices","type":"string"},{"const":"overdue_payables","type":"string"},{"const":"churn_risk","type":"string"},{"const":"tax_deadline","type":"string"}]}}}}}},"responses":{"200":{}}}},"/bff/crm/action-items/restore-all":{"post":{"operationId":"postBffCrmAction-itemsRestore-all","tags":["crm-dashboard"],"summary":"Restore all dismissals for the current member","responses":{"200":{}}}},"/bff/cron-run/summary":{"get":{"operationId":"getBffCron-runSummary","tags":["admin-observability"],"summary":"One row per cron script — latest run + 24h aggregate","description":"Powers the health-badge row on /admin/cron-jobs.","responses":{"200":{}}}},"/bff/cron-run/list":{"get":{"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":80},"in":"query","name":"script","required":false},{"schema":{"type":"number","minimum":1,"maximum":1000,"default":200},"in":"query","name":"limit","required":false}],"operationId":"getBffCron-runList","tags":["admin-observability"],"summary":"Recent cron runs","description":"Newest-first. Pass `script` to drill into a single handler.","responses":{"200":{}}}}},"components":{"schemas":{}}}