{
  "openapi": "3.1.0",
  "info": {
    "title": "TesserApp Integration API",
    "version": "1.0.0",
    "description": "Issue cards from your own systems, read what happened at the till, and get told about it as it happens. No transaction can be written over this API — see the reference for why. Additive changes only inside /v1."
  },
  "servers": [
    {
      "url": "https://api.tesserapp.eu/api/public/v1"
    }
  ],
  "security": [
    {
      "ApiKeyBearer": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyBearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "tsk_live_<43 chars base64url>",
        "description": "A shop-scoped API key created in the dashboard and shown exactly once. An MCP `tmk_` key presented here returns a 401 that names the mistake."
      }
    },
    "schemas": {
      "ActivityHeatmap": {
        "type": "object",
        "properties": {
          "from": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "days": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string"
                },
                "count": {
                  "type": "number"
                }
              },
              "required": [
                "date",
                "count"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "from",
          "to",
          "days"
        ],
        "additionalProperties": false
      },
      "AnalyticsSummary": {
        "type": "object",
        "properties": {
          "active_locations": {
            "type": "number"
          },
          "active_programs": {
            "type": "number"
          },
          "activity_30d": {
            "type": "number"
          },
          "new_cards_30d": {
            "type": "number"
          }
        },
        "required": [
          "active_locations",
          "active_programs",
          "activity_30d",
          "new_cards_30d"
        ],
        "additionalProperties": false
      },
      "Card": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "program_id": {
            "type": "string",
            "minLength": 1
          },
          "program_name": {
            "type": "string"
          },
          "program_type": {
            "type": "string"
          },
          "external_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "holder_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "holder_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "locked",
              "invited",
              "archived",
              "expired"
            ]
          },
          "stamps_count": {
            "type": "integer"
          },
          "current_value": {
            "type": [
              "integer",
              "null"
            ]
          },
          "expires_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "installed_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          }
        },
        "required": [
          "id",
          "program_id",
          "program_name",
          "program_type",
          "external_ref",
          "holder_name",
          "holder_email",
          "status",
          "stamps_count",
          "current_value",
          "expires_at",
          "installed_at",
          "created_at"
        ],
        "additionalProperties": false
      },
      "CardDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "program_id": {
            "type": "string",
            "minLength": 1
          },
          "program_name": {
            "type": "string"
          },
          "program_type": {
            "type": "string"
          },
          "external_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "holder_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "holder_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "locked",
              "invited",
              "archived",
              "expired"
            ]
          },
          "stamps_count": {
            "type": "integer"
          },
          "current_value": {
            "type": [
              "integer",
              "null"
            ]
          },
          "expires_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "installed_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          },
          "all_locations": {
            "type": "boolean"
          },
          "locations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "minLength": 1
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "id",
          "program_id",
          "program_name",
          "program_type",
          "external_ref",
          "holder_name",
          "holder_email",
          "status",
          "stamps_count",
          "current_value",
          "expires_at",
          "installed_at",
          "created_at",
          "all_locations",
          "locations"
        ],
        "additionalProperties": false
      },
      "CardPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Card"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "data",
          "next_cursor",
          "limit"
        ],
        "additionalProperties": false
      },
      "CardStats": {
        "type": "object",
        "properties": {
          "card_type": {
            "type": "string"
          },
          "kpis": {
            "type": "object",
            "additionalProperties": {
              "oneOf": [
                {
                  "type": "number"
                },
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ]
            }
          },
          "activity_by_day": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string"
                },
                "value": {
                  "type": "number"
                }
              },
              "required": [
                "date",
                "value"
              ],
              "additionalProperties": false
            }
          },
          "timezone": {
            "type": "string"
          }
        },
        "required": [
          "card_type",
          "kpis",
          "activity_by_day",
          "timezone"
        ],
        "additionalProperties": false
      },
      "CardTypeDistribution": {
        "type": "object",
        "properties": {
          "distribution": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string"
                },
                "count": {
                  "type": "number"
                },
                "label_key": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                }
              },
              "required": [
                "type",
                "count",
                "label_key",
                "color"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "distribution"
        ],
        "additionalProperties": false
      },
      "CreatePrizeRequest": {
        "type": "object",
        "properties": {
          "threshold": {
            "type": "integer",
            "minimum": 0
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "name_localizations": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "enum": [
                "it",
                "en",
                "es",
                "fr",
                "de",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            }
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "description_localizations": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "enum": [
                "it",
                "en",
                "es",
                "fr",
                "de",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            }
          },
          "ordinal": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "threshold",
          "name",
          "ordinal"
        ],
        "additionalProperties": false
      },
      "CreateProgramRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "name_localizations": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "enum": [
                "it",
                "en",
                "es",
                "fr",
                "de",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            }
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "description_localizations": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "enum": [
                "it",
                "en",
                "es",
                "fr",
                "de",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            }
          },
          "category": {
            "type": "string"
          },
          "brand_color_hex": {
            "type": "string"
          },
          "logo_url": {
            "type": "string"
          },
          "total_stamps": {
            "type": "integer",
            "minimum": 2,
            "maximum": 15
          },
          "repeat_after_reset": {
            "type": "boolean"
          },
          "stamps_expire_after_days": {
            "type": "integer",
            "minimum": 0
          },
          "prizes_expire_after_days": {
            "type": "integer",
            "minimum": 0
          },
          "card_expire_after_days": {
            "type": "integer",
            "minimum": 0
          },
          "spend_based_stamps_enabled": {
            "type": "boolean"
          },
          "euro_per_stamp_cents": {
            "type": "integer",
            "minimum": 0
          },
          "visible_in_catalog": {
            "type": "boolean"
          },
          "location_scope": {
            "type": "string",
            "enum": [
              "all_locations",
              "specific_locations"
            ]
          },
          "scoped_location_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "prizes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "threshold": {
                  "type": "integer",
                  "minimum": 0
                },
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "name_localizations": {
                  "type": "object",
                  "propertyNames": {
                    "type": "string",
                    "enum": [
                      "it",
                      "en",
                      "es",
                      "fr",
                      "de",
                      "pt"
                    ]
                  },
                  "additionalProperties": {
                    "type": "string",
                    "maxLength": 500
                  }
                },
                "description": {
                  "type": "string",
                  "maxLength": 2000
                },
                "ordinal": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "required": [
                "threshold",
                "name",
                "ordinal"
              ],
              "additionalProperties": false
            }
          },
          "icon_key": {
            "type": "string",
            "minLength": 1
          },
          "award_description": {
            "type": "string",
            "maxLength": 60
          },
          "bg_color_hex": {
            "type": "string"
          },
          "text_color_hex": {
            "type": "string"
          },
          "border_enabled": {
            "type": "boolean"
          },
          "border_color_hex": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "standard",
              "private",
              "discount",
              "access",
              "prepaid",
              "points"
            ]
          },
          "discount_percent": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "access_image_url": {
            "type": "string"
          },
          "initial_balance_cents": {
            "type": "integer",
            "minimum": 0
          },
          "default_expire_after_days": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "name",
          "category",
          "brand_color_hex",
          "logo_url",
          "repeat_after_reset",
          "spend_based_stamps_enabled",
          "visible_in_catalog",
          "location_scope",
          "border_enabled",
          "type"
        ],
        "additionalProperties": false
      },
      "CreateWebhookRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "maxLength": 2048
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bearer_token": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 4096
          },
          "active": {
            "type": "boolean"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500
          },
          "program_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "location_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "include_shop_wide_events": {
            "type": "boolean"
          },
          "http_method": {
            "type": "string",
            "enum": [
              "POST",
              "PUT",
              "PATCH"
            ]
          },
          "custom_headers": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "payload_version": {
            "type": "string",
            "enum": [
              "v1",
              "v2"
            ]
          }
        },
        "required": [
          "url",
          "events",
          "bearer_token",
          "description",
          "program_ids",
          "location_ids",
          "custom_headers"
        ],
        "additionalProperties": false
      },
      "EnrollmentQr": {
        "type": "object",
        "properties": {
          "deep_link": {
            "type": "string"
          },
          "qr_svg": {
            "type": "string"
          }
        },
        "required": [
          "deep_link",
          "qr_svg"
        ],
        "additionalProperties": false
      },
      "ErrorEnvelope": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string"
              },
              "details": {}
            },
            "required": [
              "code",
              "message"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "EventCatalogue": {
        "type": "object",
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "event": {
                  "type": "string"
                },
                "shop_wide": {
                  "type": "boolean"
                },
                "card_bearing": {
                  "type": "boolean"
                },
                "transaction_specific": {
                  "type": "boolean"
                },
                "firehose": {
                  "type": "boolean"
                }
              },
              "required": [
                "event",
                "shop_wide",
                "card_bearing",
                "transaction_specific",
                "firehose"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "events"
        ],
        "additionalProperties": false
      },
      "GrowthTimeline": {
        "type": "object",
        "properties": {
          "buckets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "new_cards": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "activity": {
            "type": "array",
            "items": {
              "type": "number"
            }
          }
        },
        "required": [
          "buckets",
          "new_cards",
          "activity"
        ],
        "additionalProperties": false
      },
      "IssueCardRequest": {
        "type": "object",
        "properties": {
          "holder_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "holder_email": {
            "type": "string",
            "format": "email"
          },
          "external_ref": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "send_email": {
            "type": "boolean"
          }
        },
        "required": [
          "holder_name",
          "holder_email",
          "send_email"
        ],
        "additionalProperties": false
      },
      "IssuedCard": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "program_id": {
            "type": "string",
            "minLength": 1
          },
          "external_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "holder_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "holder_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "expires_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "install_url": {
            "type": "string"
          },
          "install_url_expires_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          },
          "install_qr_svg": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "program_id",
          "external_ref",
          "holder_name",
          "holder_email",
          "expires_at",
          "install_url",
          "install_url_expires_at",
          "install_qr_svg"
        ],
        "additionalProperties": false
      },
      "Location": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string"
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "country_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "lat": {
            "type": [
              "number",
              "null"
            ]
          },
          "lon": {
            "type": [
              "number",
              "null"
            ]
          },
          "require_staff_pin": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          },
          "disabled_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          },
          "updated_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "address",
          "city",
          "postal_code",
          "country_code",
          "lat",
          "lon",
          "require_staff_pin",
          "active",
          "disabled_at",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false
      },
      "LocationPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Location"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "data",
          "next_cursor",
          "limit"
        ],
        "additionalProperties": false
      },
      "Me": {
        "type": "object",
        "properties": {
          "shop": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1
              },
              "api_addon": {
                "type": "boolean"
              },
              "included_locations": {
                "type": "integer"
              },
              "billable_locations": {
                "type": "integer"
              },
              "max_locations": {
                "type": "null"
              },
              "max_cards": {
                "type": "null"
              }
            },
            "required": [
              "id",
              "api_addon",
              "included_locations",
              "billable_locations",
              "max_locations",
              "max_cards"
            ],
            "additionalProperties": false
          },
          "entitlements": {
            "type": "object",
            "properties": {
              "api_access": {
                "type": "boolean"
              },
              "webhooks_advanced": {
                "type": "boolean"
              },
              "mcp_access": {
                "type": "boolean"
              },
              "source": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "grant_expires_at": {
                "oneOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "api_access",
              "webhooks_advanced",
              "mcp_access",
              "source",
              "grant_expires_at"
            ],
            "additionalProperties": false
          },
          "api_key": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "location_ids": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "id",
              "scopes",
              "location_ids"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "shop",
          "entitlements",
          "api_key"
        ],
        "additionalProperties": false
      },
      "Prize": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "program_id": {
            "type": "string",
            "minLength": 1
          },
          "threshold": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "ordinal": {
            "type": "integer"
          },
          "created_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          },
          "updated_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          }
        },
        "required": [
          "id",
          "program_id",
          "threshold",
          "name",
          "description",
          "ordinal",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false
      },
      "PrizeList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Prize"
            }
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false
      },
      "Program": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          },
          "published_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "suspended_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "total_stamps": {
            "type": [
              "integer",
              "null"
            ]
          },
          "repeat_after_reset": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "discount_percent": {
            "type": [
              "number",
              "null"
            ]
          },
          "initial_balance_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "default_expire_after_days": {
            "type": [
              "integer",
              "null"
            ]
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "access_image_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "brand_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "bg_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "text_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "icon_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "location_scope": {
            "type": [
              "string",
              "null"
            ]
          },
          "scoped_location_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          },
          "updated_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "category",
          "type",
          "active",
          "published_at",
          "suspended_at",
          "total_stamps",
          "repeat_after_reset",
          "discount_percent",
          "initial_balance_cents",
          "default_expire_after_days",
          "logo_url",
          "access_image_url",
          "brand_color_hex",
          "bg_color_hex",
          "text_color_hex",
          "icon_key",
          "location_scope",
          "scoped_location_ids",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false
      },
      "ProgramDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          },
          "published_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "suspended_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "total_stamps": {
            "type": [
              "integer",
              "null"
            ]
          },
          "repeat_after_reset": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "discount_percent": {
            "type": [
              "number",
              "null"
            ]
          },
          "initial_balance_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "default_expire_after_days": {
            "type": [
              "integer",
              "null"
            ]
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "access_image_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "brand_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "bg_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "text_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "icon_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "location_scope": {
            "type": [
              "string",
              "null"
            ]
          },
          "scoped_location_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          },
          "updated_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          },
          "prizes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Prize"
            }
          },
          "has_installed_cards": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "category",
          "type",
          "active",
          "published_at",
          "suspended_at",
          "total_stamps",
          "repeat_after_reset",
          "discount_percent",
          "initial_balance_cents",
          "default_expire_after_days",
          "logo_url",
          "access_image_url",
          "brand_color_hex",
          "bg_color_hex",
          "text_color_hex",
          "icon_key",
          "location_scope",
          "scoped_location_ids",
          "created_at",
          "updated_at",
          "prizes",
          "has_installed_cards"
        ],
        "additionalProperties": false
      },
      "ProgramPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Program"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "data",
          "next_cursor",
          "limit"
        ],
        "additionalProperties": false
      },
      "ProgramStats": {
        "type": "object",
        "properties": {
          "active_cards": {
            "type": [
              "integer",
              "null"
            ]
          },
          "total_stamps_awarded": {
            "type": [
              "integer",
              "null"
            ]
          },
          "prizes_redeemed": {
            "type": [
              "integer",
              "null"
            ]
          },
          "completion_rate": {
            "type": [
              "number",
              "null"
            ]
          },
          "cards_by_day": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              },
              "required": [
                "date",
                "count"
              ],
              "additionalProperties": false
            }
          },
          "stamps_by_day": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              },
              "required": [
                "date",
                "count"
              ],
              "additionalProperties": false
            }
          },
          "cards_by_location": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "location_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "minLength": 1
                },
                "location_name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "count": {
                  "type": "integer"
                }
              },
              "required": [
                "location_id",
                "location_name",
                "count"
              ],
              "additionalProperties": false
            }
          },
          "stamps_by_location": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "location_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "minLength": 1
                },
                "location_name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "count": {
                  "type": "integer"
                }
              },
              "required": [
                "location_id",
                "location_name",
                "count"
              ],
              "additionalProperties": false
            }
          },
          "stamps_by_hour_dow": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "day_of_week": {
                  "type": "integer"
                },
                "hour": {
                  "type": "integer"
                },
                "count": {
                  "type": "integer"
                }
              },
              "required": [
                "day_of_week",
                "hour",
                "count"
              ],
              "additionalProperties": false
            }
          },
          "platform_split": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "apple": {
                "type": "integer"
              },
              "google": {
                "type": "integer"
              }
            },
            "required": [
              "apple",
              "google"
            ],
            "additionalProperties": false
          },
          "avg_days_between_stamps": {
            "type": [
              "number",
              "null"
            ]
          },
          "timezone": {
            "type": "string"
          }
        },
        "required": [
          "active_cards",
          "total_stamps_awarded",
          "prizes_redeemed",
          "completion_rate",
          "cards_by_day",
          "stamps_by_day",
          "cards_by_location",
          "stamps_by_location",
          "stamps_by_hour_dow",
          "platform_split",
          "avg_days_between_stamps",
          "timezone"
        ],
        "additionalProperties": false
      },
      "ProgramTimeline": {
        "type": "object",
        "properties": {
          "group": {
            "type": "string",
            "enum": [
              "day",
              "week",
              "month"
            ]
          },
          "from": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "buckets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "cards": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "stamps": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "integer"
            }
          }
        },
        "required": [
          "group",
          "from",
          "to",
          "buckets",
          "cards",
          "stamps"
        ],
        "additionalProperties": false
      },
      "ReissuedCard": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "install_url": {
            "type": "string"
          },
          "install_url_expires_at": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "install_qr_svg": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "install_url",
          "install_url_expires_at",
          "install_qr_svg"
        ],
        "additionalProperties": false
      },
      "StampsTimeline": {
        "type": "object",
        "properties": {
          "group": {
            "type": "string",
            "enum": [
              "day",
              "week",
              "month"
            ]
          },
          "from": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "buckets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "series": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "program_id": {
                  "type": "string"
                },
                "program_name": {
                  "type": "string"
                },
                "brand_color_hex": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "data": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "required": [
                "program_id",
                "program_name",
                "brand_color_hex",
                "data"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "group",
          "from",
          "to",
          "buckets",
          "series"
        ],
        "additionalProperties": false
      },
      "TopPrograms": {
        "type": "object",
        "properties": {
          "programs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "program_id": {
                  "type": "string"
                },
                "program_name": {
                  "type": "string"
                },
                "brand_color_hex": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "activity_count": {
                  "type": "number"
                }
              },
              "required": [
                "program_id",
                "program_name",
                "brand_color_hex",
                "activity_count"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "programs"
        ],
        "additionalProperties": false
      },
      "Transaction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "card_id": {
            "type": "string",
            "minLength": 1
          },
          "program_id": {
            "type": "string",
            "minLength": 1
          },
          "type": {
            "type": "string"
          },
          "location_id": {
            "type": "string",
            "minLength": 1
          },
          "location_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "stamps_delta": {
            "type": "integer"
          },
          "value_delta": {
            "type": [
              "integer",
              "null"
            ]
          },
          "prize_id": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1
          },
          "reversed_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "string"
              }
            ]
          }
        },
        "required": [
          "id",
          "card_id",
          "program_id",
          "type",
          "location_id",
          "location_name",
          "stamps_delta",
          "value_delta",
          "prize_id",
          "reversed_at",
          "created_at"
        ],
        "additionalProperties": false
      },
      "TransactionPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Transaction"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "data",
          "next_cursor",
          "limit"
        ],
        "additionalProperties": false
      },
      "UpdateCardRequest": {
        "type": "object",
        "properties": {
          "holder_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "holder_email": {
            "type": "string",
            "format": "email"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "external_ref": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 256
          }
        },
        "additionalProperties": false
      },
      "UpdateLocationRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "address": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "city": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "postal_code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20
          },
          "country_code": {
            "type": "string"
          },
          "lat": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -90,
            "maximum": 90
          },
          "lon": {
            "type": [
              "number",
              "null"
            ],
            "minimum": -180,
            "maximum": 180
          },
          "require_staff_pin": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "UpdatePrizeRequest": {
        "type": "object",
        "properties": {
          "threshold": {
            "type": "integer",
            "minimum": 0
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "name_localizations": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "enum": [
                "it",
                "en",
                "es",
                "fr",
                "de",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            }
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          },
          "description_localizations": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "enum": [
                "it",
                "en",
                "es",
                "fr",
                "de",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            }
          },
          "ordinal": {
            "type": "integer",
            "minimum": 0
          }
        },
        "additionalProperties": false
      },
      "UpdateProgramRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "name_localizations": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "enum": [
                "it",
                "en",
                "es",
                "fr",
                "de",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            }
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          },
          "description_localizations": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "enum": [
                "it",
                "en",
                "es",
                "fr",
                "de",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            }
          },
          "category": {
            "type": "string"
          },
          "brand_color_hex": {
            "type": "string"
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "total_stamps": {
            "type": "integer",
            "minimum": 2,
            "maximum": 15
          },
          "repeat_after_reset": {
            "type": "boolean"
          },
          "stamps_expire_after_days": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "prizes_expire_after_days": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "card_expire_after_days": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "spend_based_stamps_enabled": {
            "type": "boolean"
          },
          "euro_per_stamp_cents": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "visible_in_catalog": {
            "type": "boolean"
          },
          "location_scope": {
            "type": "string",
            "enum": [
              "all_locations",
              "specific_locations"
            ]
          },
          "scoped_location_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "prizes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "threshold": {
                  "type": "integer",
                  "minimum": 0
                },
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "name_localizations": {
                  "type": "object",
                  "propertyNames": {
                    "type": "string",
                    "enum": [
                      "it",
                      "en",
                      "es",
                      "fr",
                      "de",
                      "pt"
                    ]
                  },
                  "additionalProperties": {
                    "type": "string",
                    "maxLength": 500
                  }
                },
                "description": {
                  "type": "string",
                  "maxLength": 2000
                },
                "ordinal": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "required": [
                "threshold",
                "name",
                "ordinal"
              ],
              "additionalProperties": false
            }
          },
          "icon_key": {
            "type": "string",
            "minLength": 1
          },
          "award_description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 60
          },
          "bg_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "text_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "border_enabled": {
            "type": "boolean"
          },
          "border_color_hex": {
            "type": [
              "string",
              "null"
            ]
          },
          "discount_percent": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "access_image_url": {
            "type": "string"
          },
          "initial_balance_cents": {
            "type": "integer",
            "minimum": 0
          },
          "default_expire_after_days": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          }
        },
        "required": [
          "logo_url"
        ],
        "additionalProperties": false
      },
      "UpdateWebhookRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "maxLength": 2048
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bearer_token": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 4096
          },
          "active": {
            "type": "boolean"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500
          },
          "rotate_secret": {
            "type": "boolean"
          },
          "program_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "location_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "include_shop_wide_events": {
            "type": "boolean"
          },
          "http_method": {
            "type": "string",
            "enum": [
              "POST",
              "PUT",
              "PATCH"
            ]
          },
          "custom_headers": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "payload_version": {
            "type": "string",
            "enum": [
              "v1",
              "v2"
            ]
          }
        },
        "additionalProperties": false
      },
      "WalletSplit": {
        "type": "object",
        "properties": {
          "apple": {
            "type": "number"
          },
          "google": {
            "type": "number"
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "apple",
          "google",
          "total"
        ],
        "additionalProperties": false
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "shop_id": {
            "type": "string",
            "minLength": 1
          },
          "program_id": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_bearer_token": {
            "type": "boolean"
          },
          "program_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "location_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "include_shop_wide_events": {
            "type": "boolean"
          },
          "http_method": {
            "type": "string",
            "enum": [
              "POST",
              "PUT",
              "PATCH"
            ]
          },
          "custom_headers": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "payload_version": {
            "type": "string",
            "enum": [
              "v1",
              "v2"
            ]
          },
          "consecutive_failures": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "shop_id",
          "program_id",
          "url",
          "events",
          "active",
          "description",
          "has_bearer_token",
          "program_ids",
          "location_ids",
          "include_shop_wide_events",
          "http_method",
          "custom_headers",
          "payload_version",
          "consecutive_failures",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "webhook_id": {
            "type": "string",
            "minLength": 1
          },
          "event": {
            "type": "string"
          },
          "event_id": {
            "type": "string"
          },
          "request_payload": {},
          "request_headers": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "response_status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "attempts": {
            "type": "integer"
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "duration_ms": {
            "type": [
              "integer",
              "null"
            ]
          },
          "card_instance_id": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "webhook_id",
          "event",
          "event_id",
          "request_payload",
          "request_headers",
          "response_status",
          "attempts",
          "last_error",
          "duration_ms",
          "card_instance_id",
          "delivered_at",
          "created_at"
        ],
        "additionalProperties": false
      },
      "WebhookDeliveryList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          }
        },
        "required": [
          "items"
        ],
        "additionalProperties": false
      },
      "WebhookList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          }
        },
        "required": [
          "items"
        ],
        "additionalProperties": false
      },
      "WebhookTestPing": {
        "type": "object",
        "properties": {
          "delivery_id": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "delivery_id"
        ],
        "additionalProperties": false
      },
      "WebhookUpdated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "shop_id": {
            "type": "string",
            "minLength": 1
          },
          "program_id": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_bearer_token": {
            "type": "boolean"
          },
          "program_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "location_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "include_shop_wide_events": {
            "type": "boolean"
          },
          "http_method": {
            "type": "string",
            "enum": [
              "POST",
              "PUT",
              "PATCH"
            ]
          },
          "custom_headers": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "payload_version": {
            "type": "string",
            "enum": [
              "v1",
              "v2"
            ]
          },
          "consecutive_failures": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "secret": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "shop_id",
          "program_id",
          "url",
          "events",
          "active",
          "description",
          "has_bearer_token",
          "program_ids",
          "location_ids",
          "include_shop_wide_events",
          "http_method",
          "custom_headers",
          "payload_version",
          "consecutive_failures",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false
      },
      "WebhookWithSecret": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "minLength": 1
          },
          "shop_id": {
            "type": "string",
            "minLength": 1
          },
          "program_id": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "active": {
            "type": "boolean"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_bearer_token": {
            "type": "boolean"
          },
          "program_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "location_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "include_shop_wide_events": {
            "type": "boolean"
          },
          "http_method": {
            "type": "string",
            "enum": [
              "POST",
              "PUT",
              "PATCH"
            ]
          },
          "custom_headers": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            }
          },
          "payload_version": {
            "type": "string",
            "enum": [
              "v1",
              "v2"
            ]
          },
          "consecutive_failures": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "secret": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "shop_id",
          "program_id",
          "url",
          "events",
          "active",
          "description",
          "has_bearer_token",
          "program_ids",
          "location_ids",
          "include_shop_wide_events",
          "http_method",
          "custom_headers",
          "payload_version",
          "consecutive_failures",
          "created_at",
          "updated_at",
          "secret"
        ],
        "additionalProperties": false
      }
    },
    "parameters": {
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Page size. Clamped to the maximum (100 by default, PUBLIC_API_MAX_PAGE_SIZE) rather than rejected.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "Opaque cursor from a previous response's `next_cursor`. Absent `next_cursor` (null) means the end.",
        "schema": {
          "type": "string"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Makes a retry safe: a repeat with the same key and body replays the stored response; the same key with a different body is a 409. Keys are remembered for 24h (IDEMPOTENCY_DEDUPE_WINDOW_HOURS). A request without the header is processed normally.",
        "schema": {
          "type": "string",
          "maxLength": 255
        }
      }
    }
  },
  "paths": {
    "/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Who am I, and what can this key do",
        "description": "Shop, plan, entitlements, location counts — and the CALLING KEY'S OWN scopes and location restriction. An integrator's first call, and the fastest way to resolve a 403.",
        "tags": [
          "me"
        ],
        "security": [
          {
            "ApiKeyBearer": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Who am I, and what can this key do",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                },
                "examples": {
                  "default": {
                    "value": {
                      "shop": {
                        "id": "shp_docsfixture0001",
                        "api_addon": true,
                        "included_locations": 0,
                        "billable_locations": 3,
                        "max_locations": null,
                        "max_cards": null
                      },
                      "entitlements": {
                        "api_access": true,
                        "webhooks_advanced": true,
                        "mcp_access": true,
                        "source": {
                          "api_access": "addon"
                        },
                        "grant_expires_at": null
                      },
                      "api_key": {
                        "id": "ak_docsfixture0001",
                        "scopes": [
                          "cards:write"
                        ],
                        "location_ids": [
                          "loc_docsfixture0001"
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "getEventCatalogue",
        "summary": "The webhook event catalogue",
        "description": "Every subscribable event with one payload example each, generated from the builders.",
        "tags": [
          "events"
        ],
        "security": [
          {
            "ApiKeyBearer": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "The webhook event catalogue",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventCatalogue"
                },
                "examples": {
                  "default": {
                    "value": {
                      "events": [
                        {
                          "event": "stamp.assigned",
                          "shop_wide": false,
                          "card_bearing": true,
                          "transaction_specific": true,
                          "firehose": false
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/locations": {
      "get": {
        "operationId": "listLocations",
        "summary": "List locations",
        "description": "Cursor-paginated. A key restricted to certain locations sees only those; `limit` above the maximum is clamped, not rejected, and the response states the effective limit.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "locations:read"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "List locations",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationPage"
                },
                "examples": {
                  "default": {
                    "value": {
                      "data": [
                        {
                          "id": "loc_docsfixture0001",
                          "name": "Via Roma 1",
                          "address": "Via Roma 1",
                          "city": "Milano",
                          "postal_code": "20121",
                          "country_code": "IT",
                          "lat": 45.4642,
                          "lon": 9.19,
                          "require_staff_pin": false,
                          "active": true,
                          "disabled_at": null,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "next_cursor": "eyJjIjoiMjAyNi0wOC0wNVQxMDoxNTowMC4wMDBaIiwiaSI6ImNpbl9kb2NzZml4dHVyZTAwMDEifQ",
                      "limit": 25
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/locations/{id}": {
      "get": {
        "operationId": "getLocation",
        "summary": "Get one location",
        "description": "Returns 404 — never 403 — for a location outside the key's restriction: a 403 would confirm that another site exists.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "locations:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "Get one location",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Location"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "loc_docsfixture0001",
                      "name": "Via Roma 1",
                      "address": "Via Roma 1",
                      "city": "Milano",
                      "postal_code": "20121",
                      "country_code": "IT",
                      "lat": 45.4642,
                      "lon": 9.19,
                      "require_staff_pin": false,
                      "active": true,
                      "disabled_at": null,
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateLocation",
        "summary": "Update a location",
        "description": "The shop's own record of a site: its name, its address and whether staff must enter a PIN there. A location cannot be CREATED over the API — the platform is pay-then-provision, so a new site is bought in the dashboard — and `active` is not a field here: enable and disable are explicit actions below, because \"disabled by the merchant\" and \"blocked for non-renewal\" are different states and one boolean cannot hold both.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "locations:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLocationRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "name": "Via Roma 1",
                    "address": "Via Roma 1",
                    "city": "Milano",
                    "postal_code": "20121",
                    "country_code": "IT",
                    "lat": 45.4642,
                    "lon": 9.19,
                    "require_staff_pin": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update a location",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Location"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "loc_docsfixture0001",
                      "name": "Via Roma 1",
                      "address": "Via Roma 1",
                      "city": "Milano",
                      "postal_code": "20121",
                      "country_code": "IT",
                      "lat": 45.4642,
                      "lon": 9.19,
                      "require_staff_pin": false,
                      "active": true,
                      "disabled_at": null,
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/locations/{id}/disable": {
      "post": {
        "operationId": "disableLocation",
        "summary": "Disable a location",
        "description": "The location's cards stop working immediately. Billing is deliberately NOT affected — renewal levers stay owner-initiated in the dashboard. Creating a location is not an API write: the platform is pay-then-provision.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "locations:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Disable a location",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Location"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "loc_docsfixture0001",
                      "name": "Via Roma 1",
                      "address": "Via Roma 1",
                      "city": "Milano",
                      "postal_code": "20121",
                      "country_code": "IT",
                      "lat": 45.4642,
                      "lon": 9.19,
                      "require_staff_pin": false,
                      "active": true,
                      "disabled_at": null,
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/locations/{id}/enable": {
      "post": {
        "operationId": "enableLocation",
        "summary": "Enable a location",
        "description": "The inverse of disable: the site starts accepting cards again immediately. Enabling a location that is already enabled is not an error — this is the endpoint to call when reconciling your own store list against ours, without first reading each one.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "locations:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Enable a location",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Location"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "loc_docsfixture0001",
                      "name": "Via Roma 1",
                      "address": "Via Roma 1",
                      "city": "Milano",
                      "postal_code": "20121",
                      "country_code": "IT",
                      "lat": 45.4642,
                      "lon": 9.19,
                      "require_staff_pin": false,
                      "active": true,
                      "disabled_at": null,
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs": {
      "get": {
        "operationId": "listPrograms",
        "summary": "List programs",
        "description": "Every card template the shop owns — published or not, of every type. Cursor-paginated, newest first, and filterable by `type`. Programs are SHOP-WIDE and carry no location, so a location-restricted key sees the same list an unrestricted one does; that is the model, not a leak. This is the call that gets you the `program_id` every card write needs.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:read"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List programs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramPage"
                },
                "examples": {
                  "default": {
                    "value": {
                      "data": [
                        {
                          "id": "prg_docsfixture0001",
                          "name": "Coffee Card",
                          "description": "Ten coffees, the eleventh on us.",
                          "category": "bar",
                          "type": "standard",
                          "active": true,
                          "published_at": "2026-09-04T10:15:00.000Z",
                          "suspended_at": null,
                          "total_stamps": 10,
                          "repeat_after_reset": true,
                          "discount_percent": null,
                          "initial_balance_cents": null,
                          "default_expire_after_days": 365,
                          "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                          "access_image_url": null,
                          "brand_color_hex": "#6F4E37",
                          "bg_color_hex": "#FFF8F0",
                          "text_color_hex": "#2B1B12",
                          "icon_key": "mug-hot",
                          "location_scope": "all_locations",
                          "scoped_location_ids": [
                            "loc_docsfixture0001"
                          ],
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "next_cursor": "eyJjIjoiMjAyNi0wOC0wNVQxMDoxNTowMC4wMDBaIiwiaSI6ImNpbl9kb2NzZml4dHVyZTAwMDEifQ",
                      "limit": 25
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createProgram",
        "summary": "Create a program",
        "description": "Creates a card template. It is created UNPUBLISHED — publish it as a second call once you are happy with it. Image uploads are not part of v1: supply a logo or access image by URL at create time instead. Several fields are conditionally required by `type` and the example below cannot show every branch at once: a stamp program (`standard`, `private`) also needs `total_stamps` and `icon_key`, `discount` needs `discount_percent`, `access` needs `access_image_url`, and `prepaid` needs `initial_balance_cents`.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProgramRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "name": "Coffee Card",
                    "name_localizations": {
                      "it": "Tessera Caffè"
                    },
                    "description": "Ten coffees, the eleventh on us.",
                    "description_localizations": {
                      "it": "Dieci caffè, l’undicesimo lo offriamo noi."
                    },
                    "category": "bar",
                    "brand_color_hex": "#6F4E37",
                    "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                    "total_stamps": 10,
                    "repeat_after_reset": true,
                    "stamps_expire_after_days": 180,
                    "visible_in_catalog": true,
                    "location_scope": "all_locations",
                    "border_enabled": false,
                    "type": "standard"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Create a program",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prg_docsfixture0001",
                      "name": "Coffee Card",
                      "description": "Ten coffees, the eleventh on us.",
                      "category": "bar",
                      "type": "standard",
                      "active": true,
                      "published_at": "2026-09-04T10:15:00.000Z",
                      "suspended_at": null,
                      "total_stamps": 10,
                      "repeat_after_reset": true,
                      "discount_percent": null,
                      "initial_balance_cents": null,
                      "default_expire_after_days": 365,
                      "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                      "access_image_url": null,
                      "brand_color_hex": "#6F4E37",
                      "bg_color_hex": "#FFF8F0",
                      "text_color_hex": "#2B1B12",
                      "icon_key": "mug-hot",
                      "location_scope": "all_locations",
                      "scoped_location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z",
                      "prizes": [
                        {
                          "id": "prz_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "threshold": 10,
                          "name": "Free coffee",
                          "description": "One espresso or filter coffee, redeemed at the till.",
                          "ordinal": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "has_installed_cards": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}": {
      "get": {
        "operationId": "getProgram",
        "summary": "Get one program",
        "description": "The full template: everything the list returns, plus the prize ladder resolved in order and `has_installed_cards` — the edit lock. Once a single card minted from this program is installed on a device, the template is frozen and an update returns `program_has_installed_cards`, so check that flag before offering an edit screen of your own.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "Get one program",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prg_docsfixture0001",
                      "name": "Coffee Card",
                      "description": "Ten coffees, the eleventh on us.",
                      "category": "bar",
                      "type": "standard",
                      "active": true,
                      "published_at": "2026-09-04T10:15:00.000Z",
                      "suspended_at": null,
                      "total_stamps": 10,
                      "repeat_after_reset": true,
                      "discount_percent": null,
                      "initial_balance_cents": null,
                      "default_expire_after_days": 365,
                      "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                      "access_image_url": null,
                      "brand_color_hex": "#6F4E37",
                      "bg_color_hex": "#FFF8F0",
                      "text_color_hex": "#2B1B12",
                      "icon_key": "mug-hot",
                      "location_scope": "all_locations",
                      "scoped_location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z",
                      "prizes": [
                        {
                          "id": "prz_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "threshold": 10,
                          "name": "Free coffee",
                          "description": "One espresso or filter coffee, redeemed at the till.",
                          "ordinal": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "has_installed_cards": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateProgram",
        "summary": "Update a program",
        "description": "A partial update — send only the fields you are changing. `type` is immutable after create. If any card from this program is installed on a device the template is locked and this returns 409 `program_has_installed_cards`: publish a new program rather than editing a card people are already carrying. Sending `prizes` REPLACES the whole ladder; omit it to leave the ladder alone, and send `[]` to clear it.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProgramRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "name": "Coffee Card",
                    "name_localizations": {
                      "it": "Tessera Caffè"
                    },
                    "description": "Ten coffees, the eleventh on us.",
                    "description_localizations": {
                      "it": "Dieci caffè, l’undicesimo lo offriamo noi."
                    },
                    "category": "bar",
                    "brand_color_hex": "#6F4E37",
                    "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                    "total_stamps": 10,
                    "repeat_after_reset": true,
                    "stamps_expire_after_days": 180
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update a program",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prg_docsfixture0001",
                      "name": "Coffee Card",
                      "description": "Ten coffees, the eleventh on us.",
                      "category": "bar",
                      "type": "standard",
                      "active": true,
                      "published_at": "2026-09-04T10:15:00.000Z",
                      "suspended_at": null,
                      "total_stamps": 10,
                      "repeat_after_reset": true,
                      "discount_percent": null,
                      "initial_balance_cents": null,
                      "default_expire_after_days": 365,
                      "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                      "access_image_url": null,
                      "brand_color_hex": "#6F4E37",
                      "bg_color_hex": "#FFF8F0",
                      "text_color_hex": "#2B1B12",
                      "icon_key": "mug-hot",
                      "location_scope": "all_locations",
                      "scoped_location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z",
                      "prizes": [
                        {
                          "id": "prz_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "threshold": 10,
                          "name": "Free coffee",
                          "description": "One espresso or filter coffee, redeemed at the till.",
                          "ordinal": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "has_installed_cards": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/publish": {
      "post": {
        "operationId": "publishProgram",
        "summary": "Publish a program",
        "description": "Makes the template live: from here on it can issue cards and, for catalogue types, it appears in the consumer app. A program is created unpublished, so this is the second half of every create — a program that is never published can still be read over the API but nobody can hold one.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Publish a program",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prg_docsfixture0001",
                      "name": "Coffee Card",
                      "description": "Ten coffees, the eleventh on us.",
                      "category": "bar",
                      "type": "standard",
                      "active": true,
                      "published_at": "2026-09-04T10:15:00.000Z",
                      "suspended_at": null,
                      "total_stamps": 10,
                      "repeat_after_reset": true,
                      "discount_percent": null,
                      "initial_balance_cents": null,
                      "default_expire_after_days": 365,
                      "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                      "access_image_url": null,
                      "brand_color_hex": "#6F4E37",
                      "bg_color_hex": "#FFF8F0",
                      "text_color_hex": "#2B1B12",
                      "icon_key": "mug-hot",
                      "location_scope": "all_locations",
                      "scoped_location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z",
                      "prizes": [
                        {
                          "id": "prz_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "threshold": 10,
                          "name": "Free coffee",
                          "description": "One espresso or filter coffee, redeemed at the till.",
                          "ordinal": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "has_installed_cards": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/unpublish": {
      "post": {
        "operationId": "unpublishProgram",
        "summary": "Unpublish a program",
        "description": "Existing cards keep working. There is no program delete over the API — it is destructive and dashboard-only.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Unpublish a program",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prg_docsfixture0001",
                      "name": "Coffee Card",
                      "description": "Ten coffees, the eleventh on us.",
                      "category": "bar",
                      "type": "standard",
                      "active": true,
                      "published_at": "2026-09-04T10:15:00.000Z",
                      "suspended_at": null,
                      "total_stamps": 10,
                      "repeat_after_reset": true,
                      "discount_percent": null,
                      "initial_balance_cents": null,
                      "default_expire_after_days": 365,
                      "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                      "access_image_url": null,
                      "brand_color_hex": "#6F4E37",
                      "bg_color_hex": "#FFF8F0",
                      "text_color_hex": "#2B1B12",
                      "icon_key": "mug-hot",
                      "location_scope": "all_locations",
                      "scoped_location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z",
                      "prizes": [
                        {
                          "id": "prz_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "threshold": 10,
                          "name": "Free coffee",
                          "description": "One espresso or filter coffee, redeemed at the till.",
                          "ordinal": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "has_installed_cards": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/suspend": {
      "post": {
        "operationId": "suspendProgram",
        "summary": "Suspend a program",
        "description": "A temporary stop, distinct from unpublish: existing cards stop earning and redeeming until it is lifted, rather than the template merely leaving the catalogue. Use it when a promotion is paused mid-flight; use unpublish when it is over.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Suspend a program",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prg_docsfixture0001",
                      "name": "Coffee Card",
                      "description": "Ten coffees, the eleventh on us.",
                      "category": "bar",
                      "type": "standard",
                      "active": true,
                      "published_at": "2026-09-04T10:15:00.000Z",
                      "suspended_at": null,
                      "total_stamps": 10,
                      "repeat_after_reset": true,
                      "discount_percent": null,
                      "initial_balance_cents": null,
                      "default_expire_after_days": 365,
                      "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                      "access_image_url": null,
                      "brand_color_hex": "#6F4E37",
                      "bg_color_hex": "#FFF8F0",
                      "text_color_hex": "#2B1B12",
                      "icon_key": "mug-hot",
                      "location_scope": "all_locations",
                      "scoped_location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z",
                      "prizes": [
                        {
                          "id": "prz_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "threshold": 10,
                          "name": "Free coffee",
                          "description": "One espresso or filter coffee, redeemed at the till.",
                          "ordinal": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "has_installed_cards": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/unsuspend": {
      "post": {
        "operationId": "unsuspendProgram",
        "summary": "Unsuspend a program",
        "description": "Lifts a suspension and resumes earning and redeeming on every card of the program. Nothing is replayed: activity that would have happened while suspended did not happen.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Unsuspend a program",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prg_docsfixture0001",
                      "name": "Coffee Card",
                      "description": "Ten coffees, the eleventh on us.",
                      "category": "bar",
                      "type": "standard",
                      "active": true,
                      "published_at": "2026-09-04T10:15:00.000Z",
                      "suspended_at": null,
                      "total_stamps": 10,
                      "repeat_after_reset": true,
                      "discount_percent": null,
                      "initial_balance_cents": null,
                      "default_expire_after_days": 365,
                      "logo_url": "https://cdn.tesserapp.eu/shops/caffe-docsfixture/logo.png",
                      "access_image_url": null,
                      "brand_color_hex": "#6F4E37",
                      "bg_color_hex": "#FFF8F0",
                      "text_color_hex": "#2B1B12",
                      "icon_key": "mug-hot",
                      "location_scope": "all_locations",
                      "scoped_location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z",
                      "prizes": [
                        {
                          "id": "prz_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "threshold": 10,
                          "name": "Free coffee",
                          "description": "One espresso or filter coffee, redeemed at the till.",
                          "ordinal": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ],
                      "has_installed_cards": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/prizes": {
      "get": {
        "operationId": "listPrizes",
        "summary": "List a program's prizes",
        "description": "The prize ladder in `ordinal` order. A ladder is at most three thresholds with at most three interchangeable options each, and the holder redeems ONE option per threshold — which is why several rows can share a `threshold`. Not paginated: the whole ladder is always one response.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "List a program's prizes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrizeList"
                },
                "examples": {
                  "default": {
                    "value": {
                      "data": [
                        {
                          "id": "prz_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "threshold": 10,
                          "name": "Free coffee",
                          "description": "One espresso or filter coffee, redeemed at the till.",
                          "ordinal": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPrize",
        "summary": "Add a prize",
        "description": "Adds one rung to the ladder, or one more option at a threshold that already exists. `threshold` is the stamp count that unlocks it and must be reachable — a threshold above the program's `total_stamps` is refused. Caps: three distinct thresholds per program, three options per threshold.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePrizeRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "threshold": 10,
                    "name": "Free coffee",
                    "name_localizations": {
                      "it": "Tessera Caffè"
                    },
                    "description": "One espresso or filter coffee, redeemed at the till.",
                    "description_localizations": {
                      "it": "Dieci caffè, l’undicesimo lo offriamo noi."
                    },
                    "ordinal": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Add a prize",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Prize"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prz_docsfixture0001",
                      "program_id": "prg_docsfixture0001",
                      "threshold": 10,
                      "name": "Free coffee",
                      "description": "One espresso or filter coffee, redeemed at the till.",
                      "ordinal": 0,
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/prizes/{prizeId}": {
      "patch": {
        "operationId": "updatePrize",
        "summary": "Update a prize",
        "description": "Renames a prize or moves it. Editing the ladder of a program whose cards are already installed is subject to the same edit lock as the program itself — a holder must not watch the reward they were working towards change underneath them.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "name": "prizeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePrizeRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "threshold": 10,
                    "name": "Free coffee",
                    "name_localizations": {
                      "it": "Tessera Caffè"
                    },
                    "description": "One espresso or filter coffee, redeemed at the till.",
                    "description_localizations": {
                      "it": "Dieci caffè, l’undicesimo lo offriamo noi."
                    },
                    "ordinal": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update a prize",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Prize"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "prz_docsfixture0001",
                      "program_id": "prg_docsfixture0001",
                      "threshold": 10,
                      "name": "Free coffee",
                      "description": "One espresso or filter coffee, redeemed at the till.",
                      "ordinal": 0,
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deletePrize",
        "summary": "Delete a prize",
        "description": "Removes one option from the ladder. Prizes already redeemed are unaffected: a redemption is a transaction, and deleting the prize it named does not rewrite history.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "name": "prizeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "Done. No content."
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/stats": {
      "get": {
        "operationId": "getProgramStats",
        "summary": "A program's statistics",
        "description": "The numbers behind the dashboard's program page: cards, stamps, redemptions, completion rate, and the per-day / per-location / per-hour breakdowns. EVERY aggregate is nullable and that is the contract — each sub-query runs independently and returns null if it fails, so one broken aggregation degrades one widget instead of failing the call. Treat null as \"unavailable\", never as zero. `timezone` is the shop's, and every bucket is anchored to it.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "A program's statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramStats"
                },
                "examples": {
                  "default": {
                    "value": {
                      "active_cards": 1452,
                      "total_stamps_awarded": 9310,
                      "prizes_redeemed": 214,
                      "completion_rate": 0.18,
                      "cards_by_day": [
                        {
                          "date": "2026-09-04",
                          "count": 12
                        }
                      ],
                      "stamps_by_day": [
                        {
                          "date": "2026-09-04",
                          "count": 12
                        }
                      ],
                      "cards_by_location": [
                        {
                          "location_id": "loc_docsfixture0001",
                          "location_name": "Via Roma 1",
                          "count": 12
                        }
                      ],
                      "stamps_by_location": [
                        {
                          "location_id": "loc_docsfixture0001",
                          "location_name": "Via Roma 1",
                          "count": 12
                        }
                      ],
                      "stamps_by_hour_dow": [
                        {
                          "day_of_week": 1,
                          "hour": 9,
                          "count": 12
                        }
                      ],
                      "platform_split": {
                        "apple": 812,
                        "google": 640
                      },
                      "avg_days_between_stamps": 6.4,
                      "timezone": "Europe/Rome"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/timeline": {
      "get": {
        "operationId": "getProgramTimeline",
        "summary": "A program's activity timeline",
        "description": "Cards issued and stamps awarded per bucket over a range, grouped by day, week or month. `buckets` is the label axis and the series are index-aligned with it, zero-filled, so it can be charted without reindexing. `stamps` is null — not an array of zeros — for faced programs (discount, access, prepaid, points), which have no stamps at all. Very long ranges at day granularity are refused rather than truncated.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "A program's activity timeline",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramTimeline"
                },
                "examples": {
                  "default": {
                    "value": {
                      "group": "day",
                      "from": "2026-08-05",
                      "to": "2026-09-04",
                      "buckets": [
                        "2026-09-04"
                      ],
                      "cards": [
                        37
                      ],
                      "stamps": [
                        96
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/enrollment-qr": {
      "get": {
        "operationId": "getEnrollmentQr",
        "summary": "The public enrollment deep link and its QR",
        "description": "Returns the deep link string and an inline SVG, so embedding it in your own portal — or printing a poster — is one call.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "programs:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "The public enrollment deep link and its QR",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentQr"
                },
                "examples": {
                  "default": {
                    "value": {
                      "deep_link": "tesserapp://program/prg_docsfixture0001/enroll",
                      "qr_svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 25 25\" shape-rendering=\"crispEdges\">…</svg>"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/cards": {
      "post": {
        "operationId": "issueCard",
        "summary": "Issue a card",
        "description": "The primary write. Set `external_ref` to YOUR id for the person — it comes back on every read and in every webhook, and it is the field to join on.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "cards:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueCardRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "holder_name": "Ada Lovelace",
                    "holder_email": "ada@docsfixture.invalid",
                    "external_ref": "EMP-00417",
                    "expires_at": "2026-10-04T10:15:00.000Z",
                    "send_email": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Issue a card",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssuedCard"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "cin_docsfixture0001",
                      "program_id": "prg_docsfixture0001",
                      "external_ref": "EMP-00417",
                      "holder_name": "Ada Lovelace",
                      "holder_email": "ada@docsfixture.invalid",
                      "expires_at": "2026-10-04T10:15:00.000Z",
                      "install_url": "https://tesserapp.eu/install#p=prg_docsfixture0001&t=itk_docsfixture0001",
                      "install_url_expires_at": "2026-10-04T10:15:00.000Z",
                      "install_qr_svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 25 25\" shape-rendering=\"crispEdges\">…</svg>"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cards": {
      "get": {
        "operationId": "listCards",
        "summary": "List and search cards",
        "description": "Filterable by `external_ref`, `holder_email`, `program_id` and status. Cursor-paginated.",
        "tags": [
          "cards"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "cards:read"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "external_ref",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "holder_email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "email"
            }
          },
          {
            "name": "program_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List and search cards",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardPage"
                },
                "examples": {
                  "default": {
                    "value": {
                      "data": [
                        {
                          "id": "cin_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "program_name": "Coffee Card",
                          "program_type": "standard",
                          "external_ref": "EMP-00417",
                          "holder_name": "Ada Lovelace",
                          "holder_email": "ada@docsfixture.invalid",
                          "status": "active",
                          "stamps_count": 4,
                          "current_value": 4,
                          "expires_at": "2026-10-04T10:15:00.000Z",
                          "installed_at": "2026-09-04T10:15:00.000Z",
                          "created_at": "2026-08-05T10:15:00.000Z"
                        }
                      ],
                      "next_cursor": "eyJjIjoiMjAyNi0wOC0wNVQxMDoxNTowMC4wMDBaIiwiaSI6ImNpbl9kb2NzZml4dHVyZTAwMDEifQ",
                      "limit": 25
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cards/{id}": {
      "get": {
        "operationId": "getCard",
        "summary": "Get one card",
        "description": "One holder's card, with the program it was minted from and the locations it works at (derived from the PROGRAM's scope — a card carries no location of its own). `installed_at` is the field to check before offering an edit: once it is set, the pass is on a device and the holder fields are frozen.",
        "tags": [
          "cards"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "cards:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "Get one card",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "cin_docsfixture0001",
                      "program_id": "prg_docsfixture0001",
                      "program_name": "Coffee Card",
                      "program_type": "standard",
                      "external_ref": "EMP-00417",
                      "holder_name": "Ada Lovelace",
                      "holder_email": "ada@docsfixture.invalid",
                      "status": "active",
                      "stamps_count": 4,
                      "current_value": 4,
                      "expires_at": "2026-10-04T10:15:00.000Z",
                      "installed_at": "2026-09-04T10:15:00.000Z",
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "all_locations": true,
                      "locations": [
                        {
                          "id": "loc_docsfixture0001",
                          "name": "Via Roma 1"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateCard",
        "summary": "Update a card",
        "description": "Holder fields and `external_ref`. A card installed on a device is locked: its holder fields and expiry are frozen and a write returns `card_locked` — reissue instead of editing.",
        "tags": [
          "cards"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "cards:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCardRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "holder_name": "Ada Lovelace",
                    "holder_email": "ada@docsfixture.invalid",
                    "expires_at": "2026-10-04T10:15:00.000Z",
                    "external_ref": "EMP-00417"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update a card",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardDetail"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "cin_docsfixture0001",
                      "program_id": "prg_docsfixture0001",
                      "program_name": "Coffee Card",
                      "program_type": "standard",
                      "external_ref": "EMP-00417",
                      "holder_name": "Ada Lovelace",
                      "holder_email": "ada@docsfixture.invalid",
                      "status": "active",
                      "stamps_count": 4,
                      "current_value": 4,
                      "expires_at": "2026-10-04T10:15:00.000Z",
                      "installed_at": "2026-09-04T10:15:00.000Z",
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "all_locations": true,
                      "locations": [
                        {
                          "id": "loc_docsfixture0001",
                          "name": "Via Roma 1"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteCard",
        "summary": "Delete a card (the GDPR / offboarding path)",
        "description": "The same service call the dashboard's delete makes, so every scrub that path performs — including the single-holder webhook payload scrub — applies here too. Requires an unrestricted key.",
        "tags": [
          "cards"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "cards:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "Done. No content."
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cards/{id}/stats": {
      "get": {
        "operationId": "getCardStats",
        "summary": "One card's statistics",
        "description": "Per-card activity for a support screen: \"how many stamps has this person actually earned, and when did they last come in\". `kpis` is a map whose keys depend on the card type (stamp, prepaid, points or faced) — read the keys your card type has and ignore the rest, so a new card type cannot break your parser.",
        "tags": [
          "cards"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "cards:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "One card's statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardStats"
                },
                "examples": {
                  "default": {
                    "value": {
                      "card_type": "standard",
                      "kpis": {
                        "stamps_count": 4
                      },
                      "activity_by_day": [
                        {
                          "date": "2026-09-04",
                          "value": 12
                        }
                      ],
                      "timezone": "Europe/Rome"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cards/{id}/reissue": {
      "post": {
        "operationId": "reissueCard",
        "summary": "Reissue a card",
        "description": "Returns a fresh single-use install link with its expiry, and the same link as an inline QR.",
        "tags": [
          "cards"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "cards:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Reissue a card",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReissuedCard"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "cin_docsfixture0001",
                      "install_url": "https://tesserapp.eu/install#p=prg_docsfixture0001&t=itk_docsfixture0001",
                      "install_url_expires_at": "2026-10-04T10:15:00.000Z",
                      "install_qr_svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 25 25\" shape-rendering=\"crispEdges\">…</svg>"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cards/{id}/archive": {
      "post": {
        "operationId": "archiveCard",
        "summary": "Archive a card",
        "description": "Unbinds the device and keeps the holder for audit. NOT erasure — that is DELETE. Requires an unrestricted key.",
        "tags": [
          "cards"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "cards:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "Done. No content."
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List a program's webhooks",
        "description": "Signing secrets and custom header values are masked on read.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "webhooks:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "List a program's webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "examples": {
                  "default": {
                    "value": {
                      "items": [
                        {
                          "id": "whk_docsfixture0001",
                          "shop_id": "shp_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "url": "https://hooks.example.com/tesserapp",
                          "events": [
                            "stamp.assigned"
                          ],
                          "active": true,
                          "description": "CRM sync — production receiver",
                          "has_bearer_token": true,
                          "program_ids": [
                            "prg_docsfixture0001"
                          ],
                          "location_ids": [
                            "loc_docsfixture0001"
                          ],
                          "include_shop_wide_events": true,
                          "http_method": "POST",
                          "custom_headers": {
                            "X-Partner-Token": "••••"
                          },
                          "payload_version": "v1",
                          "consecutive_failures": 0,
                          "created_at": "2026-08-05T10:15:00.000Z",
                          "updated_at": "2026-09-04T10:15:00.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Register a webhook",
        "description": "The response carries the signing secret ONCE. `url` must be https and must resolve to a public address. An empty program or location filter means ALL — see the webhook guide.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "webhooks:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "url": "https://hooks.example.com/tesserapp",
                    "events": [
                      "stamp.assigned"
                    ],
                    "bearer_token": "a-token-your-receiver-checks",
                    "active": true,
                    "description": "CRM sync — production receiver",
                    "program_ids": [
                      "prg_docsfixture0001"
                    ],
                    "location_ids": [
                      "loc_docsfixture0001"
                    ],
                    "include_shop_wide_events": true,
                    "http_method": "POST",
                    "custom_headers": {
                      "X-Partner-Token": "a-value-only-your-receiver-knows"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Register a webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookWithSecret"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "whk_docsfixture0001",
                      "shop_id": "shp_docsfixture0001",
                      "program_id": "prg_docsfixture0001",
                      "url": "https://hooks.example.com/tesserapp",
                      "events": [
                        "stamp.assigned"
                      ],
                      "active": true,
                      "description": "CRM sync — production receiver",
                      "has_bearer_token": true,
                      "program_ids": [
                        "prg_docsfixture0001"
                      ],
                      "location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "include_shop_wide_events": true,
                      "http_method": "POST",
                      "custom_headers": {
                        "X-Partner-Token": "••••"
                      },
                      "payload_version": "v1",
                      "consecutive_failures": 0,
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z",
                      "secret": "whsec_docs_fixture_secret_do_not_use_in_production"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/webhooks/{webhookId}": {
      "patch": {
        "operationId": "updateWebhook",
        "summary": "Update a webhook",
        "description": "Setting `active` back to true is how an auto-disabled webhook is re-enabled; it also resets the consecutive-failure counter. `rotate_secret` returns a new secret once — signing switches immediately, so update your receiver in the same change.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "webhooks:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "url": "https://hooks.example.com/tesserapp",
                    "events": [
                      "stamp.assigned"
                    ],
                    "bearer_token": "a-token-your-receiver-checks",
                    "active": true,
                    "description": "CRM sync — production receiver",
                    "rotate_secret": false,
                    "program_ids": [
                      "prg_docsfixture0001"
                    ],
                    "location_ids": [
                      "loc_docsfixture0001"
                    ],
                    "include_shop_wide_events": true,
                    "http_method": "POST"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update a webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookUpdated"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "whk_docsfixture0001",
                      "shop_id": "shp_docsfixture0001",
                      "program_id": "prg_docsfixture0001",
                      "url": "https://hooks.example.com/tesserapp",
                      "events": [
                        "stamp.assigned"
                      ],
                      "active": true,
                      "description": "CRM sync — production receiver",
                      "has_bearer_token": true,
                      "program_ids": [
                        "prg_docsfixture0001"
                      ],
                      "location_ids": [
                        "loc_docsfixture0001"
                      ],
                      "include_shop_wide_events": true,
                      "http_method": "POST",
                      "custom_headers": {
                        "X-Partner-Token": "••••"
                      },
                      "payload_version": "v1",
                      "consecutive_failures": 0,
                      "created_at": "2026-08-05T10:15:00.000Z",
                      "updated_at": "2026-09-04T10:15:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Delete a webhook",
        "description": "A soft delete: it stops firing and stops being listed, and its delivery history survives.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "webhooks:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "Done. No content."
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/webhooks/{webhookId}/test": {
      "post": {
        "operationId": "testWebhook",
        "summary": "Send a test ping",
        "description": "Posts a `test.ping` payload signed exactly like a real delivery, bypassing subscription matching. A genuine test of your verification code. The ping is ENQUEUED, not sent inline: the response is the id of the delivery row, and its outcome shows up in the delivery log.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "webhooks:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Send a test ping",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTestPing"
                },
                "examples": {
                  "default": {
                    "value": {
                      "delivery_id": "whd_docsfixture0001"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/programs/{id}/webhooks/{webhookId}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "summary": "The delivery log for one webhook",
        "description": "Every attempt with its status, duration and error, and the headers sent with secrets masked. Retained for the configured window, which is a data-minimisation control.",
        "tags": [
          "programs"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "webhooks:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The delivery log for one webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryList"
                },
                "examples": {
                  "default": {
                    "value": {
                      "items": [
                        {
                          "id": "whd_docsfixture0001",
                          "webhook_id": "whk_docsfixture0001",
                          "event": "stamp.assigned",
                          "event_id": "evt_docsfixture000001",
                          "request_payload": {
                            "event": "stamp.assigned",
                            "event_id": "evt_docsfixture000001",
                            "payload_version": "v2",
                            "occurred_at": "2026-09-04T10:15:00.000Z",
                            "shop": {
                              "id": "shp_docsfixture0001",
                              "name": "Caffè Docsfixture"
                            },
                            "location": {
                              "id": "loc_docsfixture0001",
                              "name": "Via Roma 1"
                            },
                            "program": {
                              "id": "prg_docsfixture0001",
                              "name": "Coffee Card",
                              "type": "standard"
                            },
                            "card": {
                              "id": "cin_docsfixture0001",
                              "external_ref": "EMP-00417",
                              "state": "active",
                              "holder": {
                                "name": "Ada Lovelace",
                                "email": "ada@docsfixture.invalid"
                              }
                            },
                            "transaction": {
                              "id": "trx_docsfixture0001",
                              "type": "stamp",
                              "metadata": {
                                "source": "shop_app"
                              }
                            },
                            "actor": {
                              "type": "device",
                              "id": "dev_docsfixture0001"
                            },
                            "data": {
                              "card_instance_id": "cin_docsfixture0001",
                              "stamps_delta": 1,
                              "stamps_count": 4,
                              "transaction_id": "trx_docsfixture0001"
                            }
                          },
                          "request_headers": {
                            "X-Tesserapp-Signature": "t=1757000000,v1=…"
                          },
                          "response_status": 200,
                          "attempts": 1,
                          "last_error": null,
                          "duration_ms": 142,
                          "card_instance_id": "cin_docsfixture0001",
                          "delivered_at": "2026-09-04T10:15:00.000Z",
                          "created_at": "2026-08-05T10:15:00.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/transactions": {
      "get": {
        "operationId": "listTransactions",
        "summary": "List transactions",
        "description": "The ledger: every stamp, redemption, reversal and expiry, newest first. Filterable by location, program, card, type and date range, and cursor-paginated — the cursor is a keyset, so a row inserted while you are paging cannot make you skip one. This is the one read a location-restricted key can genuinely narrow, because every transaction carries the site it happened at; asking for a location outside the restriction returns an EMPTY PAGE rather than an error, so a sync loop does not break on it. There is NO endpoint that writes a transaction, and no `transactions:write` scope: a transaction is the record that a real card was presented at a real place.",
        "tags": [
          "transactions"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "transactions:read"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "location_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "program_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "card_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List transactions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionPage"
                },
                "examples": {
                  "default": {
                    "value": {
                      "data": [
                        {
                          "id": "trx_docsfixture0001",
                          "card_id": "cin_docsfixture0001",
                          "program_id": "prg_docsfixture0001",
                          "type": "stamp",
                          "location_id": "loc_docsfixture0001",
                          "location_name": "Via Roma 1",
                          "stamps_delta": 1,
                          "value_delta": null,
                          "prize_id": null,
                          "reversed_at": null,
                          "created_at": "2026-08-05T10:15:00.000Z"
                        }
                      ],
                      "next_cursor": "eyJjIjoiMjAyNi0wOC0wNVQxMDoxNTowMC4wMDBaIiwiaSI6ImNpbl9kb2NzZml4dHVyZTAwMDEifQ",
                      "limit": 25
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/transactions/{id}": {
      "get": {
        "operationId": "getTransaction",
        "summary": "Get one transaction",
        "description": "One ledger entry, by the id a webhook or a list page gave you. The natural second call after a `transaction.created` delivery when your receiver keeps only the id. A location-restricted key gets 404 for a transaction at another site — never 403, which would confirm it exists.",
        "tags": [
          "transactions"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "transactions:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "An opaque id. The API never promises an id format."
          }
        ],
        "responses": {
          "200": {
            "description": "Get one transaction",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transaction"
                },
                "examples": {
                  "default": {
                    "value": {
                      "id": "trx_docsfixture0001",
                      "card_id": "cin_docsfixture0001",
                      "program_id": "prg_docsfixture0001",
                      "type": "stamp",
                      "location_id": "loc_docsfixture0001",
                      "location_name": "Via Roma 1",
                      "stamps_delta": 1,
                      "value_delta": null,
                      "prize_id": null,
                      "reversed_at": null,
                      "created_at": "2026-08-05T10:15:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/analytics/stamps-timeline": {
      "get": {
        "operationId": "getStampsTimeline",
        "summary": "Stamps over time",
        "description": "Transaction-derived: recomputed for a location-restricted key.",
        "tags": [
          "analytics"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "analytics:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "day",
                "week",
                "month"
              ]
            }
          },
          {
            "name": "program_ids",
            "in": "query",
            "required": true,
            "schema": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stamps over time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StampsTimeline"
                },
                "examples": {
                  "default": {
                    "value": {
                      "group": "day",
                      "from": "2026-08-05",
                      "to": "2026-09-04",
                      "buckets": [
                        "2026-09-04"
                      ],
                      "series": [
                        {
                          "program_id": "prg_docsfixture0001",
                          "program_name": "Coffee Card",
                          "brand_color_hex": "#6F4E37",
                          "data": [
                            96
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/analytics/activity-heatmap": {
      "get": {
        "operationId": "getActivityHeatmap",
        "summary": "Activity by hour and weekday",
        "description": "Transaction-derived: recomputed for a location-restricted key.",
        "tags": [
          "analytics"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "analytics:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "weeks",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Activity by hour and weekday",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivityHeatmap"
                },
                "examples": {
                  "default": {
                    "value": {
                      "from": "2026-08-05",
                      "to": "2026-09-04",
                      "days": [
                        {
                          "date": "2026-09-04",
                          "count": 12
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/analytics/top-programs": {
      "get": {
        "operationId": "getTopPrograms",
        "summary": "Busiest programs",
        "description": "Transaction-derived: recomputed for a location-restricted key.",
        "tags": [
          "analytics"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "analytics:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Busiest programs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TopPrograms"
                },
                "examples": {
                  "default": {
                    "value": {
                      "programs": [
                        {
                          "program_id": "prg_docsfixture0001",
                          "program_name": "Coffee Card",
                          "brand_color_hex": "#6F4E37",
                          "activity_count": 480
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/analytics/card-type-distribution": {
      "get": {
        "operationId": "getCardTypeDistribution",
        "summary": "Cards by type",
        "description": "Card-derived, and cards carry no location, so a location-restricted key gets `location_scope_unsupported` (403) instead of a shop-wide number.",
        "tags": [
          "analytics"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "analytics:read"
            ]
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Cards by type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardTypeDistribution"
                },
                "examples": {
                  "default": {
                    "value": {
                      "distribution": [
                        {
                          "type": "standard",
                          "count": 12,
                          "label_key": "card_types.standard",
                          "color": "#6F4E37"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/analytics/wallet-split": {
      "get": {
        "operationId": "getWalletSplit",
        "summary": "Apple / Google / app split",
        "description": "Card-derived: an unrestricted key is required.",
        "tags": [
          "analytics"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "analytics:read"
            ]
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Apple / Google / app split",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletSplit"
                },
                "examples": {
                  "default": {
                    "value": {
                      "apple": 812,
                      "google": 640,
                      "total": 1452
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/analytics/growth-timeline": {
      "get": {
        "operationId": "getGrowthTimeline",
        "summary": "Growth over time",
        "description": "Mixed series (cards and activity): an unrestricted key is required.",
        "tags": [
          "analytics"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "analytics:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "months",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Growth over time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrowthTimeline"
                },
                "examples": {
                  "default": {
                    "value": {
                      "buckets": [
                        "2026-09-04"
                      ],
                      "new_cards": [
                        37
                      ],
                      "activity": [
                        480
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/analytics/summary": {
      "get": {
        "operationId": "getAnalyticsSummary",
        "summary": "Headline numbers",
        "description": "Mixed aggregate: an unrestricted key is required.",
        "tags": [
          "analytics"
        ],
        "security": [
          {
            "ApiKeyBearer": [
              "analytics:read"
            ]
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Headline numbers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsSummary"
                },
                "examples": {
                  "default": {
                    "value": {
                      "active_locations": 3,
                      "active_programs": 4,
                      "activity_30d": 1290,
                      "new_cards_30d": 96
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or semantic failure. `error.details` lists the offending fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "validation_failed",
                        "message": "The request body failed validation.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V",
                        "details": [
                          {
                            "field": "holder_email",
                            "code": "invalid_email"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Two different failures share this status, and `error.code` is the only thing that tells them apart. `unauthenticated` — missing, malformed, unknown, revoked or expired key, or a key of the wrong class. `business_api_required` — the key is FINE; the shop has no active Business API add-on (and no grant standing in for one). Never re-key on a 401 without reading the code: the second case is recoverable by the merchant, and the same key resumes working.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthenticated",
                        "message": "No usable API key was presented.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  },
                  "business_api_required": {
                    "value": {
                      "error": {
                        "code": "business_api_required",
                        "message": "No Business API add-on is active for this shop. Switch it on from Billing in the dashboard, or ask support to enable it.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the required scope, or its location restriction excludes the target. A shop with no API access is 401 `business_api_required`, not this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "unauthorized",
                        "message": "This key does not carry the scope this endpoint requires.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it belongs to another shop. Deliberately indistinguishable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "not_found",
                        "message": "No such resource.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflict — including `idempotency_conflict` when a key is reused with a different body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "idempotency_conflict",
                        "message": "This Idempotency-Key was already used with a different request body.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour `Retry-After` and retry with the same `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "rate_limited",
                        "message": "Too many requests. Retry after the interval in the Retry-After header.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error. Retry with the same `Idempotency-Key`; quote `request_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "error": {
                        "code": "internal_error",
                        "message": "An unexpected error occurred.",
                        "request_id": "01JQ8Z6Y7K4M2N9P0Q1R2S3T4V"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
