{
  "openapi": "3.0.4",
  "info": {
    "title": "QrX Public API",
    "description": "The QrX Public API lets merchants create and manage pay-at-the-door transactions, products, returns and webhooks. Authenticate by exchanging your merchant channel API key for a short-lived access token via POST /api/v1/auth/token, then send it as a Bearer token.",
    "contact": {
      "name": "QrX API Support",
      "url": "https://qr-x.info",
      "email": "support@qr-x.net"
    },
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://api.qr-x.net",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/v1/auth/token": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Create access token",
        "description": "Exchanges a merchant channel API key for a short-lived bearer token. Use this token in the Authorization header for all other Public API calls.\n\nRate limit: 60 requests per minute per merchant API key, with an IP fallback when no API key is supplied.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicAccessTokenResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicAccessTokenResponse"
                },
                "example": {
                  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.example-signature",
                  "tokenType": "Bearer",
                  "expiresIn": 3600,
                  "MerchantChannelName": "QrX Store"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.example-signature",
                      "tokenType": "Bearer",
                      "expiresIn": 3600,
                      "MerchantChannelName": "QrX Store"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicAccessTokenResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "MerchantApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/products": {
      "get": {
        "tags": [
          "Products"
        ],
        "summary": "List products",
        "description": "Returns products available through the authenticated merchant channel, including pagination metadata for catalog synchronization.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeArchived",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicProductSummaryResponse"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicProductSummaryResponse"
                  }
                },
                "example": {
                  "data": [
                    {
                      "productId": 101,
                      "sku": "TSHIRT-BASIC",
                      "title": "Basic T-Shirt",
                      "currency": "EUR",
                      "price": 24.9,
                      "availableQuantity": 100,
                      "isArchived": false,
                      "variantCount": 2,
                      "optionGroupCount": 1,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:05:00Z"
                    }
                  ],
                  "pagination": {
                    "pageNumber": 1,
                    "pageSize": 20,
                    "totalItemCount": 1,
                    "pageCount": 1,
                    "hasNextPage": false,
                    "hasPreviousPage": false
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "data": [
                        {
                          "productId": 101,
                          "sku": "TSHIRT-BASIC",
                          "title": "Basic T-Shirt",
                          "currency": "EUR",
                          "price": 24.9,
                          "availableQuantity": 100,
                          "isArchived": false,
                          "variantCount": 2,
                          "optionGroupCount": 1,
                          "createdAt": "2026-04-23T09:00:00Z",
                          "updatedAt": "2026-04-23T09:05:00Z"
                        }
                      ],
                      "pagination": {
                        "pageNumber": 1,
                        "pageSize": 20,
                        "totalItemCount": 1,
                        "pageCount": 1,
                        "hasNextPage": false,
                        "hasPreviousPage": false
                      }
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicProductSummaryResponse"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Products"
        ],
        "summary": "Create product",
        "description": "Creates a product with optional variants, option groups, tags, images, pricing, and availability information for use in QrX ordering and catalog flows.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicProductUpsertRequest"
              },
              "example": {
                "defaultLocale": "en",
                "sku": "TSHIRT-BASIC",
                "title": "Basic T-Shirt",
                "unit": "pcs",
                "currency": "EUR",
                "price": 24.9,
                "vatPercent": 21,
                "availableQuantity": 100,
                "description": "Soft cotton tee",
                "imageUrls": [
                  "https://merchant.example.com/images/tshirt-basic.jpg"
                ],
                "tags": [
                  "apparel",
                  "spring"
                ],
                "variants": [
                  {
                    "sku": "TSHIRT-BASIC-S",
                    "name": "Small",
                    "description": "Small size",
                    "price": 24.9,
                    "imageUrl": null,
                    "sortOrder": 1,
                    "isActive": true
                  },
                  {
                    "sku": "TSHIRT-BASIC-M",
                    "name": "Medium",
                    "description": "Medium size",
                    "price": 24.9,
                    "imageUrl": null,
                    "sortOrder": 2,
                    "isActive": true
                  }
                ],
                "optionGroups": [
                  {
                    "title": "Gift Wrap",
                    "description": "Optional wrap",
                    "required": false,
                    "allowMultiple": false,
                    "sortOrder": 1,
                    "options": [
                      {
                        "sku": "GIFT-WRAP-RED",
                        "name": "Red Wrap",
                        "description": "Festive red wrapping",
                        "price": 2.5,
                        "imageUrl": null,
                        "sortOrder": 1,
                        "isActive": true
                      }
                    ]
                  }
                ]
              },
              "examples": {
                "default": {
                  "summary": "Example",
                  "value": {
                    "defaultLocale": "en",
                    "sku": "TSHIRT-BASIC",
                    "title": "Basic T-Shirt",
                    "unit": "pcs",
                    "currency": "EUR",
                    "price": 24.9,
                    "vatPercent": 21,
                    "availableQuantity": 100,
                    "description": "Soft cotton tee",
                    "imageUrls": [
                      "https://merchant.example.com/images/tshirt-basic.jpg"
                    ],
                    "tags": [
                      "apparel",
                      "spring"
                    ],
                    "variants": [
                      {
                        "sku": "TSHIRT-BASIC-S",
                        "name": "Small",
                        "description": "Small size",
                        "price": 24.9,
                        "imageUrl": null,
                        "sortOrder": 1,
                        "isActive": true
                      },
                      {
                        "sku": "TSHIRT-BASIC-M",
                        "name": "Medium",
                        "description": "Medium size",
                        "price": 24.9,
                        "imageUrl": null,
                        "sortOrder": 2,
                        "isActive": true
                      }
                    ],
                    "optionGroups": [
                      {
                        "title": "Gift Wrap",
                        "description": "Optional wrap",
                        "required": false,
                        "allowMultiple": false,
                        "sortOrder": 1,
                        "options": [
                          {
                            "sku": "GIFT-WRAP-RED",
                            "name": "Red Wrap",
                            "description": "Festive red wrapping",
                            "price": 2.5,
                            "imageUrl": null,
                            "sortOrder": 1,
                            "isActive": true
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicProductUpsertRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicProductUpsertRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                },
                "example": {
                  "productId": 101,
                  "sku": "TSHIRT-BASIC",
                  "title": "Basic T-Shirt",
                  "currency": "EUR",
                  "price": 24.9,
                  "availableQuantity": 100,
                  "isArchived": false,
                  "variantCount": 2,
                  "optionGroupCount": 1,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:05:00Z",
                  "defaultLocale": "en",
                  "unit": "pcs",
                  "vatPercent": 21,
                  "description": "Soft cotton tee",
                  "imageUrls": [
                    "https://merchant.example.com/images/tshirt-basic.jpg"
                  ],
                  "tags": [
                    "apparel",
                    "spring"
                  ],
                  "variants": [
                    {
                      "variantId": 2001,
                      "sku": "TSHIRT-BASIC-S",
                      "name": "Small",
                      "description": "Small size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 1,
                      "isActive": true
                    },
                    {
                      "variantId": 2002,
                      "sku": "TSHIRT-BASIC-M",
                      "name": "Medium",
                      "description": "Medium size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 2,
                      "isActive": true
                    }
                  ],
                  "optionGroups": [
                    {
                      "optionGroupId": 301,
                      "title": "Gift Wrap",
                      "description": "Optional wrap",
                      "required": false,
                      "allowMultiple": false,
                      "sortOrder": 1,
                      "options": [
                        {
                          "optionId": 4001,
                          "sku": "GIFT-WRAP-RED",
                          "name": "Red Wrap",
                          "description": "Festive red wrapping",
                          "price": 2.5,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        }
                      ]
                    }
                  ],
                  "rowVersion": "18277"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "productId": 101,
                      "sku": "TSHIRT-BASIC",
                      "title": "Basic T-Shirt",
                      "currency": "EUR",
                      "price": 24.9,
                      "availableQuantity": 100,
                      "isArchived": false,
                      "variantCount": 2,
                      "optionGroupCount": 1,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:05:00Z",
                      "defaultLocale": "en",
                      "unit": "pcs",
                      "vatPercent": 21,
                      "description": "Soft cotton tee",
                      "imageUrls": [
                        "https://merchant.example.com/images/tshirt-basic.jpg"
                      ],
                      "tags": [
                        "apparel",
                        "spring"
                      ],
                      "variants": [
                        {
                          "variantId": 2001,
                          "sku": "TSHIRT-BASIC-S",
                          "name": "Small",
                          "description": "Small size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        },
                        {
                          "variantId": 2002,
                          "sku": "TSHIRT-BASIC-M",
                          "name": "Medium",
                          "description": "Medium size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 2,
                          "isActive": true
                        }
                      ],
                      "optionGroups": [
                        {
                          "optionGroupId": 301,
                          "title": "Gift Wrap",
                          "description": "Optional wrap",
                          "required": false,
                          "allowMultiple": false,
                          "sortOrder": 1,
                          "options": [
                            {
                              "optionId": 4001,
                              "sku": "GIFT-WRAP-RED",
                              "name": "Red Wrap",
                              "description": "Festive red wrapping",
                              "price": 2.5,
                              "imageUrl": null,
                              "sortOrder": 1,
                              "isActive": true
                            }
                          ]
                        }
                      ],
                      "rowVersion": "18277"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/products/{productId}": {
      "get": {
        "tags": [
          "Products"
        ],
        "summary": "Get product",
        "description": "Returns the full product configuration for one product owned by the authenticated merchant channel.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                },
                "example": {
                  "productId": 101,
                  "sku": "TSHIRT-BASIC",
                  "title": "Basic T-Shirt",
                  "currency": "EUR",
                  "price": 24.9,
                  "availableQuantity": 100,
                  "isArchived": false,
                  "variantCount": 2,
                  "optionGroupCount": 1,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:05:00Z",
                  "defaultLocale": "en",
                  "unit": "pcs",
                  "vatPercent": 21,
                  "description": "Soft cotton tee",
                  "imageUrls": [
                    "https://merchant.example.com/images/tshirt-basic.jpg"
                  ],
                  "tags": [
                    "apparel",
                    "spring"
                  ],
                  "variants": [
                    {
                      "variantId": 2001,
                      "sku": "TSHIRT-BASIC-S",
                      "name": "Small",
                      "description": "Small size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 1,
                      "isActive": true
                    },
                    {
                      "variantId": 2002,
                      "sku": "TSHIRT-BASIC-M",
                      "name": "Medium",
                      "description": "Medium size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 2,
                      "isActive": true
                    }
                  ],
                  "optionGroups": [
                    {
                      "optionGroupId": 301,
                      "title": "Gift Wrap",
                      "description": "Optional wrap",
                      "required": false,
                      "allowMultiple": false,
                      "sortOrder": 1,
                      "options": [
                        {
                          "optionId": 4001,
                          "sku": "GIFT-WRAP-RED",
                          "name": "Red Wrap",
                          "description": "Festive red wrapping",
                          "price": 2.5,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        }
                      ]
                    }
                  ],
                  "rowVersion": "18277"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "productId": 101,
                      "sku": "TSHIRT-BASIC",
                      "title": "Basic T-Shirt",
                      "currency": "EUR",
                      "price": 24.9,
                      "availableQuantity": 100,
                      "isArchived": false,
                      "variantCount": 2,
                      "optionGroupCount": 1,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:05:00Z",
                      "defaultLocale": "en",
                      "unit": "pcs",
                      "vatPercent": 21,
                      "description": "Soft cotton tee",
                      "imageUrls": [
                        "https://merchant.example.com/images/tshirt-basic.jpg"
                      ],
                      "tags": [
                        "apparel",
                        "spring"
                      ],
                      "variants": [
                        {
                          "variantId": 2001,
                          "sku": "TSHIRT-BASIC-S",
                          "name": "Small",
                          "description": "Small size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        },
                        {
                          "variantId": 2002,
                          "sku": "TSHIRT-BASIC-M",
                          "name": "Medium",
                          "description": "Medium size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 2,
                          "isActive": true
                        }
                      ],
                      "optionGroups": [
                        {
                          "optionGroupId": 301,
                          "title": "Gift Wrap",
                          "description": "Optional wrap",
                          "required": false,
                          "allowMultiple": false,
                          "sortOrder": 1,
                          "options": [
                            {
                              "optionId": 4001,
                              "sku": "GIFT-WRAP-RED",
                              "name": "Red Wrap",
                              "description": "Festive red wrapping",
                              "price": 2.5,
                              "imageUrl": null,
                              "sortOrder": 1,
                              "isActive": true
                            }
                          ]
                        }
                      ],
                      "rowVersion": "18277"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Products"
        ],
        "summary": "Update product",
        "description": "Updates a product, including variants, option groups, tags, images, pricing, availability, and catalog metadata.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicProductUpsertRequest"
              },
              "example": {
                "defaultLocale": "en",
                "sku": "TSHIRT-BASIC",
                "title": "Basic T-Shirt",
                "unit": "pcs",
                "currency": "EUR",
                "price": 24.9,
                "vatPercent": 21,
                "availableQuantity": 100,
                "description": "Soft cotton tee",
                "imageUrls": [
                  "https://merchant.example.com/images/tshirt-basic.jpg"
                ],
                "tags": [
                  "apparel",
                  "spring"
                ],
                "variants": [
                  {
                    "sku": "TSHIRT-BASIC-S",
                    "name": "Small",
                    "description": "Small size",
                    "price": 24.9,
                    "imageUrl": null,
                    "sortOrder": 1,
                    "isActive": true
                  },
                  {
                    "sku": "TSHIRT-BASIC-M",
                    "name": "Medium",
                    "description": "Medium size",
                    "price": 24.9,
                    "imageUrl": null,
                    "sortOrder": 2,
                    "isActive": true
                  }
                ],
                "optionGroups": [
                  {
                    "title": "Gift Wrap",
                    "description": "Optional wrap",
                    "required": false,
                    "allowMultiple": false,
                    "sortOrder": 1,
                    "options": [
                      {
                        "sku": "GIFT-WRAP-RED",
                        "name": "Red Wrap",
                        "description": "Festive red wrapping",
                        "price": 2.5,
                        "imageUrl": null,
                        "sortOrder": 1,
                        "isActive": true
                      }
                    ]
                  }
                ]
              },
              "examples": {
                "default": {
                  "summary": "Example",
                  "value": {
                    "defaultLocale": "en",
                    "sku": "TSHIRT-BASIC",
                    "title": "Basic T-Shirt",
                    "unit": "pcs",
                    "currency": "EUR",
                    "price": 24.9,
                    "vatPercent": 21,
                    "availableQuantity": 100,
                    "description": "Soft cotton tee",
                    "imageUrls": [
                      "https://merchant.example.com/images/tshirt-basic.jpg"
                    ],
                    "tags": [
                      "apparel",
                      "spring"
                    ],
                    "variants": [
                      {
                        "sku": "TSHIRT-BASIC-S",
                        "name": "Small",
                        "description": "Small size",
                        "price": 24.9,
                        "imageUrl": null,
                        "sortOrder": 1,
                        "isActive": true
                      },
                      {
                        "sku": "TSHIRT-BASIC-M",
                        "name": "Medium",
                        "description": "Medium size",
                        "price": 24.9,
                        "imageUrl": null,
                        "sortOrder": 2,
                        "isActive": true
                      }
                    ],
                    "optionGroups": [
                      {
                        "title": "Gift Wrap",
                        "description": "Optional wrap",
                        "required": false,
                        "allowMultiple": false,
                        "sortOrder": 1,
                        "options": [
                          {
                            "sku": "GIFT-WRAP-RED",
                            "name": "Red Wrap",
                            "description": "Festive red wrapping",
                            "price": 2.5,
                            "imageUrl": null,
                            "sortOrder": 1,
                            "isActive": true
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicProductUpsertRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicProductUpsertRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                },
                "example": {
                  "productId": 101,
                  "sku": "TSHIRT-BASIC",
                  "title": "Basic T-Shirt",
                  "currency": "EUR",
                  "price": 24.9,
                  "availableQuantity": 100,
                  "isArchived": false,
                  "variantCount": 2,
                  "optionGroupCount": 1,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:05:00Z",
                  "defaultLocale": "en",
                  "unit": "pcs",
                  "vatPercent": 21,
                  "description": "Soft cotton tee",
                  "imageUrls": [
                    "https://merchant.example.com/images/tshirt-basic.jpg"
                  ],
                  "tags": [
                    "apparel",
                    "spring"
                  ],
                  "variants": [
                    {
                      "variantId": 2001,
                      "sku": "TSHIRT-BASIC-S",
                      "name": "Small",
                      "description": "Small size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 1,
                      "isActive": true
                    },
                    {
                      "variantId": 2002,
                      "sku": "TSHIRT-BASIC-M",
                      "name": "Medium",
                      "description": "Medium size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 2,
                      "isActive": true
                    }
                  ],
                  "optionGroups": [
                    {
                      "optionGroupId": 301,
                      "title": "Gift Wrap",
                      "description": "Optional wrap",
                      "required": false,
                      "allowMultiple": false,
                      "sortOrder": 1,
                      "options": [
                        {
                          "optionId": 4001,
                          "sku": "GIFT-WRAP-RED",
                          "name": "Red Wrap",
                          "description": "Festive red wrapping",
                          "price": 2.5,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        }
                      ]
                    }
                  ],
                  "rowVersion": "18277"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "productId": 101,
                      "sku": "TSHIRT-BASIC",
                      "title": "Basic T-Shirt",
                      "currency": "EUR",
                      "price": 24.9,
                      "availableQuantity": 100,
                      "isArchived": false,
                      "variantCount": 2,
                      "optionGroupCount": 1,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:05:00Z",
                      "defaultLocale": "en",
                      "unit": "pcs",
                      "vatPercent": 21,
                      "description": "Soft cotton tee",
                      "imageUrls": [
                        "https://merchant.example.com/images/tshirt-basic.jpg"
                      ],
                      "tags": [
                        "apparel",
                        "spring"
                      ],
                      "variants": [
                        {
                          "variantId": 2001,
                          "sku": "TSHIRT-BASIC-S",
                          "name": "Small",
                          "description": "Small size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        },
                        {
                          "variantId": 2002,
                          "sku": "TSHIRT-BASIC-M",
                          "name": "Medium",
                          "description": "Medium size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 2,
                          "isActive": true
                        }
                      ],
                      "optionGroups": [
                        {
                          "optionGroupId": 301,
                          "title": "Gift Wrap",
                          "description": "Optional wrap",
                          "required": false,
                          "allowMultiple": false,
                          "sortOrder": 1,
                          "options": [
                            {
                              "optionId": 4001,
                              "sku": "GIFT-WRAP-RED",
                              "name": "Red Wrap",
                              "description": "Festive red wrapping",
                              "price": 2.5,
                              "imageUrl": null,
                              "sortOrder": 1,
                              "isActive": true
                            }
                          ]
                        }
                      ],
                      "rowVersion": "18277"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Products"
        ],
        "summary": "Delete product",
        "description": "Deletes a product from the authenticated merchant channel when deletion is allowed. Prefer archiving when you need to keep historical catalog context.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/products/{productId}/archive": {
      "post": {
        "tags": [
          "Products"
        ],
        "summary": "Archive product",
        "description": "Archives a product so it is no longer active in catalog and ordering flows while keeping the record available for history and recovery.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                },
                "example": {
                  "productId": 101,
                  "sku": "TSHIRT-BASIC",
                  "title": "Basic T-Shirt",
                  "currency": "EUR",
                  "price": 24.9,
                  "availableQuantity": 100,
                  "isArchived": false,
                  "variantCount": 2,
                  "optionGroupCount": 1,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:05:00Z",
                  "defaultLocale": "en",
                  "unit": "pcs",
                  "vatPercent": 21,
                  "description": "Soft cotton tee",
                  "imageUrls": [
                    "https://merchant.example.com/images/tshirt-basic.jpg"
                  ],
                  "tags": [
                    "apparel",
                    "spring"
                  ],
                  "variants": [
                    {
                      "variantId": 2001,
                      "sku": "TSHIRT-BASIC-S",
                      "name": "Small",
                      "description": "Small size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 1,
                      "isActive": true
                    },
                    {
                      "variantId": 2002,
                      "sku": "TSHIRT-BASIC-M",
                      "name": "Medium",
                      "description": "Medium size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 2,
                      "isActive": true
                    }
                  ],
                  "optionGroups": [
                    {
                      "optionGroupId": 301,
                      "title": "Gift Wrap",
                      "description": "Optional wrap",
                      "required": false,
                      "allowMultiple": false,
                      "sortOrder": 1,
                      "options": [
                        {
                          "optionId": 4001,
                          "sku": "GIFT-WRAP-RED",
                          "name": "Red Wrap",
                          "description": "Festive red wrapping",
                          "price": 2.5,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        }
                      ]
                    }
                  ],
                  "rowVersion": "18277"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "productId": 101,
                      "sku": "TSHIRT-BASIC",
                      "title": "Basic T-Shirt",
                      "currency": "EUR",
                      "price": 24.9,
                      "availableQuantity": 100,
                      "isArchived": false,
                      "variantCount": 2,
                      "optionGroupCount": 1,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:05:00Z",
                      "defaultLocale": "en",
                      "unit": "pcs",
                      "vatPercent": 21,
                      "description": "Soft cotton tee",
                      "imageUrls": [
                        "https://merchant.example.com/images/tshirt-basic.jpg"
                      ],
                      "tags": [
                        "apparel",
                        "spring"
                      ],
                      "variants": [
                        {
                          "variantId": 2001,
                          "sku": "TSHIRT-BASIC-S",
                          "name": "Small",
                          "description": "Small size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        },
                        {
                          "variantId": 2002,
                          "sku": "TSHIRT-BASIC-M",
                          "name": "Medium",
                          "description": "Medium size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 2,
                          "isActive": true
                        }
                      ],
                      "optionGroups": [
                        {
                          "optionGroupId": 301,
                          "title": "Gift Wrap",
                          "description": "Optional wrap",
                          "required": false,
                          "allowMultiple": false,
                          "sortOrder": 1,
                          "options": [
                            {
                              "optionId": 4001,
                              "sku": "GIFT-WRAP-RED",
                              "name": "Red Wrap",
                              "description": "Festive red wrapping",
                              "price": 2.5,
                              "imageUrl": null,
                              "sortOrder": 1,
                              "isActive": true
                            }
                          ]
                        }
                      ],
                      "rowVersion": "18277"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/products/{productId}/unarchive": {
      "post": {
        "tags": [
          "Products"
        ],
        "summary": "Unarchive product",
        "description": "Restores an archived product so it can be used again in catalog and ordering flows.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                },
                "example": {
                  "productId": 101,
                  "sku": "TSHIRT-BASIC",
                  "title": "Basic T-Shirt",
                  "currency": "EUR",
                  "price": 24.9,
                  "availableQuantity": 100,
                  "isArchived": false,
                  "variantCount": 2,
                  "optionGroupCount": 1,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:05:00Z",
                  "defaultLocale": "en",
                  "unit": "pcs",
                  "vatPercent": 21,
                  "description": "Soft cotton tee",
                  "imageUrls": [
                    "https://merchant.example.com/images/tshirt-basic.jpg"
                  ],
                  "tags": [
                    "apparel",
                    "spring"
                  ],
                  "variants": [
                    {
                      "variantId": 2001,
                      "sku": "TSHIRT-BASIC-S",
                      "name": "Small",
                      "description": "Small size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 1,
                      "isActive": true
                    },
                    {
                      "variantId": 2002,
                      "sku": "TSHIRT-BASIC-M",
                      "name": "Medium",
                      "description": "Medium size",
                      "price": 24.9,
                      "imageUrl": null,
                      "sortOrder": 2,
                      "isActive": true
                    }
                  ],
                  "optionGroups": [
                    {
                      "optionGroupId": 301,
                      "title": "Gift Wrap",
                      "description": "Optional wrap",
                      "required": false,
                      "allowMultiple": false,
                      "sortOrder": 1,
                      "options": [
                        {
                          "optionId": 4001,
                          "sku": "GIFT-WRAP-RED",
                          "name": "Red Wrap",
                          "description": "Festive red wrapping",
                          "price": 2.5,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        }
                      ]
                    }
                  ],
                  "rowVersion": "18277"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "productId": 101,
                      "sku": "TSHIRT-BASIC",
                      "title": "Basic T-Shirt",
                      "currency": "EUR",
                      "price": 24.9,
                      "availableQuantity": 100,
                      "isArchived": false,
                      "variantCount": 2,
                      "optionGroupCount": 1,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:05:00Z",
                      "defaultLocale": "en",
                      "unit": "pcs",
                      "vatPercent": 21,
                      "description": "Soft cotton tee",
                      "imageUrls": [
                        "https://merchant.example.com/images/tshirt-basic.jpg"
                      ],
                      "tags": [
                        "apparel",
                        "spring"
                      ],
                      "variants": [
                        {
                          "variantId": 2001,
                          "sku": "TSHIRT-BASIC-S",
                          "name": "Small",
                          "description": "Small size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 1,
                          "isActive": true
                        },
                        {
                          "variantId": 2002,
                          "sku": "TSHIRT-BASIC-M",
                          "name": "Medium",
                          "description": "Medium size",
                          "price": 24.9,
                          "imageUrl": null,
                          "sortOrder": 2,
                          "isActive": true
                        }
                      ],
                      "optionGroups": [
                        {
                          "optionGroupId": 301,
                          "title": "Gift Wrap",
                          "description": "Optional wrap",
                          "required": false,
                          "allowMultiple": false,
                          "sortOrder": 1,
                          "options": [
                            {
                              "optionId": 4001,
                              "sku": "GIFT-WRAP-RED",
                              "name": "Red Wrap",
                              "description": "Festive red wrapping",
                              "price": 2.5,
                              "imageUrl": null,
                              "sortOrder": 1,
                              "isActive": true
                            }
                          ]
                        }
                      ],
                      "rowVersion": "18277"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicProductResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/reference/carriers": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List carriers",
        "description": "Returns the carriers that can be referenced when creating transactions or shipments through the Public API.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/reference/locales": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List locales",
        "description": "Returns supported locale codes for localized payment pages, customer communication, and transaction content.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/reference/countries": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List countries",
        "description": "Returns supported destination country codes and names for transaction and shipment creation.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/reference/shipping-methods": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List shipping methods",
        "description": "Returns the shipping methods configured for the authenticated merchant channel. Use these codes in create transaction requests when you want QrX to create or prepare carrier labels.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/reference/senders": {
      "get": {
        "tags": [
          "Reference"
        ],
        "summary": "List sender addresses",
        "description": "Returns sender address references configured for the authenticated merchant channel. Use the sender code in parcel requests when a specific sender location should be used.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns": {
      "get": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "includeTestMode",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnPageOfPublicReturnSummary"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnPageOfPublicReturnSummary"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnPageOfPublicReturnSummary"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{idOrRma}": {
      "get": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "idOrRma",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnDetail"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnDetail"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnDetail"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/receipt-facts": {
      "get": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicReturnReceiptFact"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicReturnReceiptFact"
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicReturnReceiptFact"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReceiptFactRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReceiptFactRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReceiptFactRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/events": {
      "get": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "afterSequence",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64",
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnPageOfPublicReturnEvent"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnPageOfPublicReturnEvent"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicReturnPageOfPublicReturnEvent"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/approve": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/reject": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/cancel": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/request-information": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnInformationRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnInformationRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnInformationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/acknowledge-information": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnDecisionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/receipt-facts/{factId}/supersede": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "factId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReceiptFactSupersedeRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReceiptFactSupersedeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReceiptFactSupersedeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/evidence": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/resolution": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnResolutionIntentRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnResolutionIntentRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnResolutionIntentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "get": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/resolution/acknowledge": {
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnResolutionAckRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnResolutionAckRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnResolutionAckRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/returns/{id}/messages": {
      "get": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Returns"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnMessageRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnMessageRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicReturnMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/transactions": {
      "post": {
        "tags": [
          "Transactions"
        ],
        "summary": "Create transaction",
        "description": "Creates a new QrX transaction and starts the payment provider process when a PSP is required.\n\nImportant: PSP processing is handled asynchronously in the background. A successful response from this endpoint means that the transaction was accepted by QrX and that the PSP process was started. It does not guarantee that the payment provider successfully created the payment session, payment link, or checkout transaction.\n\nThe PSP process can still fail after the API response has been returned, for example because of missing PSP configuration, invalid merchant credentials, missing required payment data, or a provider-side validation error.\n\nIf PSP creation fails, QrX marks the transaction as Cancelled and reports the final status through the configured webhook flow. Always listen to transaction webhooks and use the webhook status as the source of truth for the final transaction state.\n\nDo not rely only on the immediate API response to decide whether a transaction is payable or ready for fulfillment. Always verify the latest transaction status before printing shipping labels, printing packing slips, shipping goods, or triggering downstream fulfillment.\n\nRate limit: 300 requests per minute per authenticated merchant channel. Carriers like UPS are exempt from this transaction endpoint limits.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCreateTransactionRequest"
              },
              "example": {
                "transactionType": "Payment",
                "amount": 20.27,
                "currency": "EUR",
                "locale": "en_US",
                "testMode": true,
                "orderDetails": {
                  "orderId": "SHOP-100045",
                  "firstName": "Reyhan",
                  "lastName": "Savvy",
                  "email": "devlord1@gmail.com",
                  "phoneNumber": "+316777298172",
                  "company": null,
                  "vatNumber": null,
                  "shippingAddressType": "Residential",
                  "address1": "Max Euweplein",
                  "address2": null,
                  "houseNumber": "6",
                  "zipcode": "1017 MB",
                  "city": "Amsterdam",
                  "country": "NL",
                  "reference": "MyRefInMyWMS99282",
                  "shopOrderId": "2128721",
                  "customerLocale": "nl_NL",
                  "trackingNumber": "1Z999AA10123456784",
                  "trackingLink": "https://www.ups.com/track?tracknum=1Z999AA10123456784",
                  "orderlines": [
                    {
                      "name": "43 inch FHD Smart TV",
                      "productId": 13882,
                      "variantId": 212212121,
                      "sku": "FN43GE320",
                      "ean": "978020137962",
                      "quantity": 1,
                      "weight": 1,
                      "tax": 1.74,
                      "pricePerItem": 20.27,
                      "totalPrice": 20.27,
                      "countryOfOrigin": "NL",
                      "hsCode": "852872"
                    }
                  ]
                },
                "parcel": {
                  "shippingMethodCode": "ups-standard",
                  "senderCode": "main-warehouse-nl",
                  "createCarrierLabel": true,
                  "applyShippingRules": true,
                  "colliCount": 1,
                  "colliDetails": [
                    {
                      "colliNumber": 1,
                      "description": "43 inch FHD Smart TV",
                      "currency": "EUR",
                      "customsValue": 20.27,
                      "weight": 1,
                      "length": 20,
                      "width": 20,
                      "height": 10
                    }
                  ],
                  "destinationAddress": {
                    "firstName": "Reyhan",
                    "lastName": "Savvy",
                    "company": null,
                    "address1": "Max Euweplein",
                    "address2": null,
                    "houseNumber": "6",
                    "zipcode": "1017 MB",
                    "city": "Amsterdam",
                    "shippingAddressType": "Residential",
                    "countryCode": "NL",
                    "phoneNumber": "+316777298172",
                    "email": "devlord1@gmail.com"
                  },
                  "returnLabel": true,
                  "carrierLabelType": "Zpl"
                }
              },
              "examples": {
                "default": {
                  "summary": "Example",
                  "value": {
                    "transactionType": "Payment",
                    "amount": 20.27,
                    "currency": "EUR",
                    "locale": "en_US",
                    "testMode": true,
                    "orderDetails": {
                      "orderId": "SHOP-100045",
                      "firstName": "Reyhan",
                      "lastName": "Savvy",
                      "email": "devlord1@gmail.com",
                      "phoneNumber": "+316777298172",
                      "company": null,
                      "vatNumber": null,
                      "shippingAddressType": "Residential",
                      "address1": "Max Euweplein",
                      "address2": null,
                      "houseNumber": "6",
                      "zipcode": "1017 MB",
                      "city": "Amsterdam",
                      "country": "NL",
                      "reference": "MyRefInMyWMS99282",
                      "shopOrderId": "2128721",
                      "customerLocale": "nl_NL",
                      "trackingNumber": "1Z999AA10123456784",
                      "trackingLink": "https://www.ups.com/track?tracknum=1Z999AA10123456784",
                      "orderlines": [
                        {
                          "name": "43 inch FHD Smart TV",
                          "productId": 13882,
                          "variantId": 212212121,
                          "sku": "FN43GE320",
                          "ean": "978020137962",
                          "quantity": 1,
                          "weight": 1,
                          "tax": 1.74,
                          "pricePerItem": 20.27,
                          "totalPrice": 20.27,
                          "countryOfOrigin": "NL",
                          "hsCode": "852872"
                        }
                      ]
                    },
                    "parcel": {
                      "shippingMethodCode": "ups-standard",
                      "senderCode": "main-warehouse-nl",
                      "createCarrierLabel": true,
                      "applyShippingRules": true,
                      "colliCount": 1,
                      "colliDetails": [
                        {
                          "colliNumber": 1,
                          "description": "43 inch FHD Smart TV",
                          "currency": "EUR",
                          "customsValue": 20.27,
                          "weight": 1,
                          "length": 20,
                          "width": 20,
                          "height": 10
                        }
                      ],
                      "destinationAddress": {
                        "firstName": "Reyhan",
                        "lastName": "Savvy",
                        "company": null,
                        "address1": "Max Euweplein",
                        "address2": null,
                        "houseNumber": "6",
                        "zipcode": "1017 MB",
                        "city": "Amsterdam",
                        "shippingAddressType": "Residential",
                        "countryCode": "NL",
                        "phoneNumber": "+316777298172",
                        "email": "devlord1@gmail.com"
                      },
                      "returnLabel": true,
                      "carrierLabelType": "Zpl"
                    }
                  }
                }
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCreateTransactionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCreateTransactionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionResponse"
                },
                "example": {
                  "transactionId": "0a1999dc78dc4cac",
                  "qrCodeValue": "https://go.qr-x.app/tr/0a1999dc78dc4cac",
                  "qrCodeImage": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
                  "carrierName": "UPS",
                  "carrierShippingMethod": "UPS Standard",
                  "shippingLabels": [ ],
                  "shippingDocuments": [ ],
                  "carrierLabelType": "Zpl",
                  "pinCode": null
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "transactionId": "0a1999dc78dc4cac",
                      "qrCodeValue": "https://go.qr-x.app/tr/0a1999dc78dc4cac",
                      "qrCodeImage": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
                      "carrierName": "UPS",
                      "carrierShippingMethod": "UPS Standard",
                      "shippingLabels": [ ],
                      "shippingDocuments": [ ],
                      "carrierLabelType": "Zpl",
                      "pinCode": null
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/transactions/{transactionId}": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "summary": "Get transaction",
        "description": "Returns the current transaction details for a transaction that belongs to the authenticated merchant channel. Use this call for lookup and reconciliation, but use webhooks as the primary source of truth for status changes.\n\nRate limit: 1200 requests per minute per authenticated merchant channel. Carriers like UPS are exempt from this transaction endpoint limits.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionDetailsResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionDetailsResponse"
                },
                "example": {
                  "isTestMode": true,
                  "transactionId": "0a1999dc78dc4cac",
                  "status": "open",
                  "createdAt": "2026-04-22T12:00:00Z",
                  "paidAt": null,
                  "transactionPayoutProcessedDate": null,
                  "merchantChannelId": 2,
                  "paymentProviderId": 1,
                  "carrierId": 1,
                  "orderId": "SHOP-100045",
                  "shopOrderId": "2128721",
                  "orderCountry": "NL",
                  "description": "SHOP-100045",
                  "currency": "EUR",
                  "locale": "en_US",
                  "amount": 20.27,
                  "xpointsUsed": 0,
                  "paymentMethod": "",
                  "isRefunded": false,
                  "consumerName": "Reyhan Savvy",
                  "consumerEmail": "devlord1@gmail.com",
                  "transactionVerificationNumber": 4827
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "isTestMode": true,
                      "transactionId": "0a1999dc78dc4cac",
                      "status": "open",
                      "createdAt": "2026-04-22T12:00:00Z",
                      "paidAt": null,
                      "transactionPayoutProcessedDate": null,
                      "merchantChannelId": 2,
                      "paymentProviderId": 1,
                      "carrierId": 1,
                      "orderId": "SHOP-100045",
                      "shopOrderId": "2128721",
                      "orderCountry": "NL",
                      "description": "SHOP-100045",
                      "currency": "EUR",
                      "locale": "en_US",
                      "amount": 20.27,
                      "xpointsUsed": 0,
                      "paymentMethod": "",
                      "isRefunded": false,
                      "consumerName": "Reyhan Savvy",
                      "consumerEmail": "devlord1@gmail.com",
                      "transactionVerificationNumber": 4827
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionDetailsResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/transactions/{transactionId}/status": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "summary": "Get transaction status",
        "description": "Returns the latest lightweight transaction status fields. Use this to verify a transaction before fulfillment when you need an on-demand check in addition to webhook processing.\n\nRate limit: 1200 requests per minute per authenticated merchant channel. Carriers like UPS are exempt from this transaction endpoint limits.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionStatusResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionStatusResponse"
                },
                "example": {
                  "status": "open",
                  "transactionPayoutProcessedDate": null,
                  "transactionVerificationNumber": 4827
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "status": "open",
                      "transactionPayoutProcessedDate": null,
                      "transactionVerificationNumber": 4827
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicTransactionStatusResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/transactions/{transactionId}/ship": {
      "post": {
        "tags": [
          "Transactions"
        ],
        "summary": "Mark transaction as shipped",
        "description": "Marks an eligible transaction as shipped and stores the carrier tracking details supplied by your system. Only call this after you have verified that the transaction is valid for fulfillment.\n\nRate limit: 300 requests per minute per authenticated merchant channel. Carriers like UPS are exempt from this transaction endpoint limits.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicMarkShippedRequest"
              },
              "example": {
                "trackAndTraceNumber": "1Z999AA10123456784",
                "trackAndTraceUrl": "https://www.ups.com/track?tracknum=1Z999AA10123456784"
              },
              "examples": {
                "default": {
                  "summary": "Example",
                  "value": {
                    "trackAndTraceNumber": "1Z999AA10123456784",
                    "trackAndTraceUrl": "https://www.ups.com/track?tracknum=1Z999AA10123456784"
                  }
                }
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicMarkShippedRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicMarkShippedRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/transactions/{transactionId}/cancel": {
      "post": {
        "tags": [
          "Transactions"
        ],
        "summary": "Cancel transaction",
        "description": "Cancels an eligible open transaction with a merchant-provided reason. Cancelled transactions are no longer valid for payment, label printing, packing slips, or fulfillment.\n\nRate limit: 300 requests per minute per authenticated merchant channel. Carriers like UPS are exempt from this transaction endpoint limits.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCancelTransactionRequest"
              },
              "example": {
                "reason": "Customer cancelled the order before shipment"
              },
              "examples": {
                "default": {
                  "summary": "Example",
                  "value": {
                    "reason": "Customer cancelled the order before shipment"
                  }
                }
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCancelTransactionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicCancelTransactionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhooks",
        "description": "Returns configured webhooks for the authenticated merchant channel, including health and recent delivery state.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicWebhookSummaryResponse"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicWebhookSummaryResponse"
                  }
                },
                "example": {
                  "data": [
                    {
                      "webhookId": 18,
                      "name": "Order Events",
                      "targetUrl": "https://merchant.example.com/webhooks/qrx",
                      "eventTypes": [
                        "transaction/created",
                        "transaction/paid"
                      ],
                      "apiVersion": "2026-04-23",
                      "isActive": true,
                      "healthStatus": "healthy",
                      "consecutiveFailures": 0,
                      "lastSuccessAt": null,
                      "lastFailureAt": null,
                      "failureSince": null,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:00:00Z",
                      "version": 1
                    }
                  ],
                  "pagination": {
                    "pageNumber": 1,
                    "pageSize": 20,
                    "totalItemCount": 1,
                    "pageCount": 1,
                    "hasNextPage": false,
                    "hasPreviousPage": false
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "data": [
                        {
                          "webhookId": 18,
                          "name": "Order Events",
                          "targetUrl": "https://merchant.example.com/webhooks/qrx",
                          "eventTypes": [
                            "transaction/created",
                            "transaction/paid"
                          ],
                          "apiVersion": "2026-04-23",
                          "isActive": true,
                          "healthStatus": "healthy",
                          "consecutiveFailures": 0,
                          "lastSuccessAt": null,
                          "lastFailureAt": null,
                          "failureSince": null,
                          "createdAt": "2026-04-23T09:00:00Z",
                          "updatedAt": "2026-04-23T09:00:00Z",
                          "version": 1
                        }
                      ],
                      "pagination": {
                        "pageNumber": 1,
                        "pageSize": 20,
                        "totalItemCount": 1,
                        "pageCount": 1,
                        "hasNextPage": false,
                        "hasPreviousPage": false
                      }
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicWebhookSummaryResponse"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Create webhook",
        "description": "Creates a webhook endpoint for transaction and order events. Webhooks are required for reliable status synchronization because payment and provider processing can complete or fail asynchronously.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookUpsertRequest"
              },
              "example": {
                "name": "Order Events",
                "targetUrl": "https://merchant.example.com/webhooks/qrx",
                "eventTypes": [
                  "transaction/created",
                  "transaction/paid"
                ],
                "apiVersion": "2026-04-23",
                "isActive": true
              },
              "examples": {
                "default": {
                  "summary": "Example",
                  "value": {
                    "name": "Order Events",
                    "targetUrl": "https://merchant.example.com/webhooks/qrx",
                    "eventTypes": [
                      "transaction/created",
                      "transaction/paid"
                    ],
                    "apiVersion": "2026-04-23",
                    "isActive": true
                  }
                }
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookUpsertRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookUpsertRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                },
                "example": {
                  "webhookId": 18,
                  "name": "Order Events",
                  "targetUrl": "https://merchant.example.com/webhooks/qrx",
                  "eventTypes": [
                    "transaction/created",
                    "transaction/paid"
                  ],
                  "apiVersion": "2026-04-23",
                  "isActive": true,
                  "healthStatus": "healthy",
                  "consecutiveFailures": 0,
                  "lastSuccessAt": null,
                  "lastFailureAt": null,
                  "failureSince": null,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:00:00Z",
                  "version": 1,
                  "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "webhookId": 18,
                      "name": "Order Events",
                      "targetUrl": "https://merchant.example.com/webhooks/qrx",
                      "eventTypes": [
                        "transaction/created",
                        "transaction/paid"
                      ],
                      "apiVersion": "2026-04-23",
                      "isActive": true,
                      "healthStatus": "healthy",
                      "consecutiveFailures": 0,
                      "lastSuccessAt": null,
                      "lastFailureAt": null,
                      "failureSince": null,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:00:00Z",
                      "version": 1,
                      "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/event-types": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook event types",
        "description": "Returns the event types and API versions supported by the webhook system.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookEventTypesResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookEventTypesResponse"
                },
                "example": {
                  "eventTypes": [
                    "transaction/created",
                    "transaction/paid"
                  ],
                  "groups": {
                    "transaction": [
                      "transaction/created",
                      "transaction/paid"
                    ]
                  },
                  "apiVersions": [
                    "2026-04-23"
                  ],
                  "currentApiVersion": "2026-04-23"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "eventTypes": [
                        "transaction/created",
                        "transaction/paid"
                      ],
                      "groups": {
                        "transaction": [
                          "transaction/created",
                          "transaction/paid"
                        ]
                      },
                      "apiVersions": [
                        "2026-04-23"
                      ],
                      "currentApiVersion": "2026-04-23"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookEventTypesResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{webhookId}": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Get webhook",
        "description": "Returns the configuration and health state for one webhook owned by the authenticated merchant channel.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                },
                "example": {
                  "webhookId": 18,
                  "name": "Order Events",
                  "targetUrl": "https://merchant.example.com/webhooks/qrx",
                  "eventTypes": [
                    "transaction/created",
                    "transaction/paid"
                  ],
                  "apiVersion": "2026-04-23",
                  "isActive": true,
                  "healthStatus": "healthy",
                  "consecutiveFailures": 0,
                  "lastSuccessAt": null,
                  "lastFailureAt": null,
                  "failureSince": null,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:00:00Z",
                  "version": 1,
                  "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "webhookId": 18,
                      "name": "Order Events",
                      "targetUrl": "https://merchant.example.com/webhooks/qrx",
                      "eventTypes": [
                        "transaction/created",
                        "transaction/paid"
                      ],
                      "apiVersion": "2026-04-23",
                      "isActive": true,
                      "healthStatus": "healthy",
                      "consecutiveFailures": 0,
                      "lastSuccessAt": null,
                      "lastFailureAt": null,
                      "failureSince": null,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:00:00Z",
                      "version": 1,
                      "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Update webhook",
        "description": "Updates the configuration, target URL, event types, version, active state, or concurrency version for one webhook owned by the authenticated merchant channel.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookUpsertRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookUpsertRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookUpsertRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                },
                "example": {
                  "webhookId": 18,
                  "name": "Order Events",
                  "targetUrl": "https://merchant.example.com/webhooks/qrx",
                  "eventTypes": [
                    "transaction/created",
                    "transaction/paid"
                  ],
                  "apiVersion": "2026-04-23",
                  "isActive": true,
                  "healthStatus": "healthy",
                  "consecutiveFailures": 0,
                  "lastSuccessAt": null,
                  "lastFailureAt": null,
                  "failureSince": null,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:00:00Z",
                  "version": 1,
                  "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "webhookId": 18,
                      "name": "Order Events",
                      "targetUrl": "https://merchant.example.com/webhooks/qrx",
                      "eventTypes": [
                        "transaction/created",
                        "transaction/paid"
                      ],
                      "apiVersion": "2026-04-23",
                      "isActive": true,
                      "healthStatus": "healthy",
                      "consecutiveFailures": 0,
                      "lastSuccessAt": null,
                      "lastFailureAt": null,
                      "failureSince": null,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:00:00Z",
                      "version": 1,
                      "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete webhook",
        "description": "Deletes a webhook endpoint. After deletion, QrX will no longer deliver events to that target URL.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{webhookId}/test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Send test webhook",
        "description": "Queues a test delivery to the selected webhook so you can verify connectivity, authentication, and payload handling in your integration.\n\nRate limit: 60 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookTestRequest"
              },
              "example": {
                "eventType": "transaction/created"
              },
              "examples": {
                "default": {
                  "summary": "Example",
                  "value": {
                    "eventType": "transaction/created"
                  }
                }
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookTestRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PublicWebhookTestRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookTestResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookTestResponse"
                },
                "example": {
                  "success": true,
                  "httpStatusCode": 202,
                  "responseBody": "Event queued for delivery. Check delivery logs for results.",
                  "elapsedMs": 0,
                  "error": null
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "success": true,
                      "httpStatusCode": 202,
                      "responseBody": "Event queued for delivery. Check delivery logs for results.",
                      "elapsedMs": 0,
                      "error": null
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookTestResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{webhookId}/enable": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Enable webhook",
        "description": "Re-enables a webhook endpoint after it was disabled or paused.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                },
                "example": {
                  "webhookId": 18,
                  "name": "Order Events",
                  "targetUrl": "https://merchant.example.com/webhooks/qrx",
                  "eventTypes": [
                    "transaction/created",
                    "transaction/paid"
                  ],
                  "apiVersion": "2026-04-23",
                  "isActive": true,
                  "healthStatus": "healthy",
                  "consecutiveFailures": 0,
                  "lastSuccessAt": null,
                  "lastFailureAt": null,
                  "failureSince": null,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:00:00Z",
                  "version": 1,
                  "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "webhookId": 18,
                      "name": "Order Events",
                      "targetUrl": "https://merchant.example.com/webhooks/qrx",
                      "eventTypes": [
                        "transaction/created",
                        "transaction/paid"
                      ],
                      "apiVersion": "2026-04-23",
                      "isActive": true,
                      "healthStatus": "healthy",
                      "consecutiveFailures": 0,
                      "lastSuccessAt": null,
                      "lastFailureAt": null,
                      "failureSince": null,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:00:00Z",
                      "version": 1,
                      "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{webhookId}/rotate-secret": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Rotate webhook signing secret",
        "description": "Generates a new signing secret for the webhook. Update your receiver before relying on signature validation for future deliveries.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                },
                "example": {
                  "webhookId": 18,
                  "name": "Order Events",
                  "targetUrl": "https://merchant.example.com/webhooks/qrx",
                  "eventTypes": [
                    "transaction/created",
                    "transaction/paid"
                  ],
                  "apiVersion": "2026-04-23",
                  "isActive": true,
                  "healthStatus": "healthy",
                  "consecutiveFailures": 0,
                  "lastSuccessAt": null,
                  "lastFailureAt": null,
                  "failureSince": null,
                  "createdAt": "2026-04-23T09:00:00Z",
                  "updatedAt": "2026-04-23T09:00:00Z",
                  "version": 1,
                  "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "webhookId": 18,
                      "name": "Order Events",
                      "targetUrl": "https://merchant.example.com/webhooks/qrx",
                      "eventTypes": [
                        "transaction/created",
                        "transaction/paid"
                      ],
                      "apiVersion": "2026-04-23",
                      "isActive": true,
                      "healthStatus": "healthy",
                      "consecutiveFailures": 0,
                      "lastSuccessAt": null,
                      "lastFailureAt": null,
                      "failureSince": null,
                      "createdAt": "2026-04-23T09:00:00Z",
                      "updatedAt": "2026-04-23T09:00:00Z",
                      "version": 1,
                      "signingSecret": "whsec_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{webhookId}/deliveries": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook deliveries",
        "description": "Returns recent delivery attempts for a webhook, including success, failure, response, and retry information.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicWebhookDeliverySummaryResponse"
                  }
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicWebhookDeliverySummaryResponse"
                  }
                },
                "example": {
                  "data": [
                    {
                      "deliveryId": 991,
                      "eventType": "transaction/paid",
                      "status": "failed",
                      "attemptNumber": 3,
                      "success": false,
                      "httpStatusCode": 500,
                      "transactionId": "0a1999dc78dc4cac",
                      "orderId": "SHOP-100045",
                      "errorMessage": "Merchant endpoint returned HTTP 500.",
                      "elapsedMs": 248,
                      "createdAt": "2026-04-23T09:45:00Z"
                    }
                  ],
                  "pagination": {
                    "pageNumber": 1,
                    "pageSize": 20,
                    "totalItemCount": 1,
                    "pageCount": 1,
                    "hasNextPage": false,
                    "hasPreviousPage": false
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "data": [
                        {
                          "deliveryId": 991,
                          "eventType": "transaction/paid",
                          "status": "failed",
                          "attemptNumber": 3,
                          "success": false,
                          "httpStatusCode": 500,
                          "transactionId": "0a1999dc78dc4cac",
                          "orderId": "SHOP-100045",
                          "errorMessage": "Merchant endpoint returned HTTP 500.",
                          "elapsedMs": 248,
                          "createdAt": "2026-04-23T09:45:00Z"
                        }
                      ],
                      "pagination": {
                        "pageNumber": 1,
                        "pageSize": 20,
                        "totalItemCount": 1,
                        "pageCount": 1,
                        "hasNextPage": false,
                        "hasPreviousPage": false
                      }
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PublicWebhookDeliverySummaryResponse"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{webhookId}/deliveries/{deliveryId}": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Get webhook delivery",
        "description": "Returns detailed request and response information for a single webhook delivery attempt.\n\nRate limit: 1200 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookDeliveryResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookDeliveryResponse"
                },
                "example": {
                  "deliveryId": 991,
                  "eventType": "transaction/paid",
                  "status": "failed",
                  "attemptNumber": 3,
                  "success": false,
                  "httpStatusCode": 500,
                  "transactionId": "0a1999dc78dc4cac",
                  "orderId": "SHOP-100045",
                  "errorMessage": "Merchant endpoint returned HTTP 500.",
                  "elapsedMs": 248,
                  "createdAt": "2026-04-23T09:45:00Z",
                  "targetUrl": "https://merchant.example.com/webhooks/qrx",
                  "requestBody": "{\"eventType\":\"transaction/paid\"}",
                  "responseBody": "{\"error\":\"temporary failure\"}"
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "deliveryId": 991,
                      "eventType": "transaction/paid",
                      "status": "failed",
                      "attemptNumber": 3,
                      "success": false,
                      "httpStatusCode": 500,
                      "transactionId": "0a1999dc78dc4cac",
                      "orderId": "SHOP-100045",
                      "errorMessage": "Merchant endpoint returned HTTP 500.",
                      "elapsedMs": 248,
                      "createdAt": "2026-04-23T09:45:00Z",
                      "targetUrl": "https://merchant.example.com/webhooks/qrx",
                      "requestBody": "{\"eventType\":\"transaction/paid\"}",
                      "responseBody": "{\"error\":\"temporary failure\"}"
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookDeliveryResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Redeliver webhook delivery",
        "description": "Queues a new attempt for a previous webhook delivery. Use this after your endpoint has recovered from a temporary failure.\n\nRate limit: 60 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookTestResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookTestResponse"
                },
                "example": {
                  "success": true,
                  "httpStatusCode": 202,
                  "responseBody": "Event queued for delivery. Check delivery logs for results.",
                  "elapsedMs": 0,
                  "error": null
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "success": true,
                      "httpStatusCode": 202,
                      "responseBody": "Event queued for delivery. Check delivery logs for results.",
                      "elapsedMs": 0,
                      "error": null
                    }
                  }
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicWebhookTestResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks/{webhookId}/deliveries/{deliveryId}/cancel": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Cancel webhook delivery",
        "description": "Cancels pending retry attempts for a webhook delivery that should no longer be sent.\n\nRate limit: 300 requests per minute per authenticated merchant channel.\n\nIf exceeded, QrX returns HTTP 429 with `Content-Type: application/problem+json`, `Retry-After`, and `RateLimit-Reason` headers. The response body uses code `RATE_LIMIT_EXCEEDED`; wait at least the number of seconds in `Retry-After` before retrying.",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "429": {
            "description": "Too many requests. The response includes Retry-After and RateLimit-Reason headers.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                  "title": "Rate Limit Exceeded",
                  "status": 429,
                  "detail": "Too many requests. Wait before retrying this endpoint.",
                  "code": "RATE_LIMIT_EXCEEDED",
                  "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                  "errors": [
                    {
                      "code": "RATE_LIMIT_EXCEEDED",
                      "message": "Too many requests. Wait before retrying this endpoint."
                    }
                  ]
                },
                "examples": {
                  "default": {
                    "summary": "Example",
                    "value": {
                      "type": "https://api.qr-x.app/problems/rate-limit-exceeded",
                      "title": "Rate Limit Exceeded",
                      "status": 429,
                      "detail": "Too many requests. Wait before retrying this endpoint.",
                      "code": "RATE_LIMIT_EXCEEDED",
                      "requestId": "00-f528ce4b4cbf4b1f8dfe49a4c46f0c54-97e0c3159aa6a13d-00",
                      "errors": [
                        {
                          "code": "RATE_LIMIT_EXCEEDED",
                          "message": "Too many requests. Wait before retrying this endpoint."
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "CarrierDocument": {
        "type": "object",
        "properties": {
          "document": {
            "type": "string",
            "nullable": true
          },
          "documentType": {
            "$ref": "#/components/schemas/CarrierDocumentType"
          }
        },
        "additionalProperties": false
      },
      "CarrierDocumentType": {
        "type": "string",
        "oneOf": [
          {
            "title": "Pdf",
            "enum": [
              "Pdf"
            ],
            "type": "string"
          },
          {
            "title": "Png",
            "enum": [
              "Png"
            ],
            "type": "string"
          },
          {
            "title": "Html",
            "enum": [
              "Html"
            ],
            "type": "string"
          }
        ],
        "x-enumNames": [
          "Pdf",
          "Png",
          "Html"
        ],
        "x-enumDescriptions": [
          "Pdf",
          "Png",
          "Html"
        ],
        "x-ms-enum": {
          "name": "CarrierDocumentType",
          "modelAsString": true,
          "values": [
            {
              "name": "Pdf",
              "value": "Pdf",
              "description": "Pdf"
            },
            {
              "name": "Png",
              "value": "Png",
              "description": "Png"
            },
            {
              "name": "Html",
              "value": "Html",
              "description": "Html"
            }
          ]
        }
      },
      "CarrierLabel": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "nullable": true
          },
          "labelWithQrX": {
            "type": "string",
            "nullable": true
          },
          "labelZplHack": {
            "type": "string",
            "nullable": true
          },
          "trackingNumber": {
            "type": "string",
            "nullable": true
          },
          "trackingLink": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CarrierLabelType": {
        "type": "string",
        "oneOf": [
          {
            "title": "Zpl",
            "enum": [
              "Zpl"
            ],
            "type": "string"
          },
          {
            "title": "Pdf",
            "enum": [
              "Pdf"
            ],
            "type": "string"
          },
          {
            "title": "Gif",
            "enum": [
              "Gif"
            ],
            "type": "string"
          }
        ],
        "x-enumNames": [
          "Zpl",
          "Pdf",
          "Gif"
        ],
        "x-enumDescriptions": [
          "Zpl",
          "Pdf",
          "Gif"
        ],
        "x-ms-enum": {
          "name": "CarrierLabelType",
          "modelAsString": true,
          "values": [
            {
              "name": "Zpl",
              "value": "Zpl",
              "description": "Zpl"
            },
            {
              "name": "Pdf",
              "value": "Pdf",
              "description": "Pdf"
            },
            {
              "name": "Gif",
              "value": "Gif",
              "description": "Gif"
            }
          ]
        }
      },
      "OrderAddressType": {
        "type": "string",
        "oneOf": [
          {
            "title": "Residential",
            "enum": [
              "Residential"
            ],
            "type": "string"
          },
          {
            "title": "Business",
            "enum": [
              "Business"
            ],
            "type": "string"
          }
        ],
        "x-enumNames": [
          "Residential",
          "Business"
        ],
        "x-enumDescriptions": [
          "Residential",
          "Business"
        ],
        "x-ms-enum": {
          "name": "OrderAddressType",
          "modelAsString": true,
          "values": [
            {
              "name": "Residential",
              "value": "Residential",
              "description": "Residential"
            },
            {
              "name": "Business",
              "value": "Business",
              "description": "Business"
            }
          ]
        }
      },
      "OrderLine": {
        "required": [
          "name",
          "pricePerItem",
          "quantity",
          "sku",
          "totalPrice",
          "weight"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string"
          },
          "productId": {
            "type": "integer",
            "format": "int64"
          },
          "variantId": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "sku": {
            "minLength": 1,
            "type": "string"
          },
          "ean": {
            "type": "string",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "format": "double"
          },
          "weight": {
            "type": "number",
            "format": "double"
          },
          "tax": {
            "type": "number",
            "format": "double"
          },
          "vatPercent": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "pricePerItem": {
            "type": "number",
            "format": "double"
          },
          "totalPrice": {
            "type": "number",
            "format": "double"
          },
          "optionsJson": {
            "type": "string",
            "nullable": true
          },
          "countryOfOrigin": {
            "maxLength": 265,
            "minLength": 0,
            "type": "string",
            "nullable": true
          },
          "hsCode": {
            "maxLength": 265,
            "minLength": 0,
            "type": "string",
            "nullable": true
          },
          "imageUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicAccessTokenResponse": {
        "type": "object",
        "properties": {
          "accessToken": {
            "type": "string",
            "nullable": true
          },
          "tokenType": {
            "type": "string",
            "nullable": true
          },
          "expiresIn": {
            "type": "integer",
            "format": "int32"
          },
          "merchantChannelName": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicAddressRequest": {
        "required": [
          "address1",
          "city",
          "countryCode",
          "firstName",
          "lastName",
          "zipcode"
        ],
        "type": "object",
        "properties": {
          "firstName": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Contact first name for this address."
          },
          "lastName": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Contact last name for this address."
          },
          "company": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional company name.",
            "nullable": true
          },
          "vatNumber": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional VAT number for business or customs documents.",
            "nullable": true
          },
          "email": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional contact email address.",
            "nullable": true
          },
          "phoneNumber": {
            "maxLength": 50,
            "minLength": 0,
            "type": "string",
            "description": "Optional contact phone number.",
            "nullable": true
          },
          "address1": {
            "maxLength": 256,
            "minLength": 2,
            "type": "string",
            "description": "Primary street address."
          },
          "address2": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional second address line such as apartment, unit, or building details.",
            "nullable": true
          },
          "houseNumber": {
            "maxLength": 25,
            "minLength": 0,
            "type": "string",
            "description": "Optional house number or building number. Recommended when available; may be omitted when the primary address line already contains it.",
            "nullable": true
          },
          "zipcode": {
            "maxLength": 10,
            "minLength": 2,
            "type": "string",
            "description": "Postal or ZIP code."
          },
          "city": {
            "maxLength": 265,
            "minLength": 2,
            "type": "string",
            "description": "City."
          },
          "state": {
            "maxLength": 265,
            "minLength": 0,
            "type": "string",
            "description": "Optional state.",
            "nullable": true
          },
          "province": {
            "maxLength": 265,
            "minLength": 0,
            "type": "string",
            "description": "Optional province.",
            "nullable": true
          },
          "shippingAddressType": {
            "$ref": "#/components/schemas/OrderAddressType"
          },
          "countryCode": {
            "maxLength": 2,
            "minLength": 2,
            "type": "string",
            "description": "Two-letter ISO country code, for example NL."
          }
        },
        "additionalProperties": false
      },
      "PublicCancelTransactionRequest": {
        "required": [
          "reason"
        ],
        "type": "object",
        "properties": {
          "reason": {
            "minLength": 1,
            "type": "string",
            "description": "Human-readable reason for cancelling the transaction."
          }
        },
        "additionalProperties": false
      },
      "PublicColliDetailsRequest": {
        "required": [
          "currency",
          "description"
        ],
        "type": "object",
        "properties": {
          "colliNumber": {
            "type": "integer",
            "description": "One-based parcel number within the shipment.",
            "format": "int32"
          },
          "description": {
            "minLength": 1,
            "type": "string",
            "description": "Description of the goods in this parcel. Required for customs and label generation."
          },
          "currency": {
            "minLength": 1,
            "type": "string",
            "description": "Three-letter ISO 4217 currency code for customs value, for example EUR."
          },
          "customsValue": {
            "minimum": 0.01,
            "type": "number",
            "description": "Declared customs value for this parcel.",
            "format": "double"
          },
          "weight": {
            "minimum": 1,
            "type": "number",
            "description": "Parcel weight in kilograms.",
            "format": "double"
          },
          "length": {
            "minimum": 1,
            "type": "number",
            "description": "Parcel length in centimeters.",
            "format": "double"
          },
          "width": {
            "minimum": 1,
            "type": "number",
            "description": "Parcel width in centimeters.",
            "format": "double"
          },
          "height": {
            "minimum": 1,
            "type": "number",
            "description": "Parcel height in centimeters.",
            "format": "double"
          },
          "hsCode": {
            "type": "string",
            "description": "Optional HS code for the goods in this parcel.",
            "nullable": true
          },
          "orderlines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLine"
            },
            "description": "Optional order lines assigned to this parcel.",
            "nullable": true
          },
          "trackAndTraceNumber": {
            "type": "string",
            "description": "Optional existing tracking number for this parcel.",
            "nullable": true
          },
          "trackAndTraceUrl": {
            "type": "string",
            "description": "Optional existing tracking URL for this parcel.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicCreateTransactionRequest": {
        "required": [
          "orderDetails"
        ],
        "type": "object",
        "properties": {
          "transactionType": {
            "$ref": "#/components/schemas/TransactionType"
          },
          "amount": {
            "minimum": 1,
            "type": "number",
            "description": "Total amount to collect from the customer. For Payment transactions this is the amount sent to the payment provider.",
            "format": "double"
          },
          "orderDetails": {
            "$ref": "#/components/schemas/PublicOrderDetailsRequest"
          },
          "parcel": {
            "$ref": "#/components/schemas/PublicParcelRequest"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/PublicAddressRequest"
          },
          "locale": {
            "type": "string",
            "description": "Optional locale used for customer-facing payment and communication content.",
            "nullable": true
          },
          "xpointsToUse": {
            "minimum": 0,
            "type": "number",
            "description": "Optional QrX wallet or points amount to apply to the transaction.",
            "format": "double"
          },
          "testMode": {
            "type": "boolean",
            "description": "When true, the transaction is created in QrX test mode. PSP processing uses sandbox or test configuration where available, no real PSP payment or payout is created, and the transaction must not be treated as production fulfillment."
          },
          "currency": {
            "maxLength": 3,
            "minLength": 3,
            "type": "string",
            "description": "Three-letter ISO 4217 currency code for the transaction amount, for example EUR.",
            "nullable": true
          },
          "expiresAt": {
            "type": "string",
            "description": "Optional UTC date and time after which the payment or transaction should no longer be considered payable.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicMarkShippedRequest": {
        "type": "object",
        "properties": {
          "trackAndTraceNumber": {
            "type": "string",
            "description": "Carrier tracking number for the shipped transaction.",
            "nullable": true
          },
          "trackAndTraceUrl": {
            "type": "string",
            "description": "Carrier tracking URL that customers or merchants can use to follow the shipment.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicOrderDetailsRequest": {
        "required": [
          "address1",
          "city",
          "country",
          "email",
          "firstName",
          "lastName",
          "orderId",
          "orderlines",
          "zipcode"
        ],
        "type": "object",
        "properties": {
          "orderId": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Your external order number or checkout reference. This value is shown in QrX and used for reconciliation."
          },
          "firstName": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Customer first name for delivery and customer communication."
          },
          "lastName": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Customer last name for delivery and customer communication."
          },
          "email": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Required customer email address. QrX uses this for payment links, receipts, verification, and PIN delivery."
          },
          "phoneNumber": {
            "maxLength": 50,
            "minLength": 0,
            "type": "string",
            "description": "Customer phone number for delivery, carrier, or verification communication.",
            "nullable": true
          },
          "company": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional company name for business deliveries.",
            "nullable": true
          },
          "vatNumber": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional customer VAT number for business or cross-border shipments.",
            "nullable": true
          },
          "shippingAddressType": {
            "$ref": "#/components/schemas/OrderAddressType"
          },
          "address1": {
            "maxLength": 256,
            "minLength": 2,
            "type": "string",
            "description": "Primary street address for delivery."
          },
          "address2": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional second address line such as apartment, unit, or building details.",
            "nullable": true
          },
          "houseNumber": {
            "maxLength": 25,
            "minLength": 0,
            "type": "string",
            "description": "Optional house number or building number for the delivery address. Recommended when available; may be omitted when the primary address line already contains it.",
            "nullable": true
          },
          "zipcode": {
            "maxLength": 10,
            "minLength": 2,
            "type": "string",
            "description": "Postal or ZIP code for the delivery address."
          },
          "city": {
            "maxLength": 265,
            "minLength": 2,
            "type": "string",
            "description": "City for the delivery address."
          },
          "country": {
            "maxLength": 2,
            "minLength": 2,
            "type": "string",
            "description": "Two-letter ISO country code for the delivery address, for example NL."
          },
          "reference": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional delivery or warehouse reference shown on shipment records when supported.",
            "nullable": true
          },
          "state": {
            "maxLength": 265,
            "minLength": 0,
            "type": "string",
            "description": "Optional state for addresses where state is required.",
            "nullable": true
          },
          "province": {
            "maxLength": 265,
            "minLength": 0,
            "type": "string",
            "description": "Optional province for addresses where province is required.",
            "nullable": true
          },
          "region": {
            "maxLength": 265,
            "minLength": 0,
            "type": "string",
            "description": "Optional region for addresses where region is required.",
            "nullable": true
          },
          "shopOrderId": {
            "maxLength": 265,
            "minLength": 0,
            "type": "string",
            "description": "Optional platform-specific order ID, for example the Shopify order ID.",
            "nullable": true
          },
          "orderlines": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLine"
            },
            "description": "One or more order lines describing the products in the transaction."
          },
          "customerLocale": {
            "maxLength": 5,
            "minLength": 5,
            "type": "string",
            "description": "Optional customer locale in language-country format, for example en_US or nl_NL.",
            "nullable": true
          },
          "trackingNumber": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional existing carrier tracking number if the shipment was created outside QrX.",
            "nullable": true
          },
          "trackingLink": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional existing carrier tracking URL if the shipment was created outside QrX.",
            "nullable": true
          },
          "pickupPointId": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional pickup point identifier when the order should be delivered to a pickup point.",
            "nullable": true
          },
          "pickupPointNetwork": {
            "maxLength": 256,
            "minLength": 0,
            "type": "string",
            "description": "Optional pickup point carrier or network name.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicParcelRequest": {
        "required": [
          "colliDetails",
          "destinationAddress",
          "senderCode",
          "shippingMethodCode"
        ],
        "type": "object",
        "properties": {
          "shippingMethodCode": {
            "minLength": 1,
            "type": "string",
            "description": "Shipping method code configured for the merchant channel. Use the reference shipping methods endpoint to retrieve valid values."
          },
          "createCarrierLabel": {
            "type": "boolean",
            "description": "When true, QrX attempts to create a carrier label for the transaction when the carrier and shipping method support it."
          },
          "sendTrackingCommunications": {
            "type": "boolean",
            "nullable": true
          },
          "applyShippingRules": {
            "type": "boolean",
            "description": "When true, QrX may apply configured merchant shipping rules before creating the shipment."
          },
          "colliCount": {
            "minimum": 1,
            "type": "integer",
            "description": "Number of parcels or packages in the shipment.",
            "format": "int32"
          },
          "colliDetails": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicColliDetailsRequest"
            },
            "description": "Dimensions, weight, customs value, and optional orderline data for each parcel."
          },
          "eori": {
            "type": "string",
            "description": "Optional EORI number used for customs where required.",
            "nullable": true
          },
          "senderCode": {
            "minLength": 1,
            "type": "string",
            "description": "Sender address code configured in QrX. Use the reference senders endpoint to retrieve valid sender codes."
          },
          "destinationAddress": {
            "$ref": "#/components/schemas/PublicAddressRequest"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/PublicAddressRequest"
          },
          "hsCode": {
            "type": "string",
            "description": "Optional default HS code for customs. Colli-level HS codes can override this.",
            "nullable": true
          },
          "returnLabel": {
            "type": "boolean",
            "description": "When true, QrX requests a return label when the selected carrier and method support it."
          },
          "carrierLabelType": {
            "$ref": "#/components/schemas/CarrierLabelType"
          },
          "accessorials": {
            "$ref": "#/components/schemas/PublicShipmentAccessorials"
          }
        },
        "additionalProperties": false
      },
      "PublicProductOptionGroupResponse": {
        "required": [
          "title"
        ],
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string"
          },
          "description": {
            "maxLength": 4000,
            "minLength": 0,
            "type": "string",
            "nullable": true
          },
          "required": {
            "type": "boolean"
          },
          "allowMultiple": {
            "type": "boolean"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicProductOptionResponse"
            },
            "nullable": true
          },
          "optionGroupId": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "PublicProductOptionGroupUpsertRequest": {
        "required": [
          "title"
        ],
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Option group title, for example Toppings, Size, or Add-ons."
          },
          "description": {
            "maxLength": 4000,
            "minLength": 0,
            "type": "string",
            "description": "Optional help text for this option group.",
            "nullable": true
          },
          "required": {
            "type": "boolean",
            "description": "Whether the customer must choose from this option group."
          },
          "allowMultiple": {
            "type": "boolean",
            "description": "Whether the customer can select more than one option from this group."
          },
          "sortOrder": {
            "type": "integer",
            "description": "Display order for this option group.",
            "format": "int32"
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicProductOptionUpsertRequest"
            },
            "description": "Options available inside this group.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicProductOptionResponse": {
        "required": [
          "name",
          "sku"
        ],
        "type": "object",
        "properties": {
          "sku": {
            "maxLength": 128,
            "minLength": 1,
            "type": "string"
          },
          "name": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string"
          },
          "description": {
            "maxLength": 4000,
            "minLength": 0,
            "type": "string",
            "nullable": true
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "format": "double"
          },
          "imageUrl": {
            "type": "string",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          },
          "optionId": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "PublicProductOptionUpsertRequest": {
        "required": [
          "name",
          "sku"
        ],
        "type": "object",
        "properties": {
          "sku": {
            "maxLength": 128,
            "minLength": 1,
            "type": "string",
            "description": "Unique SKU for this option within the product."
          },
          "name": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Option name shown to customers and merchants."
          },
          "description": {
            "maxLength": 4000,
            "minLength": 0,
            "type": "string",
            "description": "Optional option description.",
            "nullable": true
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "description": "Additional option price including VAT unless your integration explicitly stores prices differently.",
            "format": "double"
          },
          "imageUrl": {
            "type": "string",
            "description": "Public image URL for this option.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Display order for this option.",
            "format": "int32"
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether this option can be selected in catalog and ordering flows."
          }
        },
        "additionalProperties": false
      },
      "PublicProductResponse": {
        "type": "object",
        "properties": {
          "productId": {
            "type": "integer",
            "format": "int32"
          },
          "sku": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "availableQuantity": {
            "type": "integer",
            "format": "int64"
          },
          "isArchived": {
            "type": "boolean"
          },
          "variantCount": {
            "type": "integer",
            "format": "int32"
          },
          "optionGroupCount": {
            "type": "integer",
            "format": "int32"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "defaultLocale": {
            "type": "string",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "nullable": true
          },
          "vatPercent": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "imageUrls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicProductVariantResponse"
            },
            "nullable": true
          },
          "optionGroups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicProductOptionGroupResponse"
            },
            "nullable": true
          },
          "rowVersion": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicProductSummaryResponse": {
        "type": "object",
        "properties": {
          "productId": {
            "type": "integer",
            "format": "int32"
          },
          "sku": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "availableQuantity": {
            "type": "integer",
            "format": "int64"
          },
          "isArchived": {
            "type": "boolean"
          },
          "variantCount": {
            "type": "integer",
            "format": "int32"
          },
          "optionGroupCount": {
            "type": "integer",
            "format": "int32"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicProductUpsertRequest": {
        "required": [
          "defaultLocale",
          "sku",
          "title"
        ],
        "type": "object",
        "properties": {
          "defaultLocale": {
            "maxLength": 10,
            "minLength": 2,
            "type": "string",
            "description": "Default locale for the product content, for example en or nl."
          },
          "sku": {
            "maxLength": 128,
            "minLength": 1,
            "type": "string",
            "description": "Unique product SKU within the merchant channel."
          },
          "title": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Product title shown in QrX catalog and ordering flows."
          },
          "unit": {
            "maxLength": 64,
            "minLength": 0,
            "type": "string",
            "description": "Optional unit label, for example piece, box, or kg.",
            "nullable": true
          },
          "currency": {
            "maxLength": 3,
            "minLength": 3,
            "type": "string",
            "description": "Three-letter ISO 4217 currency code for product pricing.",
            "nullable": true
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "description": "Base product price including VAT unless your integration explicitly stores prices differently.",
            "format": "double"
          },
          "vatPercent": {
            "maximum": 100,
            "minimum": 0,
            "type": "number",
            "description": "VAT percentage applied to the product price.",
            "format": "double",
            "nullable": true
          },
          "availableQuantity": {
            "minimum": 0,
            "type": "integer",
            "description": "Available stock quantity for catalog and ordering flows.",
            "format": "int64"
          },
          "description": {
            "maxLength": 4000,
            "minLength": 0,
            "type": "string",
            "description": "Product description shown in catalog and ordering flows.",
            "nullable": true
          },
          "imageUrls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Public image URLs for the product gallery.",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional tags for product filtering, grouping, or synchronization.",
            "nullable": true
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicProductVariantUpsertRequest"
            },
            "description": "Optional product variants such as sizes, colors, or alternate SKUs.",
            "nullable": true
          },
          "optionGroups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicProductOptionGroupUpsertRequest"
            },
            "description": "Optional option groups for configurable product choices.",
            "nullable": true
          },
          "rowVersion": {
            "type": "string",
            "description": "Optional row version for optimistic concurrency when updating an existing product.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicProductVariantResponse": {
        "required": [
          "name",
          "sku"
        ],
        "type": "object",
        "properties": {
          "sku": {
            "maxLength": 128,
            "minLength": 1,
            "type": "string"
          },
          "name": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string"
          },
          "description": {
            "maxLength": 4000,
            "minLength": 0,
            "type": "string",
            "nullable": true
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "format": "double"
          },
          "imageUrl": {
            "type": "string",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          },
          "variantId": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "PublicProductVariantUpsertRequest": {
        "required": [
          "name",
          "sku"
        ],
        "type": "object",
        "properties": {
          "sku": {
            "maxLength": 128,
            "minLength": 1,
            "type": "string",
            "description": "Unique SKU for this variant within the product."
          },
          "name": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "description": "Variant name shown to customers and merchants."
          },
          "description": {
            "maxLength": 4000,
            "minLength": 0,
            "type": "string",
            "description": "Optional variant description.",
            "nullable": true
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "description": "Variant price including VAT unless your integration explicitly stores prices differently.",
            "format": "double"
          },
          "imageUrl": {
            "type": "string",
            "description": "Public image URL for this variant.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Display order for this variant.",
            "format": "int32"
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether this variant can be selected in catalog and ordering flows."
          }
        },
        "additionalProperties": false
      },
      "PublicReceiptFactRequest": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "nullable": true
          },
          "factType": {
            "type": "string",
            "nullable": true
          },
          "returnRequestItemId": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "receivedQuantity": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "discrepancyCode": {
            "type": "string",
            "nullable": true
          },
          "condition": {
            "type": "string",
            "nullable": true
          },
          "disposition": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "externalFacilityRef": {
            "type": "string",
            "nullable": true
          },
          "externalOperatorRef": {
            "type": "string",
            "nullable": true
          },
          "deviceRef": {
            "type": "string",
            "nullable": true
          },
          "clientMutationId": {
            "type": "string",
            "nullable": true
          },
          "evidenceRefsJson": {
            "type": "string",
            "nullable": true
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReceiptFactSupersedeRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "nullable": true
          },
          "replacement": {
            "$ref": "#/components/schemas/PublicReceiptFactRequest"
          }
        },
        "additionalProperties": false
      },
      "PublicReturnDecisionRequest": {
        "type": "object",
        "properties": {
          "note": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "rmaNumber": {
            "type": "string",
            "nullable": true
          },
          "canonicalState": {
            "type": "string",
            "nullable": true
          },
          "resolutionOutcome": {
            "type": "string",
            "nullable": true
          },
          "aggregateVersion": {
            "type": "integer",
            "format": "int64"
          },
          "merchantChannelId": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "isTestMode": {
            "type": "boolean"
          },
          "requestedAt": {
            "type": "string",
            "format": "date-time"
          },
          "modified": {
            "type": "string",
            "format": "date-time"
          },
          "allowedActions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnItem"
            },
            "nullable": true
          },
          "receiptFacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnReceiptFact"
            },
            "nullable": true
          },
          "shipments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnShipment"
            },
            "nullable": true
          },
          "evidence": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnEvidence"
            },
            "nullable": true
          },
          "compatibilityWarning": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnEvent": {
        "type": "object",
        "properties": {
          "sequence": {
            "type": "integer",
            "format": "int64"
          },
          "topic": {
            "type": "string",
            "nullable": true
          },
          "returnRequestId": {
            "type": "integer",
            "format": "int64"
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          },
          "dataJson": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnEvidence": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "fileName": {
            "type": "string",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "nullable": true
          },
          "sizeBytes": {
            "type": "integer",
            "format": "int64"
          },
          "state": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnInformationRequest": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "sku": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "quantity": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "PublicReturnMessageRequest": {
        "type": "object",
        "properties": {
          "body": {
            "type": "string",
            "nullable": true
          },
          "visibility": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnPageOfPublicReturnEvent": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnEvent"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnPageOfPublicReturnSummary": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicReturnSummary"
            },
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnReceiptFact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "returnRequestItemId": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "source": {
            "type": "string",
            "nullable": true
          },
          "factType": {
            "type": "string",
            "nullable": true
          },
          "receivedQuantity": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "discrepancyCode": {
            "type": "string",
            "nullable": true
          },
          "condition": {
            "type": "string",
            "nullable": true
          },
          "disposition": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "externalFacilityRef": {
            "type": "string",
            "nullable": true
          },
          "externalOperatorRef": {
            "type": "string",
            "nullable": true
          },
          "deviceRef": {
            "type": "string",
            "nullable": true
          },
          "clientMutationId": {
            "type": "string",
            "nullable": true
          },
          "evidenceRefsJson": {
            "type": "string",
            "nullable": true
          },
          "aggregateVersion": {
            "type": "integer",
            "format": "int64"
          },
          "supersededById": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "supersedeReason": {
            "type": "string",
            "nullable": true
          },
          "actorType": {
            "type": "string",
            "nullable": true
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "PublicReturnResolutionAckRequest": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string",
            "nullable": true
          },
          "note": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnResolutionIntentRequest": {
        "type": "object",
        "properties": {
          "outcome": {
            "type": "string",
            "nullable": true
          },
          "note": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicReturnShipment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "carrierId": {
            "type": "integer",
            "format": "int32"
          },
          "trackingNumber": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "voided": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "PublicReturnSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "rmaNumber": {
            "type": "string",
            "nullable": true
          },
          "canonicalState": {
            "type": "string",
            "nullable": true
          },
          "resolutionOutcome": {
            "type": "string",
            "nullable": true
          },
          "aggregateVersion": {
            "type": "integer",
            "format": "int64"
          },
          "merchantChannelId": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "isTestMode": {
            "type": "boolean"
          },
          "requestedAt": {
            "type": "string",
            "format": "date-time"
          },
          "modified": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "PublicShipmentAccessorials": {
        "type": "object",
        "properties": {
          "signatureRequired": {
            "type": "boolean",
            "description": "Require a signature on delivery. Forced on for QrX Payment-on-Delivery on QrX's own UPS contract.",
            "nullable": true
          },
          "adultSignatureRequired": {
            "type": "boolean",
            "description": "Require an adult signature on delivery. Takes precedence over signatureRequired.",
            "nullable": true
          },
          "directDeliveryOnly": {
            "type": "boolean",
            "description": "Lock the shipment to Direct Delivery Only, preventing Access Point rerouting and the consignee pickup-point offer. Forced on for QrX Payment-on-Delivery on QrX's own UPS contract.",
            "nullable": true
          },
          "saturdayDelivery": {
            "type": "boolean",
            "description": "Request Saturday delivery where the carrier supports it.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicTransactionDetailsResponse": {
        "type": "object",
        "properties": {
          "isTestMode": {
            "type": "boolean"
          },
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "paidAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "transactionPayoutProcessedDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "merchantChannelId": {
            "type": "integer",
            "format": "int32"
          },
          "paymentProviderId": {
            "type": "integer",
            "format": "int32"
          },
          "carrierId": {
            "type": "integer",
            "format": "int32"
          },
          "orderId": {
            "type": "string",
            "nullable": true
          },
          "shopOrderId": {
            "type": "string",
            "nullable": true
          },
          "orderCountry": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "locale": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number",
            "format": "double"
          },
          "xpointsUsed": {
            "type": "number",
            "format": "double"
          },
          "paymentMethod": {
            "type": "string",
            "nullable": true
          },
          "isRefunded": {
            "type": "boolean"
          },
          "consumerName": {
            "type": "string",
            "nullable": true
          },
          "consumerAccount": {
            "type": "string",
            "nullable": true
          },
          "consumerBic": {
            "type": "string",
            "nullable": true
          },
          "consumerCountry": {
            "type": "string",
            "nullable": true
          },
          "consumerEmail": {
            "type": "string",
            "nullable": true
          },
          "transactionVerificationNumber": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicTransactionResponse": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "qrCodeValue": {
            "type": "string",
            "nullable": true
          },
          "qrCodeImage": {
            "type": "string",
            "nullable": true
          },
          "carrierName": {
            "type": "string",
            "nullable": true
          },
          "carrierShippingMethod": {
            "type": "string",
            "nullable": true
          },
          "shippingLabels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CarrierLabel"
            },
            "nullable": true
          },
          "shippingDocuments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CarrierDocument"
            },
            "nullable": true
          },
          "carrierLabelType": {
            "$ref": "#/components/schemas/CarrierLabelType"
          },
          "pinCode": {
            "type": "string",
            "nullable": true
          },
          "shippingCost": {
            "type": "number",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "PublicTransactionStatusResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "nullable": true
          },
          "transactionPayoutProcessedDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "transactionVerificationNumber": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicWebhookDeliveryResponse": {
        "type": "object",
        "properties": {
          "deliveryId": {
            "type": "integer",
            "format": "int64"
          },
          "eventType": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "attemptNumber": {
            "type": "integer",
            "format": "int32"
          },
          "success": {
            "type": "boolean"
          },
          "httpStatusCode": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "orderId": {
            "type": "string",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "elapsedMs": {
            "type": "integer",
            "format": "int64"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "targetUrl": {
            "type": "string",
            "nullable": true
          },
          "requestBody": {
            "type": "string",
            "nullable": true
          },
          "responseBody": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicWebhookDeliverySummaryResponse": {
        "type": "object",
        "properties": {
          "deliveryId": {
            "type": "integer",
            "format": "int64"
          },
          "eventType": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "attemptNumber": {
            "type": "integer",
            "format": "int32"
          },
          "success": {
            "type": "boolean"
          },
          "httpStatusCode": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "orderId": {
            "type": "string",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "elapsedMs": {
            "type": "integer",
            "format": "int64"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "PublicWebhookEventTypesResponse": {
        "type": "object",
        "properties": {
          "eventTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "groups": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "nullable": true
          },
          "apiVersions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "currentApiVersion": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicWebhookResponse": {
        "type": "object",
        "properties": {
          "webhookId": {
            "type": "integer",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "targetUrl": {
            "type": "string",
            "nullable": true
          },
          "eventTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "apiVersion": {
            "type": "string",
            "nullable": true
          },
          "isActive": {
            "type": "boolean"
          },
          "healthStatus": {
            "type": "string",
            "nullable": true
          },
          "consecutiveFailures": {
            "type": "integer",
            "format": "int32"
          },
          "lastSuccessAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastFailureAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "failureSince": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "integer",
            "format": "int32"
          },
          "signingSecret": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicWebhookSummaryResponse": {
        "type": "object",
        "properties": {
          "webhookId": {
            "type": "integer",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "targetUrl": {
            "type": "string",
            "nullable": true
          },
          "eventTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "apiVersion": {
            "type": "string",
            "nullable": true
          },
          "isActive": {
            "type": "boolean"
          },
          "healthStatus": {
            "type": "string",
            "nullable": true
          },
          "consecutiveFailures": {
            "type": "integer",
            "format": "int32"
          },
          "lastSuccessAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastFailureAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "failureSince": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "PublicWebhookTestRequest": {
        "required": [
          "eventType"
        ],
        "type": "object",
        "properties": {
          "eventType": {
            "minLength": 1,
            "type": "string",
            "description": "Webhook event type to use for the test delivery."
          }
        },
        "additionalProperties": false
      },
      "PublicWebhookTestResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "httpStatusCode": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "responseBody": {
            "type": "string",
            "nullable": true
          },
          "elapsedMs": {
            "type": "integer",
            "format": "int64"
          },
          "error": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PublicWebhookUpsertRequest": {
        "required": [
          "eventTypes",
          "name",
          "targetUrl"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 120,
            "minLength": 1,
            "type": "string",
            "description": "Internal name for this webhook endpoint."
          },
          "targetUrl": {
            "minLength": 1,
            "type": "string",
            "description": "Absolute HTTPS URL that receives webhook POST requests from QrX.",
            "format": "uri"
          },
          "eventTypes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Event types this webhook should receive. Use the event types endpoint to retrieve supported values."
          },
          "apiVersion": {
            "type": "string",
            "description": "Optional webhook API version. Leave empty to use the current default version.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether QrX should actively deliver events to this webhook endpoint."
          },
          "xmin": {
            "type": "integer",
            "description": "Optional optimistic concurrency token returned by existing webhook records.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "TransactionType": {
        "type": "string",
        "oneOf": [
          {
            "title": "Payment",
            "enum": [
              "Payment"
            ],
            "type": "string"
          },
          {
            "title": "NoPayment",
            "enum": [
              "NoPayment"
            ],
            "type": "string"
          },
          {
            "title": "OtpOnly",
            "enum": [
              "OtpOnly"
            ],
            "type": "string"
          },
          {
            "title": "DataOnly",
            "enum": [
              "DataOnly"
            ],
            "type": "string"
          }
        ],
        "x-enumNames": [
          "Payment",
          "NoPayment",
          "OtpOnly",
          "DataOnly"
        ],
        "x-enumDescriptions": [
          "Payment",
          "NoPayment",
          "OtpOnly",
          "DataOnly"
        ],
        "x-ms-enum": {
          "name": "TransactionType",
          "modelAsString": true,
          "values": [
            {
              "name": "Payment",
              "value": "Payment",
              "description": "Payment"
            },
            {
              "name": "NoPayment",
              "value": "NoPayment",
              "description": "NoPayment"
            },
            {
              "name": "OtpOnly",
              "value": "OtpOnly",
              "description": "OtpOnly"
            },
            {
              "name": "DataOnly",
              "value": "DataOnly",
              "description": "DataOnly"
            }
          ]
        }
      }
    },
    "securitySchemes": {
      "MerchantApiKey": {
        "type": "apiKey",
        "description": "Merchant channel API key. Use this only to call /api/v1/auth/token.",
        "name": "QrX-MerchantChannel-API-Key",
        "in": "header"
      },
      "Bearer": {
        "type": "http",
        "description": "Short-lived QrX access token returned by /api/v1/auth/token.",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  },
  "tags": [
    {
      "name": "Auth"
    },
    {
      "name": "Products"
    },
    {
      "name": "Reference"
    },
    {
      "name": "Returns"
    },
    {
      "name": "Transactions"
    },
    {
      "name": "Webhooks"
    }
  ]
}