{
  "openapi": "3.1.0",
  "info": {
    "title": "Big Fidelity Public API",
    "version": "1.0.0",
    "summary": "Award and redeem loyalty value from a POS, e-commerce platform or custom system.",
    "description": "The Big Fidelity Public API lets external systems register customers, issue Apple Wallet and Google Wallet passes, add stamps, record membership visits and earn or redeem points.\n\nEvery request needs two headers: `X-API-Key` identifies the business, `Authorization: Token <token>` identifies the user acting on its behalf. Obtain the user token from `POST /auth/token`.\n\nAPI keys are issued per business by Big Fidelity — request one at hello@bigfidelity.com. There is no self-service signup.\n\nCustomers are addressed by your own `external_id` plus a `business_template_id`, so you never store Big Fidelity's internal identifiers.",
    "contact": {
      "name": "Big Fidelity integrations",
      "email": "hello@bigfidelity.com",
      "url": "https://bigfidelity.com/developers"
    },
    "termsOfService": "https://bigfidelity.com/terms-and-conditions"
  },
  "externalDocs": {
    "description": "Big Fidelity Public API reference",
    "url": "https://bigfidelity.com/developers"
  },
  "servers": [
    {
      "url": "https://bigfidelity.xyz/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "apiKey": [],
      "userToken": []
    }
  ],
  "tags": [
    {
      "name": "Authentication",
      "description": "Exchange credentials for a user token."
    },
    {
      "name": "Consumers",
      "description": "Register, read and update customers."
    },
    {
      "name": "Stamps",
      "description": "Stamp and coupon cards (template types S and C)."
    },
    {
      "name": "Visits",
      "description": "Membership visit tracking (template type M)."
    },
    {
      "name": "Points",
      "description": "Points programs (template type P)."
    }
  ],
  "paths": {
    "/auth/token": {
      "post": {
        "operationId": "getUserToken",
        "tags": [
          "Authentication"
        ],
        "summary": "Get a user token",
        "description": "Exchanges a business user's credentials for a long-lived token. The user must belong to the same business as the API key. Tokens do not expire but can be regenerated.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "username": {
                    "type": "string",
                    "description": "Business user's email."
                  },
                  "password": {
                    "type": "string",
                    "format": "password"
                  }
                },
                "required": [
                  "username",
                  "password"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "token": {
                          "type": "string"
                        },
                        "user_id": {
                          "type": "integer"
                        },
                        "user_email": {
                          "type": "string",
                          "format": "email"
                        },
                        "user_name": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key or user token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Consumer or template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/consumers/register": {
      "post": {
        "operationId": "registerConsumer",
        "tags": [
          "Consumers"
        ],
        "summary": "Register a consumer",
        "description": "Registers a customer for a loyalty program and creates their Apple Wallet and Google Wallet passes. Requires the `can_register_consumers` permission.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "external_id": {
                    "type": "string",
                    "description": "Your own unique identifier for the customer, from your POS or CRM."
                  },
                  "business_template_id": {
                    "type": "string",
                    "description": "Identifier of the Big Fidelity loyalty program (template) to act on."
                  },
                  "full_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "phone_number": {
                    "type": "string"
                  },
                  "instagram": {
                    "type": "string"
                  },
                  "birthday": {
                    "type": "string",
                    "format": "date",
                    "description": "YYYY-MM-DD."
                  },
                  "identifier": {
                    "type": "string",
                    "description": "Custom identifier, e.g. a national ID."
                  },
                  "post_code": {
                    "type": "string"
                  },
                  "receive_updates": {
                    "type": "boolean",
                    "default": true
                  },
                  "platform": {
                    "type": "string",
                    "enum": [
                      "android",
                      "ios",
                      ""
                    ],
                    "description": "Restrict pass creation to one wallet. Empty means both."
                  },
                  "custom_qr_content": {
                    "type": "string"
                  }
                },
                "required": [
                  "external_id",
                  "business_template_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Consumer registered, or already registered.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "consumer_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "external_id": {
                          "type": "string"
                        },
                        "created": {
                          "type": "boolean",
                          "description": "True for a new consumer, false when one already existed."
                        },
                        "apple_pass_link": {
                          "type": "string",
                          "format": "uri"
                        },
                        "google_pass_link": {
                          "type": "string",
                          "format": "uri"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key or user token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Consumer or template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "Consumer already registered for this template.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/consumers/info": {
      "get": {
        "operationId": "getConsumerInfo",
        "tags": [
          "Consumers"
        ],
        "summary": "Get consumer info and balance",
        "description": "Returns the customer's profile and current balance. The balance fields depend on the template type: stamps for S/C, points for P, visits and membership status for M. Requires the `can_read_consumers` permission.",
        "parameters": [
          {
            "name": "external_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Your own unique identifier for the customer, from your POS or CRM."
            }
          },
          {
            "name": "business_template_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Identifier of the Big Fidelity loyalty program (template) to act on."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consumer found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "external_id": {
                          "type": "string"
                        },
                        "consumer_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "full_name": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string",
                          "format": "email"
                        },
                        "phone_number": {
                          "type": "string"
                        },
                        "template_type": {
                          "type": "string",
                          "enum": [
                            "S",
                            "C",
                            "M",
                            "P"
                          ],
                          "description": "S stamps, C coupons, M membership, P points."
                        },
                        "valid_stamps": {
                          "type": "integer",
                          "description": "S/C only."
                        },
                        "historic_stamps": {
                          "type": "integer",
                          "description": "S/C only."
                        },
                        "max_stamps": {
                          "type": "integer",
                          "description": "S/C only."
                        },
                        "points_balance": {
                          "type": "integer",
                          "description": "P only."
                        },
                        "available_points": {
                          "type": "integer",
                          "description": "P only."
                        },
                        "expired_points": {
                          "type": "integer",
                          "description": "P only."
                        },
                        "lifetime_points_earned": {
                          "type": "integer",
                          "description": "P only."
                        },
                        "lifetime_points_redeemed": {
                          "type": "integer",
                          "description": "P only."
                        },
                        "membership_status": {
                          "type": "string",
                          "description": "M only."
                        },
                        "membership_code": {
                          "type": "string",
                          "description": "M only."
                        },
                        "membership_type": {
                          "type": "string",
                          "description": "M only."
                        },
                        "visit_count": {
                          "type": "integer",
                          "description": "M only."
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key or user token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Consumer or template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/consumers/update": {
      "post": {
        "operationId": "updateConsumer",
        "tags": [
          "Consumers"
        ],
        "summary": "Update a consumer",
        "description": "Updates profile fields for a customer already registered for the given template. Only the fields you send are changed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "external_id": {
                    "type": "string",
                    "description": "Your own unique identifier for the customer, from your POS or CRM."
                  },
                  "business_template_id": {
                    "type": "string",
                    "description": "Business template UUID. The consumer must already be registered for it.",
                    "format": "uuid"
                  },
                  "full_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "identifier": {
                    "type": "string"
                  },
                  "phone_number": {
                    "type": "string"
                  },
                  "instagram": {
                    "type": "string"
                  },
                  "birthday": {
                    "type": "string",
                    "description": "YYYY-MM-DD or ISO 8601."
                  },
                  "post_code": {
                    "type": "string"
                  },
                  "receive_updates": {
                    "type": "boolean"
                  },
                  "custom_qr_content": {
                    "type": "string",
                    "description": "S, C and M templates only."
                  }
                },
                "required": [
                  "external_id",
                  "business_template_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Consumer updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "external_id": {
                          "type": "string"
                        },
                        "consumer_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "updated_fields": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key or user token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Consumer or template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/stamps/add": {
      "post": {
        "operationId": "addStamps",
        "tags": [
          "Stamps"
        ],
        "summary": "Add stamps to a card",
        "description": "Adds stamps to a stamp or coupon card (template types S and C). `stamps_to_add` may be negative to correct a mistake; both counters floor at zero. The request is rejected with `EXCEEDS_MAX_STAMPS` if it would push the card past `max_stamps`. Requires the `can_update_stamps` permission.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "external_id": {
                    "type": "string",
                    "description": "Your own unique identifier for the customer, from your POS or CRM."
                  },
                  "business_template_id": {
                    "type": "string",
                    "description": "Identifier of the Big Fidelity loyalty program (template) to act on."
                  },
                  "stamps_to_add": {
                    "type": "integer",
                    "default": 1
                  }
                },
                "required": [
                  "external_id",
                  "business_template_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stamps applied.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "external_id": {
                          "type": "string"
                        },
                        "valid_stamps": {
                          "type": "integer"
                        },
                        "historic_stamps": {
                          "type": "integer"
                        },
                        "previous_valid_stamps": {
                          "type": "integer"
                        },
                        "stamps_added": {
                          "type": "integer"
                        },
                        "max_stamps": {
                          "type": "integer"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key or user token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Consumer or template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/visits/add": {
      "post": {
        "operationId": "recordVisit",
        "tags": [
          "Visits"
        ],
        "summary": "Record a membership visit",
        "description": "Records a visit for a membership customer (template type M). Requires the `can_update_visits` permission.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "external_id": {
                    "type": "string",
                    "description": "Your own unique identifier for the customer, from your POS or CRM."
                  },
                  "business_template_id": {
                    "type": "string",
                    "description": "Identifier of the Big Fidelity loyalty program (template) to act on."
                  }
                },
                "required": [
                  "external_id",
                  "business_template_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Visit recorded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "external_id": {
                          "type": "string"
                        },
                        "visit_count": {
                          "type": "integer"
                        },
                        "membership_status": {
                          "type": "string"
                        },
                        "membership_code": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key or user token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Consumer or template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/points/earn": {
      "post": {
        "operationId": "earnPoints",
        "tags": [
          "Points"
        ],
        "summary": "Award points for a purchase",
        "description": "Awards points for a purchase on a points program (template type P). The amount awarded follows the template's `points_per_currency` and `minimum_purchase_for_points` settings. Requires the `can_earn_points` permission.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "external_id": {
                    "type": "string",
                    "description": "Your own unique identifier for the customer, from your POS or CRM."
                  },
                  "business_template_id": {
                    "type": "string",
                    "description": "Identifier of the Big Fidelity loyalty program (template) to act on."
                  },
                  "purchase_amount": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      }
                    ],
                    "description": "Purchase total, e.g. \"150.00\"."
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Free-form data stored with the transaction, e.g. invoice or order number."
                  }
                },
                "required": [
                  "external_id",
                  "business_template_id",
                  "purchase_amount"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Points awarded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "external_id": {
                          "type": "string"
                        },
                        "points_earned": {
                          "type": "integer"
                        },
                        "points_balance": {
                          "type": "integer"
                        },
                        "transaction_id": {
                          "type": "string",
                          "format": "uuid"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key or user token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Consumer or template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/points/redeem": {
      "post": {
        "operationId": "redeemPoints",
        "tags": [
          "Points"
        ],
        "summary": "Redeem points for a discount",
        "description": "Redeems points for a discount on a points program (template type P). The discount follows the template's `redemption_ratio`. Fails with `INSUFFICIENT_BALANCE` when the customer does not have enough points. Requires the `can_redeem_points` permission.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "external_id": {
                    "type": "string",
                    "description": "Your own unique identifier for the customer, from your POS or CRM."
                  },
                  "business_template_id": {
                    "type": "string",
                    "description": "Identifier of the Big Fidelity loyalty program (template) to act on."
                  },
                  "points_to_redeem": {
                    "type": "integer"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "required": [
                  "external_id",
                  "business_template_id",
                  "points_to_redeem"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Points redeemed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "external_id": {
                          "type": "string"
                        },
                        "points_redeemed": {
                          "type": "integer"
                        },
                        "discount_amount": {
                          "type": "string"
                        },
                        "points_balance": {
                          "type": "integer"
                        },
                        "transaction_id": {
                          "type": "string",
                          "format": "uuid"
                        }
                      }
                    }
                  },
                  "required": [
                    "success",
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key or user token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The API key lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Consumer or template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "description": "Human-readable error message."
                        },
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code."
                        }
                      },
                      "required": [
                        "message",
                        "code"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Business API key, issued by Big Fidelity. Format: `bf_live_...`."
      },
      "userToken": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "User token from `POST /auth/token`, sent as `Token <token>`."
      }
    }
  }
}