CampgroundTickets/docs/fluentforms-ticket-vouchers.md
Hank 718d1515b0 docs: dedicated ticket-voucher lookup page under fluent
Move the ticket-voucher API into its own standalone doc
(docs/fluentforms-ticket-vouchers.md) — endpoint, 0/1/2 rules, config, form
snippet, and curl test — so it's easy to find and hand off for the lookup. The
donor-discount doc now links to it instead of duplicating the section.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 06:36:39 +00:00

4.2 KiB

FluentForms → ticket-voucher lookup

Look up, by email, how many free tickets a donor has earned from their giving. Intended for the ticket-rewards / checkout form: enter an email, call this endpoint, and show / apply the earned vouchers.

FluentForms can't query an external database from a field natively, so this is done with a small Custom JS block that calls a secret-gated endpoint on the ticketing backend.

Endpoint

GET https://scan.beartariacampgrounds.com/api/public/ticket-vouchers?key=<SECRET>&email=<email>

Returns only the count — never names or dollar amounts:

{ "vouchers": 0 }   // or 1, or 2
  • key = the value of PUBLIC_LOOKUP_SECRET (set in the backend .env).
  • email = the donor's email (URL-encoded).
  • Rate-limited (30 requests / minute / IP) and CORS-restricted to PUBLIC_LOOKUP_ORIGIN (default https://tickets.beartariacampgrounds.com).

The secret is visible in page source, so treat it as deterrence, not security — it only gates a 0/1/2 count. Rotate it by changing PUBLIC_LOOKUP_SECRET and redeploying.

Rules

Donations are summed for the email across the online + offline transaction tables, counting only Paid rows dated on/after VOUCHER_SINCE:

Total since the cutoff Vouchers
≥ $1000 2
≥ $400 1
otherwise 0

Configurable in the backend .env:

Var Default Meaning
VOUCHER_SINCE 2025-09-04 Only donations on/after this date count. Bump each year.
VOUCHER_TIER1_MIN 400 Dollar total for 1 voucher
VOUCHER_TIER2_MIN 1000 Dollar total for 2 vouchers

The count comes from the dated transaction tables (the donor master-list rollups have no dates), so donations must exist in those tables for the window.

Form snippet

Add a Custom HTML element to the form and paste this, setting KEY to your PUBLIC_LOOKUP_SECRET (and EMAIL_SELECTOR if the email field isn't named email). It shows the earned count on email blur and writes it into a hidden field free_tickets you can use for conditional logic or to cap a quantity.

<div id="voucher-status" style="margin:6px 0;font-size:14px;font-weight:600;"></div>
<script>
(function () {
  var API = "https://scan.beartariacampgrounds.com/api/public/ticket-vouchers";
  var KEY = "REPLACE_WITH_PUBLIC_LOOKUP_SECRET";
  var EMAIL_SELECTOR = 'input[name="email"]';
  var statusEl = document.getElementById("voucher-status");
  var last = "";

  function show(n) {
    statusEl.textContent = n > 0
      ? "🎟️ You've earned " + n + " free ticket" + (n > 1 ? "s" : "") + "!"
      : "";
    statusEl.style.color = "#1b7f3b";
    // Optional: write the count into a hidden field named "free_tickets".
    // Uses the native setter so FluentForms' Vue model registers the change.
    var el = document.querySelector('input[name="free_tickets"]');
    if (el) {
      var d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el), "value");
      (d && d.set ? d.set : function (v) { el.value = v; }).call(el, String(n));
      el.dispatchEvent(new Event("input", { bubbles: true }));
      el.dispatchEvent(new Event("change", { bubbles: true }));
    }
  }

  function check(email) {
    if (!email || email === last) return;
    last = email;
    fetch(API + "?key=" + encodeURIComponent(KEY) + "&email=" + encodeURIComponent(email))
      .then(function (r) { return r.json(); })
      .then(function (d) { show(d && d.vouchers ? d.vouchers : 0); })
      .catch(function () { show(0); });
  }

  function bind() {
    var el = document.querySelector(EMAIL_SELECTOR);
    if (!el) { return setTimeout(bind, 500); }   // form may render late
    el.addEventListener("blur", function () { check(el.value.trim().toLowerCase()); });
  }
  bind();
})();
</script>

Test

curl "https://scan.beartariacampgrounds.com/api/public/ticket-vouchers?key=<SECRET>&email=<a-real-donor-email>"
# >= $1000 since cutoff -> {"vouchers":2}
# >= $400  since cutoff -> {"vouchers":1}
# otherwise             -> {"vouchers":0}

Related: fluentforms-donor-discount.md — the companion donor-discount eligibility lookup (same key / CORS / rate limit).