# Generated by `php artisan biklo:partner-docs openapi` — do not edit by hand.
# Endpoint copy lives in config/partner_docs.php; the routes decide what exists.
openapi: '3.0.3'
info:
  title: 'Biklo Partner API'
  version: 'v1'
  description: |-
    The Biklo Partner API, for company sellers and the platforms they run on.

    Authentication: `Authorization: Bearer bk_live_…`. The environment is part of the key, so a test key presented to production is a 401 rather than a surprise.

    Conventions: money is always MINOR units plus a currency (12550 = 125.50); timestamps are ISO 8601 UTC; lists are cursor-paginated and accept `updated_since` for incremental sync; every response carries `X-Request-Id`, which is the id to quote to support. Send an `Idempotency-Key` header on any write and a retry replays the first response instead of acting twice.
  contact:
    name: 'Biklo integrations'
    url: 'https://developers.biklo.com'
servers:
  - url: 'https://api.biklo.com'
    description: 'Production — bk_live_ keys'
  - url: 'https://sandbox-api.biklo.com'
    description: 'Sandbox — bk_test_ keys'
tags:
  - name: 'Getting started'
    description: 'Your key, and what it may do. Start here.'
  - name: 'Catalog'
    description: 'The reference data you map your own products against.'
  - name: 'Products'
    description: 'Listings: create, update, price, stock, images, variants.'
  - name: 'Orders'
    description: 'Accepting, packing, labelling and shipping what you sell.'
  - name: 'Threads'
    description: 'Private conversations with buyers.'
  - name: 'Questions'
    description: 'Public questions on your listings.'
  - name: 'Wallet'
    description: 'Balances, the ledger, and withdrawing to your bank.'
  - name: 'Invoices'
    description: 'The fee invoices Biklo issues to you.'
  - name: 'Fee-liabilities'
    description: 'What you owe per order, before an invoice exists.'
  - name: 'Notifications'
    description: 'The emails and SMS we sent about your orders.'
  - name: 'Company'
    description: 'Your shop profile, delivery bands and pickup points.'
  - name: 'Locations'
    description: 'Countries, counties, cities and postal codes.'
  - name: 'Webhooks'
    description: 'Subscribe once instead of polling.'
  - name: 'Sandbox test data'
    description: 'Fabricate orders, messages and questions to test against.'
  - name: 'Addresses'
    description: ''
  - name: 'Customers'
    description: ''
components:
  securitySchemes:
    bearerAuth:
      type: 'http'
      scheme: 'bearer'
      description: 'Your API key: `Authorization: Bearer bk_live_…`. The environment is part of the key, so a test key on production is a 401.'
  schemas:
    Error:
      type: 'object'
      properties:
        error:
          type: 'object'
          properties:
            code:
              type: 'string'
              example: 'missing_required_attribute'
            message:
              type: 'string'
            field:
              type: 'string'
              nullable: true
            request_id:
              type: 'string'
              example: 'req_01j9c4xk2m'
security:
  - bearerAuth: []
paths:
  /v1/addresses/{id}:
    delete:
      summary: 'Delete an address'
      description: |-
        Refused with `409 last_address` if it is your only one — every future order would lose its origin while your listings stayed up. Refused with `409 default_address` if it is the default and you have others; make another one default first.

        Required scope: `company.write`.
      operationId: 'deleteV1AddressesId'
      tags:
        - 'Addresses'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                deleted: true
                id: 4813
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.write'
    get:
      summary: 'Get one address'
      description: |-
        A single address of yours. `404` for an id that is not on your account.

        Required scope: `company.read`.
      operationId: 'getV1AddressesId'
      tags:
        - 'Addresses'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 4812
                street: 'Bulevardul Decebal 14'
                postal_code: '200001'
                city:
                  id: 1
                  name: 'Craiova'
                county:
                  id: 1
                  name: 'Dolj'
                country_code: 'RO'
                company_name: 'Bike Shop SRL'
                company_vat_code: 'RO12345678'
                company_reg_no: 'J16/123/2020'
                is_default: true
                created_at: '2026-09-14T09:12:44+00:00'
                updated_at: '2026-09-14T09:12:44+00:00'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.read'
    put:
      summary: 'Update an address'
      description: |-
        Partial — send only what changes. The result is re-validated as a whole address, not just the fields you sent: moving the city without moving the postal code is rejected, because the stored code no longer belongs to the new county. Returns the complete address.

        Required scope: `company.write`.
      operationId: 'putV1AddressesId'
      tags:
        - 'Addresses'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 4812
                street: 'Bulevardul Decebal 16'
                postal_code: '200001'
                city:
                  id: 1
                  name: 'Craiova'
                county:
                  id: 1
                  name: 'Dolj'
                country_code: 'RO'
                company_name: 'Bike Shop SRL'
                company_vat_code: 'RO12345678'
                company_reg_no: 'J16/123/2020'
                is_default: true
                created_at: '2026-09-14T09:12:44+00:00'
                updated_at: '2026-09-14T11:03:02+00:00'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              street: 'Bulevardul Decebal 16'
      security:
        - bearerAuth:
            - 'company.write'
  /v1/company/pickup-points/{id}:
    delete:
      summary: 'Delete a pickup point'
      description: |-
        Refused with 409 if it is the default and you have others — make another one default first, so drop-shipped orders never lose their origin.

        Required scope: `company.write`.
      operationId: 'deleteV1CompanyPickupPointsId'
      tags:
        - 'Company'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                deleted: true
                id: 11
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.write'
    put:
      summary: 'Update a pickup point'
      description: |-
        Partial — send only what changes. Any address field you do send is re-validated.

        Required scope: `company.write`.
      operationId: 'putV1CompanyPickupPointsId'
      tags:
        - 'Company'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 11
                label: 'Barcelona main warehouse'
                type: 'warehouse'
                address:
                  street: 'Carrer Gran 42'
                  city: 'Barcelona'
                  county: 'Barcelona'
                  postal_code: '08001'
                  country_code: 'ES'
                contact:
                  phone: '+34600000000'
                  email: 'wh@example.com'
                is_default: true
                is_active: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              label: 'Barcelona main warehouse'
      security:
        - bearerAuth:
            - 'company.write'
  /v1/product-groups/{externalGroupId}/products/{productId}:
    delete:
      summary: 'Remove one variant'
      description: |-
        The group survives while two or more products remain.

        Required scope: `products.write`.
      operationId: 'deleteV1ProductGroupsExternalGroupIdProductsProductId'
      tags:
        - 'Products'
      parameters:
        - name: 'externalGroupId'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Your own group id'
        - name: 'productId'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Product id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                external_group_id: 'ERP-1001-GROUP'
                count: 1
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/{id}/images/{imageId}:
    delete:
      summary: 'Delete an image'
      description: |-
        Removes the row and, for an uploaded file, the file itself.

        Required scope: `products.write`.
      operationId: 'deleteV1ProductsIdImagesImageId'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
        - name: 'imageId'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Image id from the product payload'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.write'
  /v1/webhooks/{id}:
    delete:
      summary: 'Delete an endpoint'
      description: |-
        Stops delivery immediately.

        Required scope: `webhooks.manage`.
      operationId: 'deleteV1WebhooksId'
      tags:
        - 'Webhooks'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                deleted: true
                id: 1
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'webhooks.manage'
    put:
      summary: 'Edit an endpoint'
      description: |-
        Change what an endpoint subscribes to, or replace its custom headers, WITHOUT reissuing its signing secret. Rotating a gateway credential should not force a redeploy of your signature verification — deleting and re-registering would, because a new endpoint gets a new secret. Send `events`, `headers`, or both; anything you leave out is untouched. Sending neither is `nothing_to_update` (400).

        Required scope: `webhooks.manage`.
      operationId: 'putV1WebhooksId'
      tags:
        - 'Webhooks'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 1
                url: 'https://erp.example.com/hooks/biklo'
                events:
                  - 'order.created'
                is_active: true
                consecutive_failures: 0
                disabled_at: null
                headers:
                  - name: 'X-Api-Key'
                    preview: 'the ••••••••'
                secret_prefix: 'whsec_64Ky4…'
                created_at: '2026-09-21T09:14:03Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              headers:
                - name: 'X-Api-Key'
                  value: 'the rotated value'
      security:
        - bearerAuth:
            - 'webhooks.manage'
  /v1/addresses:
    get:
      summary: 'List your addresses'
      description: |-
        Your own addresses, the default one first. The default is where every order ships FROM — we snapshot it as the parcel origin when an order is placed — and it is also the city, county and street a product is published with when you do not send a `city_id`. An account with no address cannot fulfil anything, so this is the first call a new integration should make.

        Required scope: `company.read`.
      operationId: 'getV1Addresses'
      tags:
        - 'Addresses'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                data:
                  - id: 4812
                    street: 'Bulevardul Decebal 14'
                    postal_code: '200001'
                    city:
                      id: 1
                      name: 'Craiova'
                    county:
                      id: 1
                      name: 'Dolj'
                    country_code: 'RO'
                    company_name: 'Bike Shop SRL'
                    company_vat_code: 'RO12345678'
                    company_reg_no: 'J16/123/2020'
                    is_default: true
                    created_at: '2026-09-14T09:12:44+00:00'
                    updated_at: '2026-09-14T09:12:44+00:00'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.read'
    post:
      summary: 'Create an address'
      description: |-
        Adds an address you can ship from. **Your first address automatically becomes the default**, whatever you send in `is_default` — a seller with one address and no default is a seller who cannot ship. The street must contain a number and the postal code must fit both the country format and the county the city is in; a courier rejects the shipment otherwise, so we reject it here instead.

        Required scope: `company.write`.
      operationId: 'postV1Addresses'
      tags:
        - 'Addresses'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 4812
                street: 'Bulevardul Decebal 14'
                postal_code: '200001'
                city:
                  id: 1
                  name: 'Craiova'
                county:
                  id: 1
                  name: 'Dolj'
                country_code: 'RO'
                company_name: 'Bike Shop SRL'
                company_vat_code: 'RO12345678'
                company_reg_no: 'J16/123/2020'
                is_default: true
                created_at: '2026-09-14T09:12:44+00:00'
                updated_at: '2026-09-14T09:12:44+00:00'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              city_id: 1
              street: 'Bulevardul Decebal 14'
              postal_code: '200001'
              is_default: true
      security:
        - bearerAuth:
            - 'company.write'
  /v1/categories:
    get:
      summary: 'List the category tree'
      description: |-
        The whole tree in one response — an ERP caches it. `id` is the Romanian master id and never changes between languages; `tid` is the row in the language you asked for. Only leaves accept listings. Each category carries its `commission` — the rate Biklo charges a company seller here, inherited down the tree — so you can set margins before listing rather than inferring the fee from a completed order. `max_amount: null` means UNCAPPED.

        Required scope: `catalog.read`.
      operationId: 'getV1Categories'
      tags:
        - 'Catalog'
      parameters:
        - name: 'lang'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'ro'
          description: 'Language code from GET /v1/languages'
        - name: 'parent_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Only the children of this category'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                language: 'ro'
                count: 210
                data:
                  - id: 4291
                    tid: 4291
                    parent_id: 5
                    name: 'Hardtail'
                    slug: 'hardtail'
                    depth: 2
                    is_leaf: true
                    shipping:
                      can_be_shipped: true
                      default_weight_kg: 14
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/categories/{id}/attributes:
    get:
      summary: 'Attributes for a category'
      description: |-
        The attributes a listing in this category must carry, including everything inherited from parent categories. Nothing can be published until the required ones are supplied — send these ids back in `attributes` when creating a product.

        Required scope: `catalog.read`.
      operationId: 'getV1CategoriesIdAttributes'
      tags:
        - 'Catalog'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
        - name: 'lang'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'ro'
          description: 'Language for names and option values'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                category_id: 4291
                language: 'ro'
                count: 9
                data:
                  - id: 32
                    tid: 32
                    name: 'Brand'
                    slug: 'brand'
                    type: 'checkbox_multiple'
                    required: true
                    options:
                      - id: 226
                        tid: 226
                        value: 'Avid'
                        slug: 'avid'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/company:
    get:
      summary: 'Your company profile'
      description: |-
        The public shop profile, the settings that change how your orders behave, and the countries you sell into. Returns 403 `not_a_company` for a private seller.

        Required scope: `company.read`.
      operationId: 'getV1Company'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                company:
                  id: 9000010
                  name: 'Example Bikes SL'
                  business_name: 'Example Bikes SL'
                  title: 'Example Bikes'
                  description: '<p>Mountain bike apparel from Barcelona.</p>'
                  logo_url: null
                  cover_url: null
                  contact:
                    person: 'Sandbox Contact'
                    email: 'contact@example.com'
                    phone: '0700000000'
                    address: 'Carrer Gran 42, Barcelona'
                  links:
                    website: 'https://example.com'
                    marketplace: null
                    google_maps: null
                    facebook: null
                    instagram: null
                    linkedin: null
                    tiktok: null
                    youtube: null
                  is_active: true
                  onboarding_completed_at: '2026-08-02T09:14:00Z'
                settings:
                  allow_price_negotiation: true
                  fees:
                    absorb_platform_fee: false
                    absorb_shipping_local: true
                    absorb_shipping_international: false
                    absorption_is_locked: true
                  shipping:
                    can_ship_with_us: true
                selling_countries:
                  - country_id: 70
                    code: 'ES'
                    name: 'España'
                    currency: 'EUR'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.read'
    put:
      summary: 'Update the profile'
      description: |-
        Presentation fields only: description, contact details and links. Your legal identity — business name, fiscal codes, IBAN — is not editable here; it appears on invoices and changes through verification in the seller dashboard. Sending a field outside the editable set returns 400 with the list of what is allowed.

        Required scope: `company.write`.
      operationId: 'putV1Company'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                company:
                  id: 9000010
                  name: 'Example Bikes SL'
                  business_name: 'Example Bikes SL'
                  title: 'Example Bikes'
                  description: '<p>Mountain bike apparel from Barcelona.</p>'
                  logo_url: null
                  cover_url: null
                  contact:
                    person: 'Sandbox Contact'
                    email: 'contact@example.com'
                    phone: '0700000000'
                    address: 'Carrer Gran 42, Barcelona'
                  links:
                    website: 'https://example.com'
                    marketplace: null
                    google_maps: null
                    facebook: null
                    instagram: null
                    linkedin: null
                    tiktok: null
                    youtube: null
                  is_active: true
                  onboarding_completed_at: '2026-08-02T09:14:00Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              description: '<p>Mountain bike apparel from Barcelona.</p>'
              website: 'https://example.com'
              phone: '+34600000000'
      security:
        - bearerAuth:
            - 'company.write'
  /v1/company/documents:
    get:
      summary: 'Verification documents'
      description: |-
        Status only — whether each filed document was accepted, and why not if it was rejected. The files themselves are identity papers and are not downloadable through the API.

        Required scope: `company.read`.
      operationId: 'getV1CompanyDocuments'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                data:
                  - id: 3
                    type: 'company_registration'
                    file_name: 'registro.pdf'
                    status: 'approved'
                    reject_reason: null
                    uploaded_at: '2026-08-01T10:00:00Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.read'
  /v1/company/financial-data:
    get:
      summary: 'Fiscal and banking details'
      description: |-
        Read-only. One entry per selling country, because a company selling into three countries may invoice from three legal entities. These appear on invoices and are changed in the seller dashboard, where they go through verification.

        Required scope: `company.read`.
      operationId: 'getV1CompanyFinancialData'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                data:
                  - id: 1
                    country_code: 'ES'
                    business_name: 'Example Bikes SL'
                    registration_number: 'B12345678'
                    vat_id: 'ESB12345678'
                    iban: 'ES91…'
                    address:
                      street: 'Carrer Gran 42'
                      city: 'Barcelona'
                      postal_code: '08001'
                      country_code: 'ES'
                    is_default: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.read'
  /v1/company/pickup-points:
    get:
      summary: 'List pickup points'
      description: |-
        The addresses a courier collects from. A pickup point is also the origin for drop-shipped orders and the address returns travel back to.

        Required scope: `company.read`.
      operationId: 'getV1CompanyPickupPoints'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                data:
                  - id: 11
                    label: 'Barcelona warehouse'
                    type: 'warehouse'
                    address:
                      street: 'Carrer Gran 42'
                      city: 'Barcelona'
                      county: 'Barcelona'
                      postal_code: '08001'
                      country_code: 'ES'
                    contact:
                      phone: '+34600000000'
                      email: 'wh@example.com'
                    is_default: true
                    is_active: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.read'
    post:
      summary: 'Create a pickup point'
      description: |-
        Address rules apply exactly as they do for a delivery: the street must contain a number, the postal code must fit the country and county, and the country must be one you sell into. Get `city_id` from GET /v1/geo/cities. The first point you create becomes the default.

        Required scope: `company.write`.
      operationId: 'postV1CompanyPickupPoints'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 11
                label: 'Barcelona warehouse'
                type: 'warehouse'
                address:
                  street: 'Carrer Gran 42'
                  city: 'Barcelona'
                  county: 'Barcelona'
                  postal_code: '08001'
                  country_code: 'ES'
                contact:
                  phone: '+34600000000'
                  email: 'wh@example.com'
                is_default: true
                is_active: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              label: 'Barcelona warehouse'
              country_code: 'ES'
              city_id: 665904
              street: 'Carrer Gran 42'
              postal_code: '08001'
              contact_phone: '+34600000000'
              contact_email: 'warehouse@example.com'
      security:
        - bearerAuth:
            - 'company.write'
  /v1/company/selling-countries:
    get:
      summary: 'Countries you sell into'
      description: |-
        You can only add pickup points, absorption bands and listings for these. Changing the list is a commercial decision made in the dashboard.

        Required scope: `company.read`.
      operationId: 'getV1CompanySellingCountries'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                data:
                  - country_id: 70
                    code: 'ES'
                    name: 'España'
                    currency: 'EUR'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.read'
  /v1/company/shipping-absorption:
    get:
      summary: 'Read your delivery bands'
      description: |-
        Per destination country AND per parcel size: above a threshold you pay the courier, below it the buyer pays at checkout. Bands compare the SELLER-GROUP subtotal — shipping is one charge per seller per order — not a single product's price. Each destination carries TWO independent sets, one per `parcel_tier`, because the courier prices them very differently: a small RO→HU parcel costs about 26 RON and a large one about 539. The response includes `band_rules`, which is worth reading before you write.

        Required scope: `company.read`.
      operationId: 'getV1CompanyShippingAbsorption'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                sets:
                  - country_code: 'HU'
                    scope: 'international'
                    parcel_tier: 'small'
                    currency: 'EUR'
                    bands:
                      - min_amount: 0
                        max_amount: 50000
                        absorbs: false
                      - min_amount: 50000
                        max_amount: null
                        absorbs: true
                  - country_code: 'HU'
                    scope: 'international'
                    parcel_tier: 'large'
                    currency: 'EUR'
                    bands:
                      - min_amount: 0
                        max_amount: null
                        absorbs: false
                parcel_tiers:
                  small: 'Accessories and small parcels — billed on the small-courier tariff.'
                  large: 'Bikes, large and extra-large items — the expensive tariff.'
                note: 'Bands compare the seller-group subtotal, in minor units. A band with absorbs=false means the buyer pays delivery at checkout. Each destination has a SEPARATE set per parcel_tier — writing one does not touch the other.'
                band_rules:
                  bands_are_half_open: 'Each band covers [min_amount, max_amount) — max is exclusive.'
                  must_be_contiguous: 'A band''s max_amount must equal the next band''s min_amount. Not max-1.'
                  first_band_starts_at_zero: true
                  last_band_is_open_ended: 'The last band must have max_amount: null.'
                  example:
                    country_code: 'RO'
                    parcel_tier: 'small'
                    currency: 'RON'
                    bands:
                      - min_amount: 0
                        max_amount: 50000
                        absorbs: false
                      - min_amount: 50000
                        max_amount: null
                        absorbs: true
                selling_countries:
                  - country_id: 70
                    code: 'ES'
                    name: 'España'
                    currency: 'EUR'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.read'
    put:
      summary: 'Set your delivery bands'
      description: |-
        Replaces the whole set for one country, scope AND parcel_tier. `parcel_tier` is REQUIRED: each destination carries two independent sets and writing one does not touch the other, so a default would quietly rewrite the small-parcel bands while you believed you had set both. Bands are half-open [min, max): a band's `max_amount` must EQUAL the next band's `min_amount` — writing 49999 then 50000 leaves a one-cent hole and the set is refused. The first band starts at 0, the last has `max_amount: null`. Amounts are in minor units. An empty `bands` array means you absorb delivery on everything.

        Required scope: `company.write`.
      operationId: 'putV1CompanyShippingAbsorption'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                sets:
                  - country_code: 'HU'
                    scope: 'international'
                    parcel_tier: 'small'
                    currency: 'EUR'
                    bands:
                      - min_amount: 0
                        max_amount: 50000
                        absorbs: false
                      - min_amount: 50000
                        max_amount: null
                        absorbs: true
                  - country_code: 'HU'
                    scope: 'international'
                    parcel_tier: 'large'
                    currency: 'EUR'
                    bands:
                      - min_amount: 0
                        max_amount: null
                        absorbs: false
                parcel_tiers:
                  small: 'Accessories and small parcels — billed on the small-courier tariff.'
                  large: 'Bikes, large and extra-large items — the expensive tariff.'
                note: 'Bands compare the seller-group subtotal, in minor units. A band with absorbs=false means the buyer pays delivery at checkout. Each destination has a SEPARATE set per parcel_tier — writing one does not touch the other.'
                band_rules:
                  bands_are_half_open: 'Each band covers [min_amount, max_amount) — max is exclusive.'
                  must_be_contiguous: 'A band''s max_amount must equal the next band''s min_amount. Not max-1.'
                  first_band_starts_at_zero: true
                  last_band_is_open_ended: 'The last band must have max_amount: null.'
                  example:
                    country_code: 'RO'
                    parcel_tier: 'small'
                    currency: 'RON'
                    bands:
                      - min_amount: 0
                        max_amount: 50000
                        absorbs: false
                      - min_amount: 50000
                        max_amount: null
                        absorbs: true
                selling_countries:
                  - country_id: 70
                    code: 'ES'
                    name: 'España'
                    currency: 'EUR'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              country_code: 'ES'
              scope: 'local'
              parcel_tier: 'large'
              currency: 'EUR'
              bands:
                - min_amount: 0
                  max_amount: 50000
                  absorbs: false
                - min_amount: 50000
                  max_amount: null
                  absorbs: true
      security:
        - bearerAuth:
            - 'company.write'
  /v1/countries:
    get:
      summary: 'Selling countries'
      description: |-
        Countries the marketplace sells in, with the currency each uses.

        Required scope: `catalog.read`.
      operationId: 'getV1Countries'
      tags:
        - 'Catalog'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 32
                data:
                  - code: 'RO'
                    name: 'Romania'
                    currency: 'RON'
                    phone_prefix: '40'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/currencies:
    get:
      summary: 'Currencies'
      description: |-
        `decimals` is the exponent for the minor units every amount in this API uses: 12550 with decimals 2 is 125.50.

        Required scope: `catalog.read`.
      operationId: 'getV1Currencies'
      tags:
        - 'Catalog'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 170
                data:
                  - code: 'RON'
                    name: 'Romanian Leu'
                    symbol: 'lei'
                    decimals: 2
                    symbol_before_amount: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/customers:
    get:
      summary: 'List your customers'
      description: |-
        Everyone who has ordered from you, keyed on the buyer rather than the order, with the billing details from their most recent order. This is what `POST /v1/orders/{id}/invoice` never gave you: the order payload carries a delivery block because a courier needs a city and a postcode, and an invoice needs a street — and, for a business buyer, a company name and a VAT number. You only ever see buyers you have actually sold to.

        Required scope: `customers.read`.
      operationId: 'getV1Customers'
      tags:
        - 'Customers'
      parameters:
        - name: 'updated_since'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'ISO 8601. A customer counts as changed when any of their orders did — a status moving to delivered is usually what makes you want to invoice.'
        - name: 'q'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Match on name or email.'
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor from the previous page'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: 98853
                data:
                  - id: 9000001
                    name: 'John Doe'
                    email: 'john.doe@example.com'
                    phone: '+40700000000'
                    orders_count: 3
                    first_order_at: '2026-03-02T11:40:19Z'
                    last_order_at: '2026-09-08T14:08:52Z'
                    billing:
                      address_line: 'Str. Exemplu 12'
                      city: 'Brasov'
                      county: 'Brasov'
                      postal_code: '500002'
                      country_code: 'RO'
                      country: 'România'
                      is_company: true
                      company:
                        name: 'Example Bike Shop SRL'
                        vat_code: 'RO12345678'
                        registration_no: 'J16/123/2020'
                      is_live: true
                      delivered_to_locker: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'customers.read'
  /v1/customers/{id}:
    get:
      summary: 'One customer and their orders'
      description: |-
        A buyer, their billing details, and every order they have placed with you — each flagged with whether it already carries an invoice, so a nightly job can pick up exactly the ones it has not billed. A buyer who has never ordered from you is `customer_not_found` (404), which is also what stops you reaching anyone else's customers.

        Required scope: `customers.read`.
      operationId: 'getV1CustomersId'
      tags:
        - 'Customers'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 9000001
                name: 'John Doe'
                email: 'john.doe@example.com'
                phone: '+40700000000'
                orders_count: 2
                first_order_at: '2026-03-02T11:40:19Z'
                last_order_at: '2026-09-08T14:08:52Z'
                billing:
                  address_line: 'Str. Exemplu 12'
                  city: 'Brasov'
                  county: 'Brasov'
                  postal_code: '500002'
                  country_code: 'RO'
                  country: 'România'
                  is_company: true
                  company:
                    name: 'Example Bike Shop SRL'
                    vat_code: 'RO12345678'
                    registration_no: 'J16/123/2020'
                  is_live: true
                  delivered_to_locker: false
                orders:
                  - id: 690
                    reference: 'ERP-1042'
                    status: 'delivered'
                    total:
                      amount: 4698
                      currency: 'RON'
                    has_invoice: false
                    created_at: '2026-09-08T14:08:52Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'customers.read'
  /v1/fee-liabilities:
    get:
      summary: 'Fees you owe, per order'
      description: |-
        A liability exists from the moment an order settles and is invoiced later in a batch, so this is where most of a current month lives — before any document exists. `owed_amount` and `charged_amount` differ whenever a liability settled PARTIALLY; reading one and assuming the other is how books stop balancing.

        Required scope: `wallet.read`.
      operationId: 'getV1FeeLiabilities'
      tags:
        - 'Fee-liabilities'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
        - name: 'status'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'settled'
          description: 'pending, settled or cancelled'
        - name: 'order_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '721'
          description: 'Only liabilities for one order'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 2
                next_cursor: null
                data:
                  - id: 17
                    order_id: 721
                    currency: 'RON'
                    owed_amount: 500
                    charged_amount: 0
                    written_off_amount: 0
                    platform_fee_amount: 500
                    shipping_fee_amount: 0
                    status: 'pending'
                    settled_at: null
                    invoice: null
                  - id: 15
                    order_id: 718
                    currency: 'RON'
                    owed_amount: 3050
                    charged_amount: 2700
                    written_off_amount: 350
                    platform_fee_amount: 1800
                    shipping_fee_amount: 1250
                    status: 'settled'
                    settled_at: '2026-09-12T08:09:40Z'
                    invoice:
                      series: 'RO_BK_COM'
                      number: '0524'
                      pdf_url: '/v1/invoices/0524/pdf?series=RO_BK_COM'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
  /v1/geo/address-rules:
    get:
      summary: 'Address validation rules'
      description: |-
        What we enforce when an address is saved, published so you can validate before sending and show your own users a useful message instead of a rejected order.

        Required scope: `catalog.read`.
      operationId: 'getV1GeoAddressRules'
      tags:
        - 'Locations'
      parameters:
        - name: 'country'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'RO'
          description: 'ISO country code — required'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                country_code: 'RO'
                street:
                  min_length: 5
                  max_length: 50
                  must_contain_digit: true
                postal_code:
                  pattern: '/^\\d{6}$/'
                  example: '500123'
                  validated_by_county_prefix: true
                required_fields:
                  - 'country_code'
                  - 'county_id'
                  - 'city_id'
                  - 'address'
                  - 'postal_code'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/geo/cities:
    get:
      summary: 'Search cities'
      description: |-
        Cursor-paginated and always filtered — the table holds 727k rows, so an unfiltered request is refused. Search covers both the local script and the latin form: `q=Sofia` finds `София`.

        Required scope: `catalog.read`.
      operationId: 'getV1GeoCities'
      tags:
        - 'Locations'
      parameters:
        - name: 'country'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'RO'
          description: 'ISO country code'
        - name: 'county_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Restrict to one county'
        - name: 'q'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'craio'
          description: 'Name prefix, either script'
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor from the previous page'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 1
                    name: 'Craiova'
                    latin_name: 'Craiova'
                    county:
                      id: 1
                      name: 'Dolj'
                      code: 'DJ'
                    latitude: 44.33
                    longitude: 23.82
                    is_capital: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/geo/cities/{id}:
    get:
      summary: 'One city, with postal codes'
      description: |-
        The postal codes are SUGGESTIONS for autofill. A code missing from this list is not invalid — roughly 7.5% of real codes are absent from our source, so never reject on absence.

        Required scope: `catalog.read`.
      operationId: 'getV1GeoCitiesId'
      tags:
        - 'Locations'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 1
                name: 'Craiova'
                county:
                  id: 1
                  name: 'Dolj'
                  code: 'DJ'
                country:
                  code: 'RO'
                  name: 'Romania'
                postal_codes:
                  - '200008'
                  - '200009'
                  - '200010'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/geo/counties:
    get:
      summary: 'Counties of a country'
      description: |-
        The second level of every address. `postal_prefixes` lists the code prefixes valid for that county where we enforce the rule (Romania today).

        Required scope: `catalog.read`.
      operationId: 'getV1GeoCounties'
      tags:
        - 'Locations'
      parameters:
        - name: 'country'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'RO'
          description: 'ISO country code — required'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                country: 'RO'
                count: 42
                data:
                  - id: 1
                    code: 'DJ'
                    name: 'Dolj'
                    latin_name: 'Dolj'
                    country_code: 'RO'
                    postal_prefixes:
                      - '20'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/geo/countries:
    get:
      summary: 'Countries (address taxonomy)'
      description: |-
        Countries for building an address. By default only the ones we sell in; pass `all=1` for every country we hold.

        Required scope: `catalog.read`.
      operationId: 'getV1GeoCountries'
      tags:
        - 'Locations'
      parameters:
        - name: 'all'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: '1 to include countries we do not sell in'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 32
                data:
                  - id: 190
                    code: 'RO'
                    name: 'Romania'
                    currency: 'RON'
                    phone_prefix: '40'
                    is_active: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/geo/subdivisions:
    get:
      summary: 'Sub-county areas'
      description: |-
        Sectors, districts and municipalities inside a county — what couriers often need for large cities.

        Required scope: `catalog.read`.
      operationId: 'getV1GeoSubdivisions'
      tags:
        - 'Locations'
      parameters:
        - name: 'county_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '1'
          description: 'Required unless q is given'
        - name: 'q'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Name prefix'
        - name: 'level'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Subdivision depth'
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 12
                    county_id: 39
                    name: 'Sectorul 3'
                    latin_name: 'Sectorul 3'
                    level: 1
                    parent_id: null
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/invoices:
    get:
      summary: 'Fee invoices issued to you'
      description: |-
        When your company absorbs the platform commission or the delivery, the buyer is not charged it — Biklo withholds it at payout and invoices you. These are those invoices. One covers SEVERAL orders, because liabilities are raised per order and invoiced in batches at settlement. `written_off_amount` is what Biklo gave up when the absorbed fees exceeded the order itself; you were never charged it, and it is on the document because it happened. `is_sandbox` marks a generated document with an SBX_ series, stamped NOT A FISCAL DOCUMENT.

        Required scope: `wallet.read`.
      operationId: 'getV1Invoices'
      tags:
        - 'Invoices'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
        - name: 'issued_from'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '2026-09-01T00:00:00Z'
          description: 'Issued on or after'
        - name: 'issued_to'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '2026-09-30T23:59:59Z'
          description: 'Issued on or before'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 'RO_BK_COM/0524'
                    series: 'RO_BK_COM'
                    number: '0524'
                    currency: 'RON'
                    total_amount: 3950
                    platform_fee_amount: 2100
                    shipping_fee_amount: 1850
                    written_off_amount: 350
                    orders_count: 2
                    issued_at: '2026-09-12T08:10:59Z'
                    pdf_url: '/v1/invoices/0524/pdf?series=RO_BK_COM'
                    is_sandbox: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
  /v1/invoices/{number}:
    get:
      summary: 'One invoice, with the orders behind it'
      description: |-
        Pass `series` when a number could exist in more than one — a number is only unique within its series. `lines` breaks the invoice down per order, with what was owed, what was actually charged, and what was written off.

        Required scope: `wallet.read`.
      operationId: 'getV1InvoicesNumber'
      tags:
        - 'Invoices'
      parameters:
        - name: 'number'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Path parameter'
        - name: 'series'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'RO_BK_COM'
          description: 'Required when the number is ambiguous'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  id: 'RO_BK_COM/0524'
                  series: 'RO_BK_COM'
                  number: '0524'
                  currency: 'RON'
                  total_amount: 3950
                  platform_fee_amount: 2100
                  shipping_fee_amount: 1850
                  written_off_amount: 350
                  orders_count: 2
                  issued_at: '2026-09-12T08:10:59Z'
                  pdf_url: '/v1/invoices/0524/pdf?series=RO_BK_COM'
                  is_sandbox: false
                  lines:
                    - id: 15
                      order_id: 721
                      currency: 'RON'
                      owed_amount: 3050
                      charged_amount: 3050
                      written_off_amount: 0
                      platform_fee_amount: 1800
                      shipping_fee_amount: 1250
                      status: 'settled'
                      settled_at: '2026-09-12T08:09:40Z'
                      invoice:
                        series: 'RO_BK_COM'
                        number: '0524'
                        pdf_url: '/v1/invoices/0524/pdf?series=RO_BK_COM'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
  /v1/invoices/{number}/pdf:
    get:
      summary: 'Download the invoice'
      description: |-
        Raw PDF bytes, not JSON — an accounting system files this. Proxied through us rather than linked directly, so ownership is checked before anything is served.

        Required scope: `wallet.read`.
      operationId: 'getV1InvoicesNumberPdf'
      tags:
        - 'Invoices'
      parameters:
        - name: 'number'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Path parameter'
        - name: 'series'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'RO_BK_COM'
          description: 'Required when the number is ambiguous'
      responses:
        '200':
          description: 'Success'
          content:
            application/pdf:
              schema:
                type: 'string'
                format: 'binary'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
  /v1/languages:
    get:
      summary: 'Published languages'
      description: |-
        The languages the catalog is available in. Pass one as `?lang=` to the category endpoints.

        Required scope: `catalog.read`.
      operationId: 'getV1Languages'
      tags:
        - 'Catalog'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 24
                data:
                  - code: 'ro'
                    name: 'Romanian'
                    native_name: 'Română'
                    is_default: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'catalog.read'
  /v1/me:
    get:
      summary: 'Who am I'
      description: |-
        The first call any integration makes: which environment you are talking to, which seller the key acts for, and what it may do. No scope required — a key can always describe itself.

        No scope required.
      operationId: 'getV1Me'
      tags:
        - 'Getting started'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                api_version: 'v1'
                environment: 'test'
                is_sandbox: true
                app:
                  id: 1
                  name: 'EasySales (pilot)'
                  vendor: 'easysales'
                key:
                  public_id: '88e2fb06233a'
                  scopes:
                    - 'catalog.read'
                    - 'products.read'
                  expires_at: null
                seller:
                  user_id: 22
                  name: 'Bike Shop SRL'
                  is_company: true
                shipping_address:
                  ready: true
                  reason: null
                  message: null
                  default_address:
                    id: 4812
                    street: 'Bulevardul Decebal 14'
                    city: 'Craiova'
                    county: 'Dolj'
                    postal_code: '200001'
                    country_code: 'RO'
                  details_url: '/v1/addresses'
                rate_limits:
                  per_minute: 60
                  per_day: 5000
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/notifications:
    get:
      summary: 'Emails and SMS sent about your orders'
      description: |-
        Every message the platform sent about one of YOUR orders — scoped by seller, not by recipient, because most of this mail goes to buyers. In the sandbox nothing is delivered, so every row is `suppressed`: composed in full and deliberately not sent. This is the only evidence a test order produced a notification at all. Subscribe to the `notification.sent` webhook rather than polling.

        Required scope: `orders.read`.
      operationId: 'getV1Notifications'
      tags:
        - 'Notifications'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
        - name: 'channel'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'mail'
          description: 'mail or sms'
        - name: 'status'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'suppressed'
          description: 'sent, failed or suppressed'
        - name: 'order_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '721'
          description: 'Only messages about one order'
        - name: 'template'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'email_shipping_sent'
          description: 'Filter by template'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 7
                    channel: 'mail'
                    status: 'suppressed'
                    order_id: 721
                    template: 'email_shipping_sent'
                    subject: 'Comanda ta a fost expediata'
                    preview: 'AWB 123456'
                    created_at: '2026-09-12T07:58:14Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.read'
  /v1/notifications/{id}:
    get:
      summary: 'One notification, with its content'
      description: |-
        Adds the recipient and the rendered body. `body_available` is false in production, where only metadata is kept — a rendered order email carries the buyer's name, address and phone. The sandbox has no real buyers, so it keeps everything.

        Required scope: `orders.read`.
      operationId: 'getV1NotificationsId'
      tags:
        - 'Notifications'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  id: 7
                  channel: 'mail'
                  status: 'suppressed'
                  order_id: 721
                  template: 'email_shipping_sent'
                  subject: 'Comanda ta a fost expediata'
                  recipient: 'buyer@example.com'
                  driver: 'mailing-service'
                  body: '<p>AWB 123456</p>'
                  body_available: true
                  created_at: '2026-09-12T07:58:14Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.read'
  /v1/orders:
    get:
      summary: 'List orders'
      description: |-
        Orders placed with you. Lines carry your own external_id and sku so you can match them to your catalog without a lookup.

        Required scope: `orders.read`.
      operationId: 'getV1Orders'
      tags:
        - 'Orders'
      parameters:
        - name: 'status'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'pending | accepted | rejected | ship_to_courier | picked_up | in_delivery | delivered | confirmed | returned | cancelled | expired | lost | not_confirmed'
        - name: 'updated_since'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'ISO 8601'
        - name: 'created_from'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: ' ISO 8601'
        - name: 'created_to'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'ISO 8601'
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 711
                    reference: 'SBXORD-SJP6NHXY'
                    status: 'pending'
                    can_accept: true
                    has_awb: false
                    total:
                      amount: 359800
                      currency: 'RON'
                    refunded:
                      amount: 0
                      currency: 'RON'
                    items:
                      - id: 1123
                        product_id: 237224
                        external_id: 'ERP-1001'
                        sku: 'MTB-29-001'
                        title: 'Bicicleta MTB Hardtail 29 inch'
                        quantity: 2
                        quantity_ordered: 2
                        quantity_short: 0
                        unit_price:
                          amount: 179900
                          currency: 'RON'
                        total_price:
                          amount: 359800
                          currency: 'RON'
                    awb: null
                    is_dropshipping: false
                    delivered_at: null
                    created_at: '2026-09-11T09:20:14Z'
                    updated_at: '2026-09-11T09:20:14Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.read'
  /v1/orders/{id}:
    get:
      summary: 'One order'
      description: |-
        Adds the delivery details you need to ship, the fee breakdown and the courier.

        Required scope: `orders.read`.
      operationId: 'getV1OrdersId'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 711
                reference: 'SBXORD-SJP6NHXY'
                status: 'accepted'
                can_accept: false
                has_awb: true
                total:
                  amount: 359800
                  currency: 'RON'
                refunded:
                  amount: 0
                  currency: 'RON'
                items:
                  - id: 1123
                    product_id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    quantity: 2
                    quantity_ordered: 2
                    quantity_short: 0
                    unit_price:
                      amount: 179900
                      currency: 'RON'
                    total_price:
                      amount: 359800
                      currency: 'RON'
                awb:
                  number: 'SBX0000000711'
                  tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000000711'
                is_dropshipping: false
                created_at: '2026-09-11T09:20:14Z'
                updated_at: '2026-09-11T10:02:47Z'
                accepted_at: '2026-09-11T10:02:47Z'
                delivered_at: null
                expires_at: '2026-09-13T09:20:14Z'
                notes_from_buyer: 'Please call before delivery.'
                courier_id: 1
                seller_invoice: null
                fees:
                  platform_fee: 17990
                  shipping: 2500
                  currency: 'RON'
                delivery:
                  recipient: 'John Doe'
                  phone: '07xxxxxxxx'
                  city: 'Craiova'
                  county: 'Dolj'
                  postcode: '200000'
                  country: 'RO'
                  is_locker: false
                refunds: []
                parcels:
                  - id: 4012
                    sequence_no: 1
                    weight_kg: 2.4
                    length_cm: 40
                    width_cm: 30
                    height_cm: 20
                    is_seller_declared: true
                    items:
                      - order_item_id: 1123
                        quantity: 2
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.read'
  /v1/orders/{id}/customer:
    get:
      summary: 'The customer behind one order'
      description: |-
        The endpoint to reach for when you are about to raise an invoice: you are holding an order id and you need the buyer AS THEY WERE FOR THAT SALE. A customer who has moved has two orders at two addresses, and each invoice must carry its own — `GET /v1/customers/{id}` gives you their latest, this gives you that order's. An order with no buyer account on it is `customer_not_found` (404).

        Required scope: `customers.read`.
      operationId: 'getV1OrdersIdCustomer'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 9000001
                name: 'John Doe'
                email: 'john.doe@example.com'
                phone: '+40700000000'
                billing:
                  address_line: 'Str. Exemplu 12'
                  city: 'Brasov'
                  county: 'Brasov'
                  postal_code: '500002'
                  country_code: 'RO'
                  country: 'România'
                  is_company: true
                  company:
                    name: 'Example Bike Shop SRL'
                    vat_code: 'RO12345678'
                    registration_no: 'J16/123/2020'
                  is_live: true
                  delivered_to_locker: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'customers.read'
  /v1/orders/{id}/label:
    get:
      summary: 'Download the label'
      description: |-
        Returns the label BYTES, not JSON — send it straight to a printer. ZPL is what most warehouse printers want.

        PDF labels come in a page size: `?size=a6` (105 × 148 mm, label printer), `a5`, `a4`, or `original` (the courier's own PDF, usually an A4 sheet with the label printed twice). Without `size` you get the size the seller chose in their Biklo settings, and **A6** if they never chose. Each distinct label gets its own portrait page; a duplicate copy is dropped, every parcel of a multi-parcel order is kept. A4/A5 print at real size, A6 fills the page. The `X-Label-Size` response header says what you received — `original` while Biklo has label formatting switched off. `size` does not apply to ZPL.

        Required scope: `orders.read`.
      operationId: 'getV1OrdersIdLabel'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
        - name: 'format'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'pdf'
          description: 'pdf or zpl'
        - name: 'size'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'a6'
          description: 'PDF page size: a6, a5, a4 or original. Default: the seller''s saved choice, else a6.'
      responses:
        '200':
          description: 'Success'
          content:
            application/pdf:
              schema:
                type: 'string'
                format: 'binary'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.read'
  /v1/orders/{id}/tracking:
    get:
      summary: 'Tracking events'
      description: |-
        The courier's own history where we have it; before an AWB exists it falls back to the order's own milestones so you always have something to render.

        Required scope: `orders.read`.
      operationId: 'getV1OrdersIdTracking'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                order_id: 711
                status: 'Livrat'
                internal_status: 'accepted'
                awb:
                  number: 'SBX0000007112'
                  tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000007112'
                events:
                  - status: 'accepted'
                    at: '2026-09-09T19:40:19Z'
                    location: null
                    source: 'order'
                    is_final: false
                  - status: 'Livrat'
                    at: '2026-09-11T14:22:05Z'
                    location: 'Craiova'
                    source: 'courier'
                    is_final: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.read'
  /v1/product-groups/{externalGroupId}:
    get:
      summary: 'Read a variant group'
      description: |-
        By your own group id.

        Required scope: `products.read`.
      operationId: 'getV1ProductGroupsExternalGroupId'
      tags:
        - 'Products'
      parameters:
        - name: 'externalGroupId'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Your own group id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                external_group_id: 'ERP-1001-GROUP'
                group_id: 904
                count: 2
                variants:
                  - product_id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001-S'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    price:
                      amount: 249900
                    stock: 4
                    size: 'S'
                    color: 'Negru'
                    gender: null
                    is_representative: true
                  - product_id: 237225
                    external_id: 'ERP-1001-M'
                    sku: 'MTB-29-001-M'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    price:
                      amount: 249900
                    stock: 2
                    size: 'M'
                    color: 'Negru'
                    gender: null
                    is_representative: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.read'
  /v1/products:
    get:
      summary: 'List your products'
      description: |-
        Your own catalog only, cursor-paginated. Use `updated_since` for incremental sync instead of re-reading everything.

        Required scope: `products.read`.
      operationId: 'getV1Products'
      tags:
        - 'Products'
      parameters:
        - name: 'updated_since'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '2026-09-01T00:00:00Z'
          description: 'ISO 8601'
        - name: 'status'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'active'
          description: 'active | draft | sold | archived'
        - name: 'sku'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: ' Exact match'
        - name: 'external_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Your own id'
        - name: 'category_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Master or translated id'
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: '165987'
                data:
                  - id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001'
                    gtin: null
                    mpn: null
                    ean: null
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    description: 'A hardtail mountain bike in very good condition, barely used.'
                    category_id: 4291
                    status: 'active'
                    is_reviewed: true
                    price:
                      amount: 249900
                      currency: 'RON'
                      negotiable: true
                    stock: 4
                    shipping:
                      ship_with_us: true
                      free_shipping: false
                      shipping_class: 'bike'
                      parcel_tier: 'large'
                      weight_kg: 14.5
                      width_cm: 80
                      height_cm: 120
                      length_cm: 180
                    group_id: null
                    images:
                      - id: 108876841
                        position: 0
                        path: 'files/237224/mtb-front.jpg'
                        source_url: null
                    attributes:
                      - field_id: 32
                        option_id: 226
                        value: null
                    created_at: '2026-09-01T08:14:22Z'
                    updated_at: '2026-09-11T16:02:51Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.read'
    post:
      summary: 'Create or update a product'
      description: |-
        Upsert keyed on your `external_id`: the same call twice updates rather than duplicating, which makes a retried push safe. Required category attributes are enforced exactly as they are for a seller using the dashboard. Send `images` in the same call — one request per product, images included.

        Required scope: `products.write`.
      operationId: 'postV1Products'
      tags:
        - 'Products'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 237224
                external_id: 'ERP-1001'
                sku: 'MTB-29-001'
                gtin: null
                mpn: null
                ean: null
                title: 'Bicicleta MTB Hardtail 29 inch'
                description: 'A hardtail mountain bike in very good condition, barely used.'
                category_id: 4291
                status: 'active'
                is_reviewed: true
                price:
                  amount: 249900
                  currency: 'RON'
                  negotiable: true
                stock: 4
                shipping:
                  ship_with_us: true
                  free_shipping: false
                  shipping_class: 'bike'
                  parcel_tier: 'large'
                  weight_kg: 14.5
                  width_cm: 80
                  height_cm: 120
                  length_cm: 180
                group_id: null
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                attributes:
                  - field_id: 32
                    option_id: 226
                    value: null
                created_at: '2026-09-01T08:14:22Z'
                updated_at: '2026-09-11T16:02:51Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              external_id: 'ERP-1001'
              title: 'Bicicleta MTB Hardtail 29 inch'
              description: 'A hardtail mountain bike in very good condition, barely used.'
              category_id: 4291
              price:
                amount: 249900
                currency: 'RON'
                negotiable: true
              stock: 4
              sku: 'MTB-29-001'
              attributes:
                - field_id: 32
                  option_id: 226
                - field_id: 47
                  option_id: 422
              shipping:
                weight_kg: 14.5
                width_cm: 80
                height_cm: 120
                length_cm: 180
              images:
                - 'https://cdn.example.com/erp/mtb-front.jpg'
                - 'https://cdn.example.com/erp/mtb-side.jpg'
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/batch/{batchId}:
    get:
      summary: 'Batch status and per-item results'
      description: |-
        Failures are listed first, because that is what you opened this for. `?failed_only=1` returns just those.

        Required scope: `products.write`.
      operationId: 'getV1ProductsBatchBatchId'
      tags:
        - 'Products'
      parameters:
        - name: 'batchId'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'The batch_id returned by POST /v1/products/batch'
        - name: 'failed_only'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: '1 to return only the failures'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                batch_id: 'batch_v4lfngtgb6sxqkzwagrqv8c2'
                status: 'completed'
                total: 7
                processed: 7
                succeeded: 5
                failed: 2
                created_at: '2026-09-11T14:02:10Z'
                completed_at: '2026-09-11T14:02:38Z'
                error: null
                items_shown: 2
                items:
                  - position: 0
                    external_id: 'ERP-1001'
                    status: 'success'
                    product_id: 237224
                    error: null
                  - position: 5
                    external_id: 'BATCH-BAD'
                    status: 'failed'
                    product_id: null
                    error:
                      code: 'missing_required_attribute'
                      message: 'The attribute "Brand" is required for this category.'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/{id}:
    get:
      summary: 'One product'
      description: |-
        By our id, or by your own with `?by=external_id`.

        Required scope: `products.read`.
      operationId: 'getV1ProductsId'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
        - name: 'by'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Set to external_id to look up by your identifier'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 237224
                external_id: 'ERP-1001'
                sku: 'MTB-29-001'
                gtin: null
                mpn: null
                ean: null
                title: 'Bicicleta MTB Hardtail 29 inch'
                description: 'A hardtail mountain bike in very good condition, barely used.'
                category_id: 4291
                status: 'active'
                is_reviewed: true
                price:
                  amount: 249900
                  currency: 'RON'
                  negotiable: true
                stock: 4
                shipping:
                  ship_with_us: true
                  free_shipping: false
                  shipping_class: 'bike'
                  parcel_tier: 'large'
                  weight_kg: 14.5
                  width_cm: 80
                  height_cm: 120
                  length_cm: 180
                group_id: null
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                attributes:
                  - field_id: 32
                    option_id: 226
                    value: null
                created_at: '2026-09-01T08:14:22Z'
                updated_at: '2026-09-11T16:02:51Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.read'
    put:
      summary: 'Update a product'
      description: |-
        Partial: keys you omit are left alone. Send `attributes` only when you want to replace the whole set.

        Required scope: `products.write`.
      operationId: 'putV1ProductsId'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 237224
                external_id: 'ERP-1001'
                sku: 'MTB-29-001'
                gtin: null
                mpn: null
                ean: null
                title: 'Bicicleta MTB Hardtail 29 inch'
                description: 'A hardtail mountain bike in very good condition, barely used.'
                category_id: 4291
                status: 'active'
                is_reviewed: true
                price:
                  amount: 249900
                  currency: 'RON'
                  negotiable: true
                stock: 4
                shipping:
                  ship_with_us: true
                  free_shipping: false
                  shipping_class: 'bike'
                  parcel_tier: 'large'
                  weight_kg: 14.5
                  width_cm: 80
                  height_cm: 120
                  length_cm: 180
                group_id: null
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                attributes:
                  - field_id: 32
                    option_id: 226
                    value: null
                created_at: '2026-09-01T08:14:22Z'
                updated_at: '2026-09-11T16:02:51Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              title: 'Bicicleta MTB Hardtail 29 actualizata'
              price:
                amount: 199900
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/{id}/pricing:
    get:
      summary: 'What a buyer pays, and what it costs you'
      description: |-
        The same figures the product page renders, from the same service — a partner and a buyer are never shown different numbers. Takes a DESTINATION, because delivery and absorption both depend on where the parcel goes; defaults to the listing's own country. Each `status` says who bears that line: `charged` means the buyer, anything else means your company or the platform absorbed it. `delivery.quoted: false` is NOT free delivery — it means we could not price that route at all, and the order may not be placeable there. Its own endpoint rather than a block on the product payload, because it costs a route lookup per product.

        Required scope: `products.read`.
      operationId: 'getV1ProductsIdPricing'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
        - name: 'country_code'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'RO'
          description: 'Destination. Defaults to the listing''s own country'
        - name: 'by'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'Set to external_id to look the product up by your identifier'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  currency: 'RON'
                  destination_country_code: 'RO'
                  buyer_pays:
                    product: 120000
                    buyer_protection:
                      amount: 6000
                      status: 'absorbed_by_company'
                    delivery:
                      amount: 2500
                      status: 'charged'
                      quoted: true
                    total_estimated: 122500
                  commission:
                    percentage: 5
                    min_amount: 499
                    max_amount: null
                  note: 'Estimates from the same service the product page renders.'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.read'
  /v1/questions:
    get:
      summary: 'List questions on your listings'
      description: |-
        Public questions — these render on the product page for every future buyer, so an unanswered one is visible to everyone. `unanswered_count` is carried on every response so you can badge it without a second call.

        Required scope: `questions.read`.
      operationId: 'getV1Questions'
      tags:
        - 'Questions'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
        - name: 'unanswered_only'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'true'
          description: 'Only questions still waiting'
        - name: 'product_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '237233'
          description: 'Only questions on one listing'
        - name: 'updated_since'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '2026-09-01T00:00:00Z'
          description: 'Incremental sync'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 2
                next_cursor: null
                unanswered_count: 1
                data:
                  - id: 31
                    text: 'What frame size is this?'
                    product:
                      id: 237233
                      title: 'Trek Marlin 7'
                      slug: 'trek-marlin-7'
                    asked_by:
                      id: 9000002
                      name: 'Jane Doe'
                    is_answered: false
                    answered_at: null
                    votes:
                      helpful: 0
                      not_helpful: 0
                      same_question: 0
                    answers: []
                    created_at: '2026-09-10T06:21:50Z'
                    updated_at: '2026-09-10T06:21:50Z'
                  - id: 30
                    text: 'Does it come with pedals?'
                    product:
                      id: 237233
                      title: 'Trek Marlin 7'
                      slug: 'trek-marlin-7'
                    asked_by:
                      id: 9000003
                      name: 'Maria I.'
                    is_answered: true
                    answered_at: '2026-09-09T11:04:12Z'
                    votes:
                      helpful: 2
                      not_helpful: 0
                      same_question: 1
                    answers:
                      - id: 14
                        text: 'Yes, flat pedals are included.'
                        is_from_seller: true
                        author_name: 'Bike Shop SRL'
                        created_at: '2026-09-09T11:04:12Z'
                        updated_at: '2026-09-09T11:04:12Z'
                    created_at: '2026-09-09T10:58:03Z'
                    updated_at: '2026-09-09T11:04:12Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'questions.read'
  /v1/questions/{id}:
    get:
      summary: 'Get one question'
      description: |-
        With every published answer on it.

        Required scope: `questions.read`.
      operationId: 'getV1QuestionsId'
      tags:
        - 'Questions'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  id: 31
                  text: 'What frame size is this?'
                  product:
                    id: 237233
                    title: 'Trek Marlin 7'
                    slug: 'trek-marlin-7'
                  asked_by:
                    id: 9000002
                    name: 'Jane Doe'
                  is_answered: true
                  answered_at: '2026-09-10T06:21:57Z'
                  votes:
                    helpful: 2
                    not_helpful: 0
                    same_question: 1
                  answers:
                    - id: 15
                      text: 'Size L — suits 180-190 cm.'
                      is_from_seller: true
                      author_name: 'Bike Shop SRL'
                      created_at: '2026-09-10T06:21:57Z'
                      updated_at: '2026-09-10T06:21:57Z'
                  created_at: '2026-09-10T06:21:50Z'
                  updated_at: '2026-09-10T06:21:57Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'questions.read'
  /v1/returns:
    get:
      summary: 'List returns'
      description: |-
        Returns buyers have raised against your orders.

        Required scope: `orders.read`.
      operationId: 'getV1Returns'
      tags:
        - 'Orders'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 8
                    order_id: 711
                    return_order_id: 742
                    reference: 'SBXORD-SJP6NHXY'
                    reason: 'Wrong size delivered'
                    order_status: 'delivered'
                    requested_at: '2026-09-09T19:45:00Z'
                    inspection:
                      status: 'awaiting_seller'
                      delivered_at: '2026-09-12T09:10:00Z'
                      deadline_at: '2026-09-14T09:10:00Z'
                      refund:
                        amount: 179900
                        currency: 'RON'
                      refunded: null
                      decided_at: null
                      decided_by: null
                      can_accept: true
                      can_reject: true
                    items:
                      - id: 1123
                        product_id: 237224
                        quantity: 1
                        total_price:
                          amount: 179900
                          currency: 'RON'
                        return_status: 'requested'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.read'
  /v1/threads:
    get:
      summary: 'List buyer conversations'
      description: |-
        Conversations on your listings, newest activity first. Buyers are a display name and an id — never an email or a phone number. Use `unread_only=true` for the ones actually waiting on you.

        Required scope: `messages.read`.
      operationId: 'getV1Threads'
      tags:
        - 'Threads'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor from the previous page'
        - name: 'unread_only'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'true'
          description: 'Only conversations you have not read'
        - name: 'product_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '237233'
          description: 'Only conversations about one listing'
        - name: 'updated_since'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '2026-09-01T00:00:00Z'
          description: 'Incremental sync'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 107373
                    subject: 'Trek Marlin 7'
                    product:
                      id: 237233
                      title: 'Trek Marlin 7'
                      slug: 'trek-marlin-7'
                    buyer:
                      id: 9000002
                      name: 'Jane Doe'
                    last_message:
                      id: 174420
                      from: 'buyer'
                      preview: 'Is this still available?'
                      created_at: '2026-09-10T06:15:18Z'
                    is_unread: true
                    created_at: '2026-09-10T06:15:18Z'
                    updated_at: '2026-09-10T06:15:18Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'messages.read'
  /v1/threads/{id}:
    get:
      summary: 'Get one conversation'
      description: |-
        The same shape as a row in the list. 404 if the conversation is not on one of your listings.

        Required scope: `messages.read`.
      operationId: 'getV1ThreadsId'
      tags:
        - 'Threads'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  id: 107373
                  subject: 'Trek Marlin 7'
                  product:
                    id: 237233
                    title: 'Trek Marlin 7'
                    slug: 'trek-marlin-7'
                  buyer:
                    id: 9000002
                    name: 'Jane Doe'
                  last_message:
                    id: 174420
                    from: 'buyer'
                    preview: 'Is this still available?'
                    created_at: '2026-09-10T06:15:18Z'
                  is_unread: true
                  created_at: '2026-09-10T06:15:18Z'
                  updated_at: '2026-09-10T06:15:18Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'messages.read'
  /v1/threads/{id}/messages:
    get:
      summary: 'List messages in a conversation'
      description: |-
        Newest first. `body` is the text as STORED — when chat protection masked contact details, this is the masked version, which is what the buyer sees too.

        Required scope: `messages.read`.
      operationId: 'getV1ThreadsIdMessages'
      tags:
        - 'Threads'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 174420
                    from: 'buyer'
                    author:
                      id: 9000002
                      name: 'Jane Doe'
                    body: 'Is this still available?'
                    has_attachment: false
                    type: 'text'
                    created_at: '2026-09-10T06:15:18Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'messages.read'
    post:
      summary: 'Reply to a buyer'
      description: |-
        Every reply passes through the same chat-protection scan the seller dashboard applies. A message carrying contact details is refused with 422 `blocked_by_chat_protection` and a `detected` list saying what was found, or is masked before it is stored — check `chat_protection.was_masked` and show your user the `body` we return, not the one you sent.

        Required scope: `messages.write`.
      operationId: 'postV1ThreadsIdMessages'
      tags:
        - 'Threads'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  id: 174421
                  thread_id: 107373
                  from: 'seller'
                  body: 'Yes, it is in stock — we ship within 24 hours.'
                  created_at: '2026-09-10T06:15:30Z'
                chat_protection:
                  decision: 'allow'
                  was_masked: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              body: 'Yes, it is in stock — we ship within 24 hours.'
      security:
        - bearerAuth:
            - 'messages.write'
  /v1/wallet/account:
    get:
      summary: 'Payout onboarding state'
      description: |-
        Check this BEFORE offering a withdrawal button. Payout onboarding runs on Stripe Connect, which collects identity documents directly in a hosted browser flow — it CANNOT be completed through this API and no endpoint for it will ever exist. `requirements.currently_due` carries Stripe's own field names for what is still missing, and `next_step` says what to tell your user.

        Required scope: `wallet.read`.
      operationId: 'getV1WalletAccount'
      tags:
        - 'Wallet'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  has_account: true
                  can_withdraw: true
                  onboarding_status: 'complete'
                  payouts_enabled: true
                  details_submitted: true
                  requirements:
                    currently_due: []
                    past_due: []
                    pending_verification: []
                    disabled_reason: null
                  bank_accounts:
                    - last4: '0000'
                      currency: 'RON'
                      country: 'RO'
                  next_step:
                    action: 'none'
                    message: 'This account can receive payouts.'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
  /v1/wallet/balance:
    get:
      summary: 'Balances per currency'
      description: |-
        A LIST, not a number: a seller trading cross-border holds several currencies at once. Every figure is minor units. When money is `blocked` and cannot be withdrawn, the response also carries an `onboarding` block saying why. `settled_to_fees` is terminal: the company's absorbed fees consumed the whole order, so nothing was transferred and nothing was refunded.

        Required scope: `wallet.read`.
      operationId: 'getV1WalletBalance'
      tags:
        - 'Wallet'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  - currency: 'RON'
                    pending: 123400
                    available: 45000
                    paid_out: 890000
                    refunded: 0
                    blocked: 0
                    debt: 0
                    settled_to_fees: 0
                    under_review: 0
                can_withdraw: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
  /v1/wallet/ledger:
    get:
      summary: 'The append-only ledger'
      description: |-
        Every movement, in order. Reconcile against THIS, not against the balance: balances are a current view, the ledger is the history.

        Required scope: `wallet.read`.
      operationId: 'getV1WalletLedger'
      tags:
        - 'Wallet'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
        - name: 'currency'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'RON'
          description: 'Filter by currency'
        - name: 'order_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '716'
          description: 'Entries for one order'
        - name: 'entry_type'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'payout_paid'
          description: 'Filter by movement type'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 224550
                    lot_id: 1091
                    order_id: 716
                    direction: 'credit'
                    type: 'return_window_started'
                    amount: 123400
                    currency: 'RON'
                    balance_category: 'pending'
                    created_at: '2026-09-10T07:01:08Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
  /v1/wallet/lots:
    get:
      summary: 'Money per order'
      description: |-
        One row per order. `balance_bucket` says which bucket in GET /v1/wallet/balance this lot counts towards, so you can reconcile the two without learning our internal statuses. `net_transferred_amount` is what actually reached the seller — NOT `amount` when the company absorbed fees, because the surcharge is withheld at transfer. Reconcile against the net.

        Required scope: `wallet.read`.
      operationId: 'getV1WalletLots'
      tags:
        - 'Wallet'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
        - name: 'cursor'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'next_cursor'
        - name: 'status'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'ready_to_transfer'
          description: 'Filter by lot status'
        - name: 'currency'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: 'RON'
          description: 'Filter by currency'
        - name: 'order_id'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '716'
          description: 'The lot for one order'
        - name: 'updated_since'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '2026-09-01T00:00:00Z'
          description: 'Incremental sync'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                next_cursor: null
                data:
                  - id: 1091
                    order_id: 716
                    amount: 123400
                    currency: 'RON'
                    status: 'return_window'
                    balance_bucket: 'pending'
                    is_withdrawable: false
                    held_for_return: false
                    net_transferred_amount: null
                    return_window_expires_at: '2026-09-24T07:01:08Z'
                    withdrawal_id: null
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
  /v1/wallet/withdrawals:
    get:
      summary: 'Payout history'
      description: |-
        Read from Stripe. If Stripe cannot be reached we fall back to our own rows and mark them `source: local` — you will never see an empty list that wrongly implies no money ever moved.

        Required scope: `wallet.read`.
      operationId: 'getV1WalletWithdrawals'
      tags:
        - 'Wallet'
      parameters:
        - name: 'limit'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: '50'
          description: 'Max 100'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  - id: 'po_1QxyzABC'
                    amount: 45000
                    currency: 'RON'
                    status: 'paid'
                    orders_count: 3
                    bank_reference: 'ARN123456789'
                    created_at: '2026-09-08T09:00:00Z'
                    arrival_at: '2026-09-10T00:00:00Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.read'
    post:
      summary: 'Withdraw to the bank'
      description: |-
        Send `amount` and `currency` together or neither — an amount without a currency is ambiguous the moment a seller holds two, so it is refused rather than guessed. With neither, everything available is withdrawn per currency. `status: funds_settling` is NOT a failure: the money was released and is settling at Stripe. A `payout_failed` is almost always a bank account that cannot receive the balance currency. Returns 409 `onboarding_required` when the seller has not finished Stripe onboarding in a browser.

        Required scope: `wallet.withdraw`.
      operationId: 'postV1WalletWithdrawals'
      tags:
        - 'Wallet'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  status: 'payout_created'
                  withdrawals:
                    - id: 'po_1QxyzABC'
                      amount: 45000
                      currency: 'RON'
                      status: 'pending'
                  transferred_lots: 3
                  settling: []
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              amount: 45000
              currency: 'RON'
      security:
        - bearerAuth:
            - 'wallet.withdraw'
  /v1/webhooks:
    get:
      summary: 'List your endpoints'
      description: |-
        Also returns `available_events`, the full list you may subscribe to.

        Required scope: `webhooks.manage`.
      operationId: 'getV1Webhooks'
      tags:
        - 'Webhooks'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                data:
                  - id: 1
                    url: 'https://erp.example.com/hooks'
                    events:
                      - 'order.created'
                    is_active: true
                    consecutive_failures: 0
                    disabled_at: null
                    headers:
                      - name: 'X-Api-Key'
                        preview: 'the ••••••••'
                    secret_prefix: 'whsec_64Ky4…'
                available_events:
                  - 'order.created'
                  - 'order.status_changed'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'webhooks.manage'
    post:
      summary: 'Register an endpoint'
      description: |-
        The signing secret is returned ONCE. Verify every delivery: X-Biklo-Signature is `t=<timestamp>,v1=hmac_sha256(timestamp + "." + raw_body, secret)` — the same scheme Stripe uses. An empty `events` list means every event.

        Required scope: `webhooks.manage`.
      operationId: 'postV1Webhooks'
      tags:
        - 'Webhooks'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 1
                url: 'https://erp.example.com/hooks/biklo'
                events:
                  - 'order.created'
                  - 'order.status_changed'
                is_active: true
                headers:
                  - name: 'X-Api-Key'
                    preview: 'the ••••••••'
                secret: 'whsec_…'
                secret_note: 'Shown once.'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              url: 'https://erp.example.com/hooks/biklo'
              events:
                - 'order.created'
                - 'order.status_changed'
              headers:
                - name: 'X-Api-Key'
                  value: 'the value your gateway expects'
      security:
        - bearerAuth:
            - 'webhooks.manage'
  /v1/webhooks/{id}/deliveries:
    get:
      summary: 'Delivery log'
      description: |-
        What happened to every event we sent you — the answer to "we never got the order".

        Required scope: `webhooks.manage`.
      operationId: 'getV1WebhooksIdDeliveries'
      tags:
        - 'Webhooks'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
        - name: 'status'
          in: 'query'
          required: false
          schema:
            type: 'string'
          example: ''
          description: 'pending | delivered | failed | abandoned'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                count: 1
                data:
                  - id: 3
                    event: 'order.created'
                    event_id: 'evt_vlvslhcxut3gj4oikfnqyf7n'
                    status: 'delivered'
                    attempts: 1
                    response_status: 200
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'webhooks.manage'
  /v1/products/{id}/price:
    patch:
      summary: 'Update price only'
      description: |-
        The cheap path for the field ERPs push most often — one UPDATE, no attribute or shipping rewrite. Amount in minor units.

        Required scope: `products.write`.
      operationId: 'patchV1ProductsIdPrice'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 237224
                external_id: 'ERP-1001'
                sku: 'MTB-29-001'
                gtin: null
                mpn: null
                ean: null
                title: 'Bicicleta MTB Hardtail 29 inch'
                description: 'A hardtail mountain bike in very good condition, barely used.'
                category_id: 4291
                status: 'active'
                is_reviewed: true
                price:
                  amount: 249900
                  currency: 'RON'
                  negotiable: true
                stock: 4
                shipping:
                  ship_with_us: true
                  free_shipping: false
                  shipping_class: 'bike'
                  parcel_tier: 'large'
                  weight_kg: 14.5
                  width_cm: 80
                  height_cm: 120
                  length_cm: 180
                group_id: null
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                attributes:
                  - field_id: 32
                    option_id: 226
                    value: null
                created_at: '2026-09-01T08:14:22Z'
                updated_at: '2026-09-11T16:02:51Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              price: 179900
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/{id}/stock:
    patch:
      summary: 'Update stock only'
      description: |-
        The cheap path for stock. One UPDATE, nothing else touched.

        Required scope: `products.write`.
      operationId: 'patchV1ProductsIdStock'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 237224
                external_id: 'ERP-1001'
                sku: 'MTB-29-001'
                gtin: null
                mpn: null
                ean: null
                title: 'Bicicleta MTB Hardtail 29 inch'
                description: 'A hardtail mountain bike in very good condition, barely used.'
                category_id: 4291
                status: 'active'
                is_reviewed: true
                price:
                  amount: 249900
                  currency: 'RON'
                  negotiable: true
                stock: 4
                shipping:
                  ship_with_us: true
                  free_shipping: false
                  shipping_class: 'bike'
                  parcel_tier: 'large'
                  weight_kg: 14.5
                  width_cm: 80
                  height_cm: 120
                  length_cm: 180
                group_id: null
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                attributes:
                  - field_id: 32
                    option_id: 226
                    value: null
                created_at: '2026-09-01T08:14:22Z'
                updated_at: '2026-09-11T16:02:51Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              stock: 2
      security:
        - bearerAuth:
            - 'products.write'
  /v1/addresses/{id}/default:
    post:
      summary: 'Make an address the default'
      description: |-
        Makes this the address orders ship from, and clears the flag on every other one. This is the setting that decides where a courier collects, and which city a product with no `city_id` is published in — change it and your next product sync moves the catalogue with it.

        Required scope: `company.write`.
      operationId: 'postV1AddressesIdDefault'
      tags:
        - 'Addresses'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 4813
                street: 'Strada Depozitului 9'
                postal_code: '600001'
                city:
                  id: 385
                  name: 'Bacau'
                county:
                  id: 2
                  name: 'Bacau'
                country_code: 'RO'
                company_name: 'Bike Shop SRL'
                company_vat_code: 'RO12345678'
                company_reg_no: 'J16/123/2020'
                is_default: true
                created_at: '2026-09-14T09:40:10+00:00'
                updated_at: '2026-09-14T11:20:55+00:00'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.write'
  /v1/company/logo:
    post:
      summary: 'Upload the shop logo'
      description: |-
        Multipart `file` — PNG, JPG or WebP. Resized and stored the same way the seller dashboard stores it.

        Required scope: `company.write`.
      operationId: 'postV1CompanyLogo'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                company:
                  id: 9000010
                  name: 'Example Bikes SL'
                  business_name: 'Example Bikes SL'
                  title: 'Example Bikes'
                  description: '<p>Mountain bike apparel from Barcelona.</p>'
                  logo_url: 'https://cdn.biklo.ro/app/companies/5611/logo.png'
                  cover_url: null
                  contact:
                    person: 'Sandbox Contact'
                    email: 'contact@example.com'
                    phone: '0700000000'
                    address: 'Carrer Gran 42, Barcelona'
                  links:
                    website: 'https://example.com'
                    marketplace: null
                    google_maps: null
                    facebook: null
                    instagram: null
                    linkedin: null
                    tiktok: null
                    youtube: null
                  is_active: true
                  onboarding_completed_at: '2026-08-02T09:14:00Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'company.write'
  /v1/orders/{id}/accept:
    post:
      summary: 'Accept an order'
      description: |-
        Only a pending order can be accepted; anything else returns 409 with its current status. Accepting BOOKS THE COURIER, exactly as Accept does in the seller dashboard: the response carries the AWB (`awb.number`, `awb.tracking_url`), the label is ready at GET /v1/orders/{id}/label, tracking starts, and the buyer gets the usual emails and SMS. If the courier cannot be booked the order stays pending and nothing changed — fix the reason (`courier_required`, `buyer_phone_missing`, `awb_generation_failed` 502) and call again. A face-to-face order is accepted without a courier. This is also where you declare how the order is PACKED. Send nothing and one box per order line is assumed. Send `parcels` to combine lines into fewer boxes or split a line's pieces across boxes — the courier is quoted per parcel. Never more boxes than pieces. Reference lines by the `id` on each item from GET /v1/orders/{id}, and give dimensions in cm and kg like everywhere else. SHORT SHIPMENT: if you have fewer pieces of a line than were ordered, send `items` with how many you ship. The courier is booked for those pieces, and only once it returned an AWB are the lines reduced and the buyer refunded the product price of the missing pieces (delivery and fees are not refunded); a failed booking changes nothing. The order then carries `quantity_ordered` / `quantity_short` per line and the refund, `order.items_changed` is sent, and the listing is set to stock 0.

        Required scope: `orders.write`.
      operationId: 'postV1OrdersIdAccept'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 711
                reference: 'SBXORD-SJP6NHXY'
                status: 'accepted'
                can_accept: false
                has_awb: true
                total:
                  amount: 359800
                  currency: 'RON'
                refunded:
                  amount: 0
                  currency: 'RON'
                items:
                  - id: 1123
                    product_id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    quantity: 2
                    quantity_ordered: 2
                    quantity_short: 0
                    unit_price:
                      amount: 179900
                      currency: 'RON'
                    total_price:
                      amount: 359800
                      currency: 'RON'
                awb:
                  number: 'SBX0000000711'
                  tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000000711'
                is_dropshipping: false
                created_at: '2026-09-11T09:20:14Z'
                updated_at: '2026-09-11T10:02:47Z'
                accepted_at: '2026-09-11T10:02:47Z'
                delivered_at: null
                expires_at: '2026-09-13T09:20:14Z'
                notes_from_buyer: 'Please call before delivery.'
                courier_id: 1
                seller_invoice: null
                fees:
                  platform_fee: 17990
                  shipping: 2500
                  currency: 'RON'
                delivery:
                  recipient: 'John Doe'
                  phone: '07xxxxxxxx'
                  city: 'Craiova'
                  county: 'Dolj'
                  postcode: '200000'
                  country: 'RO'
                  is_locker: false
                refunds: []
                parcels:
                  - id: 4012
                    sequence_no: 1
                    weight_kg: 2.4
                    length_cm: 40
                    width_cm: 30
                    height_cm: 20
                    is_seller_declared: true
                    items:
                      - order_item_id: 1123
                        quantity: 2
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              items:
                - id: 1123
                  quantity: 1
              parcels:
                - items:
                    - shipping_item_id: 1123
                      quantity: 2
                    - shipping_item_id: 1124
                      quantity: 1
                  weight_kg: 2.4
                  length_cm: 40
                  width_cm: 30
                  height_cm: 20
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/orders/{id}/awb:
    post:
      summary: 'Request a waybill'
      description: |-
        Accepting an order already books its courier, so this returns that AWB (`already_existed: true`). It books one only for an order accepted before accept did so — and it is idempotent: never a second shipment for the same order.

        Required scope: `orders.write`.
      operationId: 'postV1OrdersIdAwb'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                awb:
                  number: 'SBX0000007112'
                  tracking_url: 'https://.../sandbox/tracking/SBX0000007112'
                already_existed: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example: []
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/orders/{id}/confirm-shipped:
    post:
      summary: 'Confirm handover (deprecated)'
      description: |-
        **Deprecated — you do not need to call this.** Accepting the order books the courier, and the parcel's progress comes from the courier itself (`GET /v1/orders/{id}/tracking`). The endpoint still answers `200` with the order, unchanged, so existing integrations keep working; it no longer changes anything. Remove the call when convenient.

        Required scope: `orders.write`.
      operationId: 'postV1OrdersIdConfirmShipped'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 711
                reference: 'SBXORD-SJP6NHXY'
                status: 'accepted'
                can_accept: false
                has_awb: true
                total:
                  amount: 359800
                  currency: 'RON'
                refunded:
                  amount: 0
                  currency: 'RON'
                items:
                  - id: 1123
                    product_id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    quantity: 2
                    quantity_ordered: 2
                    quantity_short: 0
                    unit_price:
                      amount: 179900
                      currency: 'RON'
                    total_price:
                      amount: 359800
                      currency: 'RON'
                awb:
                  number: 'SBX0000000711'
                  tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000000711'
                is_dropshipping: false
                created_at: '2026-09-11T09:20:14Z'
                updated_at: '2026-09-11T10:02:47Z'
                accepted_at: '2026-09-11T10:02:47Z'
                delivered_at: null
                expires_at: '2026-09-13T09:20:14Z'
                notes_from_buyer: 'Please call before delivery.'
                courier_id: 1
                seller_invoice: null
                fees:
                  platform_fee: 17990
                  shipping: 2500
                  currency: 'RON'
                delivery:
                  recipient: 'John Doe'
                  phone: '07xxxxxxxx'
                  city: 'Craiova'
                  county: 'Dolj'
                  postcode: '200000'
                  country: 'RO'
                  is_locker: false
                refunds: []
                parcels:
                  - id: 4012
                    sequence_no: 1
                    weight_kg: 2.4
                    length_cm: 40
                    width_cm: 30
                    height_cm: 20
                    is_seller_declared: true
                    items:
                      - order_item_id: 1123
                        quantity: 2
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      deprecated: true
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/orders/{id}/invoice:
    post:
      summary: 'Upload your invoice'
      description: |-
        YOUR fiscal invoice for the goods — Biklo does not issue it. Send a multipart `file`, or a `url` we reference without downloading.

        Required scope: `orders.write`.
      operationId: 'postV1OrdersIdInvoice'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                order_id: 711
                seller_invoice: 'https://erp.example.com/invoices/FCT-2026-001.pdf'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              url: 'https://erp.example.com/invoices/FCT-2026-001.pdf'
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/orders/{id}/reject:
    post:
      summary: 'Reject an order'
      description: |-
        Refunds the buyer for this order. Possible while the order is pending or accepted.

        Required scope: `orders.write`.
      operationId: 'postV1OrdersIdReject'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 711
                reference: 'SBXORD-SJP6NHXY'
                status: 'rejected'
                can_accept: false
                has_awb: true
                total:
                  amount: 359800
                  currency: 'RON'
                refunded:
                  amount: 0
                  currency: 'RON'
                items:
                  - id: 1123
                    product_id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    quantity: 2
                    quantity_ordered: 2
                    quantity_short: 0
                    unit_price:
                      amount: 179900
                      currency: 'RON'
                    total_price:
                      amount: 359800
                      currency: 'RON'
                awb:
                  number: 'SBX0000000711'
                  tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000000711'
                is_dropshipping: false
                created_at: '2026-09-11T09:20:14Z'
                updated_at: '2026-09-11T10:02:47Z'
                accepted_at: '2026-09-11T10:02:47Z'
                delivered_at: null
                expires_at: '2026-09-13T09:20:14Z'
                notes_from_buyer: 'Please call before delivery.'
                courier_id: 1
                seller_invoice: null
                fees:
                  platform_fee: 17990
                  shipping: 2500
                  currency: 'RON'
                delivery:
                  recipient: 'John Doe'
                  phone: '07xxxxxxxx'
                  city: 'Craiova'
                  county: 'Dolj'
                  postcode: '200000'
                  country: 'RO'
                  is_locker: false
                refunds: []
                parcels:
                  - id: 4012
                    sequence_no: 1
                    weight_kg: 2.4
                    length_cm: 40
                    width_cm: 30
                    height_cm: 20
                    is_seller_declared: true
                    items:
                      - order_item_id: 1123
                        quantity: 2
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/product-groups:
    post:
      summary: 'Create or re-link a variant group'
      description: |-
        One product sold in several sizes or colours. Each variant is its own product with its own price and stock; the group links them so the storefront shows one card with a picker. Pushing the same group again re-links it (200) instead of creating a second one (201).

        Required scope: `products.write`.
      operationId: 'postV1ProductGroups'
      tags:
        - 'Products'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                external_group_id: 'ERP-1001-GROUP'
                group_id: 904
                count: 2
                variants:
                  - product_id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001-S'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    price:
                      amount: 249900
                    stock: 4
                    size: 'S'
                    color: 'Negru'
                    gender: null
                    is_representative: true
                  - product_id: 237225
                    external_id: 'ERP-1001-M'
                    sku: 'MTB-29-001-M'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    price:
                      amount: 249900
                    stock: 2
                    size: 'M'
                    color: 'Negru'
                    gender: null
                    is_representative: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              external_group_id: 'ERP-1001-GROUP'
              products:
                - external_id: 'ERP-1001'
                  size: 'S'
                  color: 'Negru'
                - external_id: 'ERP-1001-M'
                  size: 'M'
                  color: 'Negru'
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/batch:
    post:
      summary: 'Bulk upsert'
      description: |-
        Up to 1000 products, worked through on a queue. Returns immediately with a batch id — NOTHING is written yet. Poll the batch for per-item results. Each product takes every field of `POST /v1/products`, `images` included, so a whole catalogue — pictures and all — is a handful of requests.

        Required scope: `products.write`.
      operationId: 'postV1ProductsBatch'
      tags:
        - 'Products'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                batch_id: 'batch_v4lfngtgb6sxqkzwagrqv8c2'
                status: 'queued'
                total: 1
                message: 'Accepted. Nothing is written yet — poll GET /v1/products/batch/{id} for per-item results.'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              products:
                - external_id: 'ERP-1001'
                  title: 'Bicicleta MTB Hardtail 29 inch'
                  description: 'A hardtail mountain bike in very good condition.'
                  category_id: 4291
                  price:
                    amount: 249900
                  stock: 4
                  attributes:
                    - field_id: 32
                      option_id: 226
                    - field_id: 47
                      option_id: 422
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/{id}/archive:
    post:
      summary: 'Archive a product'
      description: |-
        Takes the listing off the marketplace: out of search, the storefront and every cart. Use it when a product leaves your catalogue — stock `0` alone keeps it visible and unbuyable (a sell-out by Biklo orders is different: that archives it, and restocking relists it). Archived as if you had switched it off in the dashboard, so an order that is cancelled later never puts it back on sale. Idempotent; the listing, its id and its history stay, and `POST /v1/products/{id}/unarchive` brings it back.

        Required scope: `products.write`.
      operationId: 'postV1ProductsIdArchive'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 237224
                external_id: 'ERP-1001'
                sku: 'MTB-29-001'
                gtin: null
                mpn: null
                ean: null
                title: 'Bicicleta MTB Hardtail 29 inch'
                description: 'A hardtail mountain bike in very good condition, barely used.'
                category_id: 4291
                status: 'archived'
                is_reviewed: true
                price:
                  amount: 249900
                  currency: 'RON'
                  negotiable: true
                stock: 4
                shipping:
                  ship_with_us: true
                  free_shipping: false
                  shipping_class: 'bike'
                  parcel_tier: 'large'
                  weight_kg: 14.5
                  width_cm: 80
                  height_cm: 120
                  length_cm: 180
                group_id: null
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                attributes:
                  - field_id: 32
                    option_id: 226
                    value: null
                created_at: '2026-09-01T08:14:22Z'
                updated_at: '2026-09-11T16:02:51Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/{id}/images:
    post:
      summary: 'Add images'
      description: |-
        Two ways, mixable in one call: `images` as URLs (referenced, nothing downloaded — the way supplier feeds work) and/or `files` as multipart uploads onto our storage. Position 0 is the primary image. For URLs, sending `images` with the product itself (`POST /v1/products`, `PUT`, or the batch) saves this request entirely — this endpoint is for uploads and for adding to what a listing has.

        Required scope: `products.write`.
      operationId: 'postV1ProductsIdImages'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                attached_from_urls: 2
                uploaded: 0
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                  - id: 108876840
                    position: 1
                    path: null
                    source_url: 'https://cdn.example.com/erp/mtb-side.jpg'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              images:
                - url: 'https://cdn.example.com/erp/mtb-front.jpg'
                - url: 'https://cdn.example.com/erp/mtb-side.jpg'
              replace: false
      security:
        - bearerAuth:
            - 'products.write'
  /v1/products/{id}/unarchive:
    post:
      summary: 'Put a product back on sale'
      description: |-
        The opposite of archive, with a fresh 90-day lease so the expiry job does not archive it again straight away. Idempotent on a listing that is already active. A listing a Biklo order sold out comes back on its own when you send stock above 0, so this is mainly for listings you archived. Refused with `product_reserved` (409) only for a listing with no stock left while an order for it is still in progress — if that order is cancelled or rejected, the product comes back by itself.

        Required scope: `products.write`.
      operationId: 'postV1ProductsIdUnarchive'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 237224
                external_id: 'ERP-1001'
                sku: 'MTB-29-001'
                gtin: null
                mpn: null
                ean: null
                title: 'Bicicleta MTB Hardtail 29 inch'
                description: 'A hardtail mountain bike in very good condition, barely used.'
                category_id: 4291
                status: 'active'
                is_reviewed: true
                price:
                  amount: 249900
                  currency: 'RON'
                  negotiable: true
                stock: 4
                shipping:
                  ship_with_us: true
                  free_shipping: false
                  shipping_class: 'bike'
                  parcel_tier: 'large'
                  weight_kg: 14.5
                  width_cm: 80
                  height_cm: 120
                  length_cm: 180
                group_id: null
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                attributes:
                  - field_id: 32
                    option_id: 226
                    value: null
                created_at: '2026-09-01T08:14:22Z'
                updated_at: '2026-09-11T16:02:51Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'products.write'
  /v1/questions/{id}/answer:
    post:
      summary: 'Answer a question'
      description: |-
        Answers are moderated exactly as they are on the site. Check `is_published`: when it is false the answer is held for review and is NOT yet on the listing, so tell your user that rather than showing it as live.

        Required scope: `questions.write`.
      operationId: 'postV1QuestionsIdAnswer'
      tags:
        - 'Questions'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  id: 15
                  question_id: 31
                  text: 'Size L — suits 180-190 cm.'
                  status: 'published'
                  is_published: true
                  created_at: '2026-09-10T06:21:57Z'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              text: 'Size L — suits 180-190 cm.'
      security:
        - bearerAuth:
            - 'questions.write'
  /v1/returns/{id}/accept:
    post:
      summary: 'Accept a return'
      description: |-
        Takes the ORDER id. You checked the returned product and it is fine: the buyer is refunded the price of the returned lines from the held money. Only once the return parcel is delivered to you and before `inspection.deadline_at` (`GET /v1/returns`). Refused with 409: `return_not_delivered` (the parcel is not back yet), `return_not_open` (already decided, or the Biklo team decides it now), `inspection_deadline_passed`, `return_decision_failed` (the refund did not go through; nothing changed). On an order paid before Biklo Payments it only marks the order returned. Returns the order.

        Required scope: `orders.write`.
      operationId: 'postV1ReturnsIdAccept'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 711
                reference: 'SBXORD-SJP6NHXY'
                status: 'returned'
                can_accept: false
                has_awb: true
                total:
                  amount: 359800
                  currency: 'RON'
                refunded:
                  amount: 0
                  currency: 'RON'
                items:
                  - id: 1123
                    product_id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    quantity: 2
                    quantity_ordered: 2
                    quantity_short: 0
                    unit_price:
                      amount: 179900
                      currency: 'RON'
                    total_price:
                      amount: 359800
                      currency: 'RON'
                awb:
                  number: 'SBX0000000711'
                  tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000000711'
                is_dropshipping: false
                created_at: '2026-09-11T09:20:14Z'
                updated_at: '2026-09-11T10:02:47Z'
                accepted_at: '2026-09-11T10:02:47Z'
                delivered_at: null
                expires_at: '2026-09-13T09:20:14Z'
                notes_from_buyer: 'Please call before delivery.'
                courier_id: 1
                seller_invoice: null
                fees:
                  platform_fee: 17990
                  shipping: 2500
                  currency: 'RON'
                delivery:
                  recipient: 'John Doe'
                  phone: '07xxxxxxxx'
                  city: 'Craiova'
                  county: 'Dolj'
                  postcode: '200000'
                  country: 'RO'
                  is_locker: false
                refunds: []
                parcels:
                  - id: 4012
                    sequence_no: 1
                    weight_kg: 2.4
                    length_cm: 40
                    width_cm: 30
                    height_cm: 20
                    is_seller_declared: true
                    items:
                      - order_item_id: 1123
                        quantity: 2
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/returns/{id}/reject:
    post:
      summary: 'Reject a return'
      description: |-
        Takes the ORDER id. The returned product is not what was sent, or it came back damaged: this opens a dispute for the Biklo team, who decide — refund in full, refund part, or no refund. The money stays held meanwhile; you get `return.escalated`, then `return.resolved`. Same timing and the same 409 refusals as accept. Returns the order.

        Required scope: `orders.write`.
      operationId: 'postV1ReturnsIdReject'
      tags:
        - 'Orders'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 711
                reference: 'SBXORD-SJP6NHXY'
                status: 'returned'
                can_accept: false
                has_awb: true
                total:
                  amount: 359800
                  currency: 'RON'
                refunded:
                  amount: 0
                  currency: 'RON'
                items:
                  - id: 1123
                    product_id: 237224
                    external_id: 'ERP-1001'
                    sku: 'MTB-29-001'
                    title: 'Bicicleta MTB Hardtail 29 inch'
                    quantity: 2
                    quantity_ordered: 2
                    quantity_short: 0
                    unit_price:
                      amount: 179900
                      currency: 'RON'
                    total_price:
                      amount: 359800
                      currency: 'RON'
                awb:
                  number: 'SBX0000000711'
                  tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000000711'
                is_dropshipping: false
                created_at: '2026-09-11T09:20:14Z'
                updated_at: '2026-09-11T10:02:47Z'
                accepted_at: '2026-09-11T10:02:47Z'
                delivered_at: null
                expires_at: '2026-09-13T09:20:14Z'
                notes_from_buyer: 'Please call before delivery.'
                courier_id: 1
                seller_invoice: null
                fees:
                  platform_fee: 17990
                  shipping: 2500
                  currency: 'RON'
                delivery:
                  recipient: 'John Doe'
                  phone: '07xxxxxxxx'
                  city: 'Craiova'
                  county: 'Dolj'
                  postcode: '200000'
                  country: 'RO'
                  is_locker: false
                refunds: []
                parcels:
                  - id: 4012
                    sequence_no: 1
                    weight_kg: 2.4
                    length_cm: 40
                    width_cm: 30
                    height_cm: 20
                    is_seller_declared: true
                    items:
                      - order_item_id: 1123
                        quantity: 2
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              reason: 'The returned bike has a cracked frame that was not there when we shipped it. Photos sent by email.'
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/sandbox/messages:
    post:
      summary: 'Sandbox: have a buyer write to you'
      description: |-
        Sandbox only. Buyers are the ones who START conversations and the sandbox has none, so without this your inbox is permanently empty. A synthetic buyer opens (or continues) a conversation about one of your own listings, through the same write path a real buyer uses.

        Required scope: `messages.write`.

        **Sandbox only** — this route does not exist in production.
      operationId: 'postV1SandboxMessages'
      tags:
        - 'Sandbox test data'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  thread_id: 107373
                  message_id: 174420
                  product_id: 237233
                  from: 'buyer'
                  body: 'Is this still available?'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              product_id: 237233
              body: 'Is this still available?'
      security:
        - bearerAuth:
            - 'messages.write'
  /v1/sandbox/orders:
    post:
      summary: 'Create a test order (sandbox only)'
      description: |-
        404 in production. The sandbox has no buyers, so this fabricates an order from a synthetic buyer against one of your own products. No payment exists and no courier is contacted. It sends `order.created` to your webhooks like a real order does — even though you asked for it, because it stands in for a buyer.

        Required scope: `orders.write`.

        **Sandbox only** — this route does not exist in production.
      operationId: 'postV1SandboxOrders'
      tags:
        - 'Sandbox test data'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                order:
                  id: 711
                  reference: 'SBXORD-SJP6NHXY'
                  status: 'pending'
                  can_accept: false
                  has_awb: true
                  total:
                    amount: 359800
                    currency: 'RON'
                  refunded:
                    amount: 0
                    currency: 'RON'
                  items:
                    - id: 1123
                      product_id: 237224
                      external_id: 'ERP-1001'
                      sku: 'MTB-29-001'
                      title: 'Bicicleta MTB Hardtail 29 inch'
                      quantity: 2
                      quantity_ordered: 2
                      quantity_short: 0
                      unit_price:
                        amount: 179900
                        currency: 'RON'
                      total_price:
                        amount: 359800
                        currency: 'RON'
                  awb:
                    number: 'SBX0000000711'
                    tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000000711'
                  is_dropshipping: false
                  created_at: '2026-09-11T09:20:14Z'
                  updated_at: '2026-09-11T10:02:47Z'
                  accepted_at: '2026-09-11T10:02:47Z'
                  delivered_at: null
                  expires_at: '2026-09-13T09:20:14Z'
                  notes_from_buyer: 'Please call before delivery.'
                  courier_id: 1
                  seller_invoice: null
                  fees:
                    platform_fee: 17990
                    shipping: 2500
                    currency: 'RON'
                  delivery:
                    recipient: 'John Doe'
                    phone: '07xxxxxxxx'
                    city: 'Craiova'
                    county: 'Dolj'
                    postcode: '200000'
                    country: 'RO'
                    is_locker: false
                  refunds: []
                  parcels:
                    - id: 4012
                      sequence_no: 1
                      weight_kg: 2.4
                      length_cm: 40
                      width_cm: 30
                      height_cm: 20
                      is_seller_declared: true
                      items:
                        - order_item_id: 1123
                          quantity: 2
                note: 'A test order from a synthetic buyer. No payment exists and no courier was contacted.'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              external_id: 'ERP-1001'
              quantity: 2
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/sandbox/orders/{id}/advance:
    post:
      summary: 'Advance a test order (sandbox only)'
      description: |-
        404 in production. Plays the buyer and the courier: walks the order to the next step, or straight to the one you name, in seconds instead of days. It behaves like production — the order's own `status` only goes `pending → accepted`; after that the courier steps add courier events to the AWB (booking the sandbox courier first if nobody has) and the order stays `accepted`. Follow the parcel on `GET /v1/orders/{id}/tracking`; `delivered` also stamps `delivered_at` and starts the return window, as a real courier's delivery does.

        Required scope: `orders.write`.

        **Sandbox only** — this route does not exist in production.
      operationId: 'postV1SandboxOrdersIdAdvance'
      tags:
        - 'Sandbox test data'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                from: 'in_delivery'
                to: 'delivered'
                order:
                  id: 711
                  reference: 'SBXORD-SJP6NHXY'
                  status: 'accepted'
                  can_accept: false
                  has_awb: true
                  total:
                    amount: 359800
                    currency: 'RON'
                  refunded:
                    amount: 0
                    currency: 'RON'
                  items:
                    - id: 1123
                      product_id: 237224
                      external_id: 'ERP-1001'
                      sku: 'MTB-29-001'
                      title: 'Bicicleta MTB Hardtail 29 inch'
                      quantity: 2
                      quantity_ordered: 2
                      quantity_short: 0
                      unit_price:
                        amount: 179900
                        currency: 'RON'
                      total_price:
                        amount: 359800
                        currency: 'RON'
                  awb:
                    number: 'SBX0000000711'
                    tracking_url: 'https://sandbox-api.biklo.com/track/SBX0000000711'
                  is_dropshipping: false
                  created_at: '2026-09-11T09:20:14Z'
                  updated_at: '2026-09-11T10:02:47Z'
                  accepted_at: '2026-09-11T10:02:47Z'
                  delivered_at: null
                  expires_at: '2026-09-13T09:20:14Z'
                  notes_from_buyer: 'Please call before delivery.'
                  courier_id: 1
                  seller_invoice: null
                  fees:
                    platform_fee: 17990
                    shipping: 2500
                    currency: 'RON'
                  delivery:
                    recipient: 'John Doe'
                    phone: '07xxxxxxxx'
                    city: 'Craiova'
                    county: 'Dolj'
                    postcode: '200000'
                    country: 'RO'
                    is_locker: false
                  refunds: []
                  parcels:
                    - id: 4012
                      sequence_no: 1
                      weight_kg: 2.4
                      length_cm: 40
                      width_cm: 30
                      height_cm: 20
                      is_seller_declared: true
                      items:
                        - order_item_id: 1123
                          quantity: 2
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              status: 'delivered'
      security:
        - bearerAuth:
            - 'orders.write'
  /v1/sandbox/questions:
    post:
      summary: 'Sandbox: have a buyer ask a question'
      description: |-
        Sandbox only. `published_by_sandbox` is true when auto-publish is off and we published the question anyway so you have something readable to integrate against.

        Required scope: `questions.write`.

        **Sandbox only** — this route does not exist in production.
      operationId: 'postV1SandboxQuestions'
      tags:
        - 'Sandbox test data'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  question_id: 31
                  product_id: 237233
                  text: 'What frame size is this?'
                  status: 'published'
                  published_by_sandbox: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              product_id: 237233
              text: 'What frame size is this?'
      security:
        - bearerAuth:
            - 'questions.write'
  /v1/sandbox/withdrawals/advance:
    post:
      summary: 'Sandbox: skip the settlement wait'
      description: |-
        Sandbox only. Stripe test-mode payouts are REAL payouts and sit `pending` until Stripe settles them, which takes days. This skips the waiting and nothing else — Stripe is never simulated, only its clock is short-circuited.

        Required scope: `wallet.withdraw`.

        **Sandbox only** — this route does not exist in production.
      operationId: 'postV1SandboxWithdrawalsAdvance'
      tags:
        - 'Sandbox test data'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  payouts_created: 1
                  lots_marked_paid_out: 3
                  errors: []
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'wallet.withdraw'
  /v1/threads/{id}/read:
    post:
      summary: 'Mark a conversation read'
      description: |-
        Call this once your own inbox has shown the messages. Without it the seller dashboard keeps reporting conversations as unread that your users have already dealt with.

        Required scope: `messages.write`.
      operationId: 'postV1ThreadsIdRead'
      tags:
        - 'Threads'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                data:
                  id: 107373
                  is_unread: false
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'messages.write'
  /v1/webhooks/deliveries/{deliveryId}/replay:
    post:
      summary: 'Replay a delivery'
      description: |-
        Re-sends with the SAME event_id, so your handler can deduplicate.

        Required scope: `webhooks.manage`.
      operationId: 'postV1WebhooksDeliveriesDeliveryIdReplay'
      tags:
        - 'Webhooks'
      parameters:
        - name: 'deliveryId'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Delivery id from the webhook delivery log'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 3
                status: 'pending'
                replayed: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'webhooks.manage'
  /v1/webhooks/{id}/enable:
    post:
      summary: 'Re-enable an endpoint'
      description: |-
        We switch an endpoint off after 20 consecutive failures. Once you have fixed it, this brings it back and clears the counter.

        Required scope: `webhooks.manage`.
      operationId: 'postV1WebhooksIdEnable'
      tags:
        - 'Webhooks'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                id: 1
                is_active: true
                consecutive_failures: 0
                disabled_at: null
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'webhooks.manage'
  /v1/webhooks/{id}/test:
    post:
      summary: 'Send yourself a test webhook'
      description: |-
        Queues a `test.ping` to this endpoint so you can wire up a receiver without creating a real order first. It travels the **same path as every real event** — same queue, same headers, same HMAC signature — so a delivery that arrives and verifies here proves the real ones will too. Sent regardless of what the endpoint subscribes to, because an integrator testing a receiver has not necessarily decided which events they want yet. `202` means queued, not delivered: the outcome appears on `GET /v1/webhooks/{id}/deliveries` a moment later. Refused with `409 endpoint_disabled` if the endpoint is switched off.

        Required scope: `webhooks.manage`.
      operationId: 'postV1WebhooksIdTest'
      tags:
        - 'Webhooks'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                queued: true
                delivery_id: 9412
                event_id: 'evt_94q9tgtrsqymkrnwjdxbyfeh'
                event: 'test.ping'
                url: 'https://erp.example.com/hooks/biklo'
                deliveries_url: '/v1/webhooks/1/deliveries'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth:
            - 'webhooks.manage'
  /v1/company/settings:
    put:
      summary: 'Update order settings'
      description: |-
        Today the only writable setting is `allow_price_negotiation` — whether buyers may send price offers on your listings. Fee absorption is changed through /v1/company/shipping-absorption, because it carries rules a toggle cannot express.

        Required scope: `company.write`.
      operationId: 'putV1CompanySettings'
      tags:
        - 'Company'
      parameters: []
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                settings:
                  allow_price_negotiation: true
                  fees:
                    absorb_platform_fee: false
                    absorb_shipping_local: true
                    absorb_shipping_international: false
                    absorption_is_locked: true
                  shipping:
                    can_ship_with_us: true
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              allow_price_negotiation: true
      security:
        - bearerAuth:
            - 'company.write'
  /v1/products/{id}/images/order:
    put:
      summary: 'Reorder images'
      description: |-
        Ids you do not name keep their relative order after the ones you do. The first is the primary image.

        Required scope: `products.write`.
      operationId: 'putV1ProductsIdImagesOrder'
      tags:
        - 'Products'
      parameters:
        - name: 'id'
          in: 'path'
          required: true
          schema:
            type: 'string'
          description: 'Resource id'
      responses:
        '200':
          description: 'Success'
          content:
            application/json:
              schema:
                type: 'object'
              example:
                images:
                  - id: 108876841
                    position: 0
                    path: 'files/237224/mtb-front.jpg'
                    source_url: null
                  - id: 108876840
                    position: 1
                    path: null
                    source_url: 'https://cdn.example.com/erp/mtb-side.jpg'
        '401':
          description: 'Missing, malformed, revoked, expired or wrong-environment key'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'The key lacks the required scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'The request was understood but breaks a business rule'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limited — see the Retry-After header'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: 'object'
            example:
              image_ids:
                - 108876841
                - 108876840
                - 108876839
      security:
        - bearerAuth:
            - 'products.write'
