tf-checkout-react 2.0.0-beta.26 → 2.0.0-beta.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2194 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'">
7
+ <title>Ticket Fairy React checkout guide</title>
8
+ <style>
9
+ :root { color-scheme: light; font-family: system-ui, -apple-system, sans-serif; }
10
+ body { color: #1d2032; background: #fff; line-height: 1.55; margin: 0; overflow-wrap: anywhere; }
11
+ main { max-width: 75rem; min-width: 0; margin: 0 auto; padding: 2rem 1.25rem 5rem; }
12
+ h1, h2, h3, h4 { line-height: 1.25; scroll-margin-top: 1rem; }
13
+ h1 { font-size: clamp(1.8rem, 3vw, 2.5rem); }
14
+ h2 { margin-top: 2.5rem; border-bottom: 1px solid #d4d8e4; padding-bottom: .35rem; }
15
+ a { color: #5020b8; text-decoration-thickness: .08em; }
16
+ a:focus-visible { outline: 3px solid #7a51e7; outline-offset: 3px; }
17
+ pre { box-sizing: border-box; max-width: 100%; overflow-x: auto; padding: 1rem; background: #f3f2f8; border-radius: .5rem; }
18
+ code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .9em; overflow-wrap: anywhere; }
19
+ pre code { font-size: .875rem; overflow-wrap: normal; white-space: pre; }
20
+ table { box-sizing: border-box; border-collapse: collapse; display: block; overflow-x: auto; max-width: 100%; }
21
+ th, td { border: 1px solid #d4d8e4; padding: .5rem .65rem; text-align: left; vertical-align: top; }
22
+ th { background: #f3f2f8; }
23
+ .skip { position: absolute; left: -10000px; }
24
+ .skip:focus { position: static; display: inline-block; padding: .5rem; }
25
+ @media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
26
+ </style>
27
+ </head>
28
+ <body>
29
+ <a class="skip" href="#main">Skip to content</a>
30
+ <main id="main">
31
+ <h1 id="tf-checkout-react">tf-checkout-react</h1>
32
+ <p>Ticket Fairy's React checkout for the web. Render the complete
33
+ checkout, compose its sections, or build your own UI against the
34
+ checkout engine. The package also exports authentication, confirmation,
35
+ rewards, ticket-management and account components, plus the shared API
36
+ and React Query hooks. Which paths a buyer can actually use depend on
37
+ the event, the deployed API, the buyer's session and the payment
38
+ provider.</p>
39
+ <p>This reference describes <strong>2.0.0-beta.27</strong>. It is a
40
+ prerelease with a different API from 1.x. Pin the version while
41
+ evaluating it. npm's <code>latest</code> and <code>beta</code> tags can
42
+ move independently and an unqualified install may select 1.x:</p>
43
+ <pre class="bash"><code>npm view tf-checkout-react dist-tags
44
+ npm install tf-checkout-react@2.0.0-beta.27 @tanstack/react-query react react-dom</code></pre>
45
+ <p>The <a
46
+ href="https://unpkg.com/tf-checkout-react@2.0.0-beta.27/docs/API.html">API
47
+ reference</a> is included as <code>docs/API.md</code> and
48
+ <code>docs/API.html</code> in this package. A <a
49
+ href="https://unpkg.com/tf-checkout-react@2.0.0-beta.27/docs/GUIDE.html">standalone
50
+ guide</a> is also available.</p>
51
+ <p>If the HTML has not reached the CDN yet, open the packaged
52
+ <code>docs/API.md</code> in a Markdown viewer or read the <a
53
+ href="https://cdn.jsdelivr.net/npm/tf-checkout-react@2.0.0-beta.27/docs/API.md">plain-text
54
+ API Markdown</a>. The full guide is also shown on this npm page.</p>
55
+ <h2 id="choose-a-checkout-layout">Choose a checkout layout</h2>
56
+ <table>
57
+ <thead>
58
+ <tr>
59
+ <th>Your goal</th>
60
+ <th>Start here</th>
61
+ <th>What the SDK renders</th>
62
+ </tr>
63
+ </thead>
64
+ <tbody>
65
+ <tr>
66
+ <td>Add a complete checkout to an event page</td>
67
+ <td><a href="#embeddedcheckout"><code>EmbeddedCheckout</code></a></td>
68
+ <td>A ready-made ticket or seat selection view followed by add-ons,
69
+ buyer details, waiver and payment when applicable.</td>
70
+ </tr>
71
+ <tr>
72
+ <td>Continue a cart created by an earlier flow</td>
73
+ <td><a
74
+ href="#resume-a-server-cart"><code>ResumedCheckout</code></a></td>
75
+ <td>Ready-made buyer details, waiver and payment for the current
76
+ session's existing cart.</td>
77
+ </tr>
78
+ <tr>
79
+ <td>Keep the checkout on one page and arrange the sections yourself</td>
80
+ <td><a href="#single-page-checkout">Single-page composition</a></td>
81
+ <td>Ticket selection, seats, add-ons, billing and payment sections in
82
+ the host's layout.</td>
83
+ </tr>
84
+ <tr>
85
+ <td>Show progressive steps or connect routes</td>
86
+ <td><a href="#step-by-step-checkout">Step-by-step composition</a></td>
87
+ <td>The same sections; your application controls what is visible and how
88
+ the buyer moves between steps.</td>
89
+ </tr>
90
+ <tr>
91
+ <td>Organize the form as an accordion</td>
92
+ <td><a href="#accordion-checkout">Accordion composition</a></td>
93
+ <td>Native HTML disclosure sections around the SDK's checkout
94
+ components.</td>
95
+ </tr>
96
+ <tr>
97
+ <td>Build your own checkout UI</td>
98
+ <td><a href="#headless-apis">Headless APIs</a></td>
99
+ <td>The shared engine, hooks and API; your application owns the UI and
100
+ navigation.</td>
101
+ </tr>
102
+ </tbody>
103
+ </table>
104
+ <p><code>EmbeddedCheckout</code> and <code>ResumedCheckout</code> are
105
+ the ready-made flows in this version. The 1.x <code>*Container</code>
106
+ components and named single-page/accordion examples are not drop-in 2.x
107
+ exports. The <a href="#migrating-from-1x">migration guide</a> shows how
108
+ to reproduce those layouts with the current components.</p>
109
+ <p><a href="#requirements">Requirements</a> · <a
110
+ href="#quick-start">Quick start</a> · <a
111
+ href="#configuration-and-sessions">Configure sessions</a> · <a
112
+ href="#embeddedcheckout">Ready-made checkout</a> · <a
113
+ href="#compose-sections">Custom layouts</a> · <a
114
+ href="#payments">Payments</a> · <a
115
+ href="#authentication">Authentication</a> · <a
116
+ href="#component-reference">Component reference</a> · <a
117
+ href="#styling-and-localization">Styling</a> · <a
118
+ href="#migrating-from-1x">Migration</a> · <a
119
+ href="#testing-and-troubleshooting">Troubleshooting</a></p>
120
+ <h2 id="requirements">Requirements</h2>
121
+ <ul>
122
+ <li>Node.js 18 or newer for tooling; a React browser application and a
123
+ bundler that handles JavaScript and CSS imports.</li>
124
+ <li>Peer dependencies: <code>react &gt;=18</code>,
125
+ <code>react-dom &gt;=18</code> and
126
+ <code>@tanstack/react-query &gt;=5</code>. Supply one compatible copy of
127
+ each in the host. Query-based components and hooks need the host's
128
+ <code>QueryClientProvider</code>.</li>
129
+ <li>A Ticket Fairy event ID and a <strong>public SDK client ID</strong>
130
+ registered for this integration, together with compatible API and
131
+ provider configuration. Ask your Ticket Fairy integration contact for
132
+ the appropriate environment and event setup. Never put a confidential
133
+ OAuth client secret in browser code.</li>
134
+ <li>The shared core and seat renderer are bundled; npm installs the
135
+ package's declared runtime dependencies. No separate shared-core install
136
+ is required. Browser and provider support must be tested for the actual
137
+ event and device.</li>
138
+ </ul>
139
+ <p>The package entry imports
140
+ <code>react-international-phone/style.css</code> and its own checkout
141
+ stylesheet. Your bundler must process both those imports and CSS
142
+ <code>@import</code> rules. The latter is also exported at
143
+ <code>tf-checkout-react/checkout.css</code> for build setups that need
144
+ an explicit import. Its <code>dist/styles</code> files and referenced
145
+ assets are part of the npm package.</p>
146
+ <h2 id="quick-start">Quick start</h2>
147
+ <p>This example puts the ready-made checkout on one event page. You need
148
+ a test event ID and the matching <strong>public</strong> SDK client ID.
149
+ Ask your Ticket Fairy integration contact for these values and the
150
+ appropriate environment.</p>
151
+ <ol type="1">
152
+ <li>Install the package and its peers using the command above.</li>
153
+ <li>Replace <code>EVENT_ID</code> and <code>PUBLIC_SDK_CLIENT_ID</code>
154
+ below. Configure the SDK once in your browser entry, before rendering
155
+ the checkout.</li>
156
+ <li>Mount <code>App</code> in your React application. The package entry
157
+ imports its CSS; the bundler must process CSS imports and their
158
+ assets.</li>
159
+ </ol>
160
+ <pre class="tsx"><code>import { useState } from &#39;react&#39;
161
+ import { QueryClient, QueryClientProvider } from &#39;@tanstack/react-query&#39;
162
+ import {
163
+ configureCheckout, EmbeddedCheckout, type PlaceOrderResult,
164
+ } from &#39;tf-checkout-react&#39;
165
+
166
+ configureCheckout({
167
+ env: &#39;STAG&#39;,
168
+ clientId: &#39;PUBLIC_SDK_CLIENT_ID&#39;,
169
+ clientSecret: &#39;&#39;,
170
+ cookieAuth: true,
171
+ })
172
+
173
+ const queryClient = new QueryClient()
174
+
175
+ export function App() {
176
+ const [order, setOrder] = useState&lt;PlaceOrderResult | null&gt;(null)
177
+
178
+ return (
179
+ &lt;QueryClientProvider client={queryClient}&gt;
180
+ {order ? (
181
+ &lt;section role=&quot;status&quot;&gt;
182
+ &lt;h1&gt;Checking your order&lt;/h1&gt;
183
+ &lt;p&gt;Check your order status before making another purchase.&lt;/p&gt;
184
+ {order.pending &amp;&amp; &lt;p&gt;Your payment is pending.&lt;/p&gt;}
185
+ {order.needIdVerification &amp;&amp; &lt;p&gt;Identity verification may be required.&lt;/p&gt;}
186
+ &lt;/section&gt;
187
+ ) : (
188
+ &lt;EmbeddedCheckout
189
+ eventId=&quot;EVENT_ID&quot;
190
+ confirmationMode=&quot;redirect&quot;
191
+ onComplete={setOrder}
192
+ /&gt;
193
+ )}
194
+ &lt;/QueryClientProvider&gt;
195
+ )
196
+ }</code></pre>
197
+ <p>The buyer first chooses tickets or seats. After reservation, the
198
+ checkout shows applicable add-ons, buyer details, waiver and payment.
199
+ <code>onComplete</code> hands the result to the host; the example
200
+ displays a neutral status instead of claiming that tickets are ready.
201
+ Connect that screen to <strong>your backend's authoritative order
202
+ status</strong> using <code>order.orderHash</code>, handle any required
203
+ ID verification and pending voucher, and provide support if the status
204
+ cannot be established. The callback alone is not proof of settlement or
205
+ ticket issuance.</p>
206
+ <p>Use <code>env: 'PROD'</code> with the matching production public
207
+ client ID when your integration is ready. This beta's stock payment UI
208
+ can ask a buyer to retry an unconfirmed payment; that wording does not
209
+ establish that retrying is safe. See <a href="#payments">Payments</a>
210
+ before using the stock flow in production.</p>
211
+ <h2 id="configuration-and-sessions">Configuration and sessions</h2>
212
+ <p><code>configureCheckout(config: TtfConfig)</code> wraps the shared
213
+ <code>configure</code> function, adds a browser
214
+ <code>localStorage</code> adapter and a browser checkout-auth popup, and
215
+ then applies your supplied options. Call it once at client startup,
216
+ before any SDK hook or <code>ttf</code> call. Calling it again replaces
217
+ the global configuration and can retire existing session state. Do not
218
+ reconfigure from a component render.</p>
219
+ <table>
220
+ <thead>
221
+ <tr>
222
+ <th>Option</th>
223
+ <th>Meaning</th>
224
+ </tr>
225
+ </thead>
226
+ <tbody>
227
+ <tr>
228
+ <td><code>clientId</code>, <code>clientSecret</code></td>
229
+ <td>Required strings. For a public browser integration use its
230
+ registered SDK client ID and an empty <code>clientSecret</code>; a
231
+ confidential secret belongs on a trusted server only.</td>
232
+ </tr>
233
+ <tr>
234
+ <td><code>env</code></td>
235
+ <td><code>PROD</code> (default), <code>STAG</code>, or <code>DEV</code>,
236
+ selecting <code>https://www.ticketfairy.com</code>,
237
+ <code>https://test.ticketfairy.com</code>, or
238
+ <code>https://sandbox.ticketfairy.com</code>.</td>
239
+ </tr>
240
+ <tr>
241
+ <td><code>baseUrl</code></td>
242
+ <td>Explicit host overrides <code>env</code>, including <code>''</code>
243
+ for same origin behind a proxy. A trailing <code>/api</code> is
244
+ normalized; the SDK appends <code>/api</code> for API calls.</td>
245
+ </tr>
246
+ <tr>
247
+ <td><code>sourceOrigin</code></td>
248
+ <td>Optional value of the <code>X-Source-Origin</code> request header
249
+ when required for your integration.</td>
250
+ </tr>
251
+ <tr>
252
+ <td><code>storage</code></td>
253
+ <td>Synchronous <code>StorageAdapter</code> overriding the browser
254
+ default. <code>getItem(key)</code>, <code>setItem(key, value)</code>,
255
+ and <code>removeItem(key)</code> are required; optional
256
+ <code>flush()</code> returns <code>Promise&lt;void&gt;</code> for a
257
+ synchronous mirror with asynchronous persistence.</td>
258
+ </tr>
259
+ <tr>
260
+ <td><code>cookieAuth</code></td>
261
+ <td>Enables the header-backed Ticket Fairy session path. Use when the
262
+ integration is set up for a shared session or anonymous cookie cart;
263
+ browser cookie and CORS policies still apply.</td>
264
+ </tr>
265
+ <tr>
266
+ <td><code>withCredentials</code></td>
267
+ <td>Controls automatic HTTP cookie handling; defaults to true in
268
+ browsers. Cross-origin cookies also require correct server CORS/cookie
269
+ configuration and browser permission.</td>
270
+ </tr>
271
+ <tr>
272
+ <td><code>auth</code></td>
273
+ <td>Function returning additional headers or <code>undefined</code>;
274
+ called for each request. Headers normally merge after SDK headers, but
275
+ protected requests enforce session isolation: guest bootstrap strips
276
+ sensitive buyer/session headers after that merge. Use only credentials
277
+ appropriate to the browser.</td>
278
+ </tr>
279
+ <tr>
280
+ <td><code>accountAuth</code></td>
281
+ <td>Opts into first-party account auth routes; default is off. Requires
282
+ the corresponding backend journey and account authority.</td>
283
+ </tr>
284
+ <tr>
285
+ <td><code>sdkCheckoutPhoneAuth</code></td>
286
+ <td>Opts into the first-party phone checkout journey only when its
287
+ matching backend is deployed.</td>
288
+ </tr>
289
+ <tr>
290
+ <td><code>browserAuth</code>, <code>sdkCheckoutBrowserAuth</code></td>
291
+ <td>Browser authorization ports for specialized integrations. The web
292
+ wrapper supplies the checkout popup port when supported; an explicit
293
+ config value overrides it.</td>
294
+ </tr>
295
+ </tbody>
296
+ </table>
297
+ <p><code>localStorageAdapter</code> no-ops outside a browser;
298
+ <code>createMemoryStorage()</code> is an exported non-persistent adapter
299
+ useful for tests. Browser local storage is accessible to scripts in the
300
+ origin. Protect against XSS, avoid logging tokens, order links or
301
+ personal information, and pick an adapter and session lifetime
302
+ appropriate to your application. Logout/session changes need to be
303
+ coordinated with the host: stale UI or a cached profile is not proof of
304
+ authorization.</p>
305
+ <p>The public checkout sign-in path establishes an event-scoped buyer
306
+ identity. It does <strong>not</strong> grant a full account session for
307
+ private tickets or account preferences. A full account experience needs
308
+ the corresponding authorized session and backend routes. Two-factor and
309
+ other proof steps must finish before an authentication flow is complete.
310
+ Do not treat a checkout profile callback as permission to read private
311
+ account data.</p>
312
+ <h3 id="server-rendering">Server rendering</h3>
313
+ <p>The default storage adapter is server-safe, and the checkout hook
314
+ supplies an idle server snapshot. Payment elements, popups, DOM effects
315
+ and browser storage need a browser. In SSR frameworks, mount the
316
+ interactive checkout in a client component; do not run a browser
317
+ checkout on the server or share a configured module/session singleton
318
+ across server requests. Configure the browser before rendering that
319
+ client tree. Confirm that the framework processes the package's CSS
320
+ imports. Static import/SSR compatibility of a particular framework and
321
+ all third-party dependencies should be tested in that framework.</p>
322
+ <h2 id="embeddedcheckout">EmbeddedCheckout</h2>
323
+ <p><code>EmbeddedCheckout</code> owns a <code>CheckoutProvider</code>
324
+ and presents ticket/bundle or seat selection, add-ons, billing, waivers,
325
+ payment and inline completion as the flow requires. It must be under
326
+ <code>QueryClientProvider</code>.</p>
327
+ <p>Only <code>eventId</code> is required. Callbacks and options are
328
+ optional. The component owns its checkout provider; do not wrap it in
329
+ another <code>CheckoutProvider</code> to control its internal steps. The
330
+ host still supplies <code>QueryClientProvider</code>.</p>
331
+ <h3 id="what-the-buyer-sees">What the buyer sees</h3>
332
+ <ol type="1">
333
+ <li><strong>Tickets:</strong> the event's catalog, quantities,
334
+ applicable codes and any organizer-configured waiting list. Seated
335
+ events can open a seat map.</li>
336
+ <li><strong>Checkout:</strong> a selection summary and the applicable
337
+ add-ons, buyer/holder details, waiver and payment. The reservation timer
338
+ is displayed when available.</li>
339
+ <li><strong>Completion:</strong> <code>inline</code> shows the SDK's
340
+ confirmation view; <code>redirect</code> calls <code>onComplete</code>
341
+ and leaves the host to show the next screen. The quick start uses
342
+ <code>redirect</code> so the host can check order status before
343
+ presenting a receipt.</li>
344
+ </ol>
345
+ <p><code>initialView="seats"</code> opens the seat-selection view first
346
+ for an applicable seated event. <code>onViewChange</code> reports
347
+ <code>tickets</code>, <code>seats</code> or <code>checkout</code>; it
348
+ does not turn the component into a controlled router. For custom paths
349
+ or step arrangements, use <a href="#compose-sections">section
350
+ composition</a>.</p>
351
+ <p>When choosing <code>confirmationMode="redirect"</code>, provide
352
+ <code>onComplete</code> to receive the result and navigate to your
353
+ status page. Although the prop is optional in the type, without that
354
+ handoff the checkout remains mounted and no host status page is
355
+ reached.</p>
356
+ <h3 id="options-and-callbacks">Options and callbacks</h3>
357
+ <table>
358
+ <thead>
359
+ <tr>
360
+ <th>Prop</th>
361
+ <th>Type / default</th>
362
+ <th>Description</th>
363
+ </tr>
364
+ </thead>
365
+ <tbody>
366
+ <tr>
367
+ <td><code>eventId</code></td>
368
+ <td><code>string</code></td>
369
+ <td>Event to sell.</td>
370
+ </tr>
371
+ <tr>
372
+ <td><code>onComplete</code></td>
373
+ <td><code>(order: PlaceOrderResult) =&gt; void</code></td>
374
+ <td>Result of placement, including an asynchronously pending
375
+ payment.</td>
376
+ </tr>
377
+ <tr>
378
+ <td><code>confirmationMode</code></td>
379
+ <td><code>'inline' | 'redirect'</code>; <code>inline</code></td>
380
+ <td>Inline renders verification/confirmation. Redirect shows a
381
+ transition; use <code>onComplete</code> to navigate.</td>
382
+ </tr>
383
+ <tr>
384
+ <td><code>initialView</code></td>
385
+ <td><code>'tickets' | 'seats'</code>; <code>tickets</code></td>
386
+ <td>Initial selection view.</td>
387
+ </tr>
388
+ <tr>
389
+ <td><code>onViewChange</code></td>
390
+ <td><code>(view: 'tickets' | 'seats' | 'checkout') =&gt; void</code></td>
391
+ <td>Reports the visible flow view.</td>
392
+ </tr>
393
+ <tr>
394
+ <td><code>autoScroll</code></td>
395
+ <td><code>boolean</code>; <code>true</code></td>
396
+ <td>Scroll to buyer details after reservation.</td>
397
+ </tr>
398
+ <tr>
399
+ <td><code>requireEmailConfirmation</code></td>
400
+ <td><code>boolean</code>; <code>true</code></td>
401
+ <td>Require guests to repeat their email.</td>
402
+ </tr>
403
+ <tr>
404
+ <td><code>collectTicketHolders</code></td>
405
+ <td><code>boolean</code>; <code>true</code></td>
406
+ <td>Collect one named holder per ticket.</td>
407
+ </tr>
408
+ <tr>
409
+ <td><code>collectHolderContact</code></td>
410
+ <td><code>boolean</code>; <code>true</code></td>
411
+ <td>Collect holder contact details when holders are collected.</td>
412
+ </tr>
413
+ <tr>
414
+ <td><code>skipBillingWhenProfileComplete</code></td>
415
+ <td><code>boolean</code>; <code>false</code></td>
416
+ <td>Skip billing only for an eligible complete signed-in profile and
417
+ compatible holder/custom-field requirements. Payment is not skipped. See
418
+ the privacy and opt-in limitations below.</td>
419
+ </tr>
420
+ <tr>
421
+ <td><code>onLogin</code></td>
422
+ <td><code>(email?: string) =&gt; void</code></td>
423
+ <td>Opens host login instead of the built-in modal; the email may be an
424
+ existing-account match.</td>
425
+ </tr>
426
+ <tr>
427
+ <td><code>auth</code></td>
428
+ <td><code>false | EmbeddedCheckoutAuthOptions</code></td>
429
+ <td>Disable or configure the built-in modal; ignored when
430
+ <code>onLogin</code> is supplied.</td>
431
+ </tr>
432
+ <tr>
433
+ <td><code>privacyPolicy</code></td>
434
+ <td><code>CheckoutPrivacyPolicy</code></td>
435
+ <td><code>{ url, brandName, linkLabel? }</code>; adds the host's
436
+ required privacy acknowledgement.</td>
437
+ </tr>
438
+ <tr>
439
+ <td><code>additionalConditions</code></td>
440
+ <td><code>EventCondition[]</code></td>
441
+ <td>Host acknowledgements
442
+ <code>{ id, name, content, isRequired }</code>; required ones gate
443
+ payment. Content is rendered as HTML: supply trusted or sanitized
444
+ HTML.</td>
445
+ </tr>
446
+ <tr>
447
+ <td><code>ttfOptInLabel</code>, <code>brandOptInLabel</code></td>
448
+ <td><code>string</code></td>
449
+ <td>Override the Ticket Fairy opt-in label or add a brand opt-in. The
450
+ privacy-policy option changes the Ticket Fairy control as described
451
+ below.</td>
452
+ </tr>
453
+ <tr>
454
+ <td><code>initialPromoCode</code>, <code>referrer</code>,
455
+ <code>readAttributionFromUrl</code></td>
456
+ <td><code>string</code>, <code>string | number</code>,
457
+ <code>boolean</code></td>
458
+ <td>Apply a code and attribution; URL reading defaults to
459
+ <code>true</code>.</td>
460
+ </tr>
461
+ <tr>
462
+ <td><code>showTestCardHint</code></td>
463
+ <td><code>boolean</code>; <code>false</code></td>
464
+ <td>Demo-only sandbox card copy.</td>
465
+ </tr>
466
+ <tr>
467
+ <td><code>theme</code>, <code>locale</code>, <code>messages</code>,
468
+ <code>className</code></td>
469
+ <td><code>CheckoutTheme</code>, <code>LocaleCode</code>,
470
+ <code>Partial&lt;Messages&gt;</code>, <code>string</code></td>
471
+ <td>Appearance, copy and root class.</td>
472
+ </tr>
473
+ </tbody>
474
+ </table>
475
+ <p><code>EmbeddedCheckoutAuthOptions</code> accepts
476
+ <code>allowRegistration</code>, <code>allowPasswordReset</code>,
477
+ <code>requireRegistrationAddress</code>, <code>logoUrl</code>,
478
+ <code>onCheckoutAuthenticated(profile: CheckoutBuyerProfile)</code> and
479
+ <code>onAuthenticated(profile: TfProfile)</code>. The two callbacks
480
+ represent different session authorities; use the one appropriate to your
481
+ configured journey. <code>requireRegistrationAddress={false}</code> does
482
+ not remove the address requirement for the public checkout registration
483
+ or account-completion journey; those paths force it on in this
484
+ version.</p>
485
+ <h3 id="example-brand-the-ready-made-checkout">Example: brand the
486
+ ready-made checkout</h3>
487
+ <p>Use the same <code>QueryClientProvider</code> and one-time
488
+ configuration as the quick start. Here <code>onViewChange</code> can
489
+ update surrounding page content; <code>onComplete</code> passes the
490
+ order result to the host's status screen.</p>
491
+ <pre class="tsx"><code>import { useState } from &#39;react&#39;
492
+ import { EmbeddedCheckout, type PlaceOrderResult } from &#39;tf-checkout-react&#39;
493
+
494
+ export function BrandedCheckout() {
495
+ const [order, setOrder] = useState&lt;PlaceOrderResult | null&gt;(null)
496
+ const [view, setView] = useState(&#39;tickets&#39;)
497
+
498
+ if (order) return &lt;p role=&quot;status&quot;&gt;Checking your order status…&lt;/p&gt;
499
+
500
+ return (
501
+ &lt;main&gt;
502
+ &lt;p&gt;Checkout step: {view}&lt;/p&gt;
503
+ &lt;EmbeddedCheckout
504
+ eventId=&quot;EVENT_ID&quot;
505
+ confirmationMode=&quot;redirect&quot;
506
+ onComplete={setOrder}
507
+ onViewChange={setView}
508
+ initialPromoCode=&quot;WELCOME&quot;
509
+ referrer=&quot;REFERRER_ID&quot;
510
+ readAttributionFromUrl={false}
511
+ locale=&quot;en-US&quot;
512
+ messages={{ &#39;tickets.getTickets&#39;: &#39;Continue to checkout&#39; }}
513
+ theme={{ colorScheme: &#39;light&#39;, accent: &#39;#6b2bd9&#39;, radiusCard: &#39;16px&#39; }}
514
+ className=&quot;festival-checkout&quot;
515
+ /&gt;
516
+ &lt;/main&gt;
517
+ )
518
+ }</code></pre>
519
+ <p>Use a promo or referral only when it belongs to this visit. Remove
520
+ those props when they do not apply. By default the component also reads
521
+ <code>promo</code> / <code>promo_code</code> and <code>ttf_r</code> /
522
+ <code>referrer_id</code> from the URL. The example disables that
523
+ behavior so the host controls attribution. <code>initialPromoCode</code>
524
+ is applied once when the catalog mounts. It is not a guarantee that a
525
+ code is valid. <code>theme</code> changes SDK design tokens,
526
+ <code>className</code> lets your stylesheet target this instance, and
527
+ <code>messages</code> overrides individual SDK copy keys.
528
+ <code>locale</code> and <code>messages</code> do not automatically
529
+ translate the event's own content or an external payment-provider page.
530
+ See <a href="#styling-and-localization">Styling and localization</a> for
531
+ the available theme tokens and locales.</p>
532
+ <h3 id="example-connect-host-navigation-and-sign-in">Example: connect
533
+ host navigation and sign-in</h3>
534
+ <p>Pass callbacks when the surrounding application owns these actions.
535
+ For example, <code>openSignIn</code> can open your sign-in UI, and
536
+ <code>onOrder</code> can hand the result to your order-status screen.
537
+ <code>onViewChange</code> is a notification, not a way to force the
538
+ checkout to a particular step.</p>
539
+ <pre class="tsx"><code>import { EmbeddedCheckout, type PlaceOrderResult } from &#39;tf-checkout-react&#39;
540
+
541
+ type View = &#39;tickets&#39; | &#39;seats&#39; | &#39;checkout&#39;
542
+
543
+ export function HostCheckout(props: {
544
+ eventId: string
545
+ openSignIn: (email?: string) =&gt; void
546
+ showOrderStatus: (order: PlaceOrderResult) =&gt; void
547
+ reportView: (view: View) =&gt; void
548
+ }) {
549
+ return (
550
+ &lt;EmbeddedCheckout
551
+ eventId={props.eventId}
552
+ onLogin={props.openSignIn}
553
+ onViewChange={props.reportView}
554
+ confirmationMode=&quot;redirect&quot;
555
+ onComplete={props.showOrderStatus}
556
+ /&gt;
557
+ )
558
+ }</code></pre>
559
+ <p>The email passed to <code>openSignIn</code> can be absent. Supplying
560
+ <code>onLogin</code> replaces the built-in login modal; your host must
561
+ complete the appropriate sign-in journey. An event-scoped checkout
562
+ identity is not automatically a full account session.
563
+ <code>showOrderStatus</code> must check the order and provider rather
564
+ than treating the callback as a paid receipt.</p>
565
+ <h3 id="resume-a-server-cart">Resume a server cart</h3>
566
+ <p><code>ResumedCheckout</code> is a ready-made layout for a cart that
567
+ <strong>already exists in the current session</strong>, such as one
568
+ created by a preceding resale flow. It starts with buyer details and
569
+ payment; it does not show ticket selection, create the cart, or accept a
570
+ cart ID. Its <code>confirmationMode</code> defaults to
571
+ <code>redirect</code>. Provide <code>onComplete</code> for the
572
+ redirect/status handoff: without it the successful flow remains on its
573
+ loading transition. Alternatively select <code>inline</code> and account
574
+ for the confirmation and verification-copy limitations below.</p>
575
+ <pre class="tsx"><code>import { useState } from &#39;react&#39;
576
+ import { ResumedCheckout, type PlaceOrderResult } from &#39;tf-checkout-react&#39;
577
+
578
+ // Mount only after your preceding flow created a cart in this session.
579
+ export function ResumePage() {
580
+ const [order, setOrder] = useState&lt;PlaceOrderResult | null&gt;(null)
581
+ if (order) return &lt;p role=&quot;status&quot;&gt;Checking your order status…&lt;/p&gt;
582
+
583
+ return (
584
+ &lt;ResumedCheckout
585
+ eventId=&quot;EVENT_ID&quot;
586
+ isFromResale
587
+ confirmationMode=&quot;redirect&quot;
588
+ onComplete={setOrder}
589
+ /&gt;
590
+ )
591
+ }</code></pre>
592
+ <p>Wrap this page in the same <code>QueryClientProvider</code> as the
593
+ quick start. Set <code>isFromResale</code> only for the resale path.
594
+ Check the result with your backend, including any verification or
595
+ pending-payment requirements. If the preceding flow did not create a
596
+ cart, or the session changed, return the buyer to that flow instead of
597
+ assuming a cart can be resumed.</p>
598
+ <p>Props are <code>eventId</code> (required), <code>isFromResale</code>
599
+ (default <code>false</code>), <code>onComplete</code>,
600
+ <code>confirmationMode</code>, <code>requireEmailConfirmation</code>,
601
+ <code>collectTicketHolders</code>, <code>collectHolderContact</code>
602
+ (each default <code>true</code>), <code>privacyPolicy</code>,
603
+ <code>brandOptInLabel</code>, <code>additionalConditions</code>,
604
+ <code>theme</code> and <code>className</code>. Unlike
605
+ <code>EmbeddedCheckout</code>, this component does not accept
606
+ <code>locale</code>, <code>messages</code>, <code>auth</code> or
607
+ <code>onLogin</code> props in this version.</p>
608
+ <h2 id="compose-sections">Compose sections</h2>
609
+ <p>Use sections when the ready-made flow does not fit your page. Put all
610
+ sections for one checkout inside a single <code>CheckoutProvider</code>,
611
+ under the host's <code>QueryClientProvider</code>. The provider shares
612
+ one checkout instance with its children. The default store is app-wide:
613
+ mounting two flows does not create two independent carts. Configure the
614
+ SDK once, before mounting the provider.</p>
615
+ <p>The examples below assume the quick start's
616
+ <code>configureCheckout</code> and <code>QueryClientProvider</code>
617
+ setup. They demonstrate page layout and section wiring; your host still
618
+ needs to implement order-status reconciliation, expiry and recovery for
619
+ its event and enabled payment methods.</p>
620
+ <p>These are wiring recipes, not complete buyer navigation. Each
621
+ includes a return from the seat view and keeps <code>Tickets</code>
622
+ mounted while switching views. The host still needs to implement Edit
623
+ and Back from checkout (including payment to billing), preserve entered
624
+ details, handle seat holds and cart expiry, and guard event/session
625
+ changes and in-flight or retained payments. Use
626
+ <code>EmbeddedCheckout</code> for its built-in Back and guarded Edit
627
+ behavior. The seat-view Back button only changes views: it does not
628
+ itself release reserved seats or cancel an already-started reservation
629
+ or cart priming. Coordinate any in-flight work and the hold's expiry or
630
+ release under your deployed backend contract before permitting a
631
+ conflicting selection.</p>
632
+ <h3 id="single-page-checkout">Single-page checkout</h3>
633
+ <p>This layout keeps the buyer on one browser page. Selecting tickets or
634
+ seats reveals a single combined form with add-ons, buyer details, waiver
635
+ and payment. The host supplies the status view after
636
+ <code>onComplete</code>.</p>
637
+ <pre class="tsx"><code>import { useState } from &#39;react&#39;
638
+ import {
639
+ AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
640
+ Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
641
+ } from &#39;tf-checkout-react&#39;
642
+
643
+ function SinglePageContents({ eventId }: { eventId: string }) {
644
+ const checkout = useCheckoutContext()
645
+ const [view, setView] = useState&lt;&#39;tickets&#39; | &#39;seats&#39; | &#39;checkout&#39;&gt;(&#39;tickets&#39;)
646
+ const [order, setOrder] = useState&lt;PlaceOrderResult | null&gt;(null)
647
+
648
+ if (order) return &lt;p role=&quot;status&quot;&gt;Checking your order status…&lt;/p&gt;
649
+
650
+ return (
651
+ &lt;main&gt;
652
+ &lt;div hidden={view !== &#39;tickets&#39;}&gt;
653
+ &lt;Tickets
654
+ eventId={eventId}
655
+ onContinue={() =&gt; setView(&#39;checkout&#39;)}
656
+ onSelectSeats={() =&gt; setView(&#39;seats&#39;)}
657
+ /&gt;
658
+ &lt;/div&gt;
659
+ {view === &#39;seats&#39; &amp;&amp; (
660
+ &lt;&gt;
661
+ &lt;button type=&quot;button&quot; onClick={() =&gt; setView(&#39;tickets&#39;)}&gt;Back to tickets&lt;/button&gt;
662
+ &lt;SeatMap eventId={eventId} onContinue={() =&gt; setView(&#39;checkout&#39;)} /&gt;
663
+ &lt;/&gt;
664
+ )}
665
+ {view === &#39;checkout&#39; &amp;&amp; (
666
+ &lt;&gt;
667
+ &lt;TimerBanner seconds={checkout.secondsLeft} /&gt;
668
+ &lt;AddOns eventId={eventId} /&gt;
669
+ &lt;BillingInfo
670
+ eventId={eventId}
671
+ requireEmailConfirmation
672
+ collectTicketHolders
673
+ collectHolderContact
674
+ /&gt;
675
+ &lt;WaiverSigning eventId={eventId} /&gt;
676
+ &lt;Payment
677
+ eventId={eventId}
678
+ requireEmailConfirmation
679
+ collectTicketHolders
680
+ requireHolderContact
681
+ onComplete={setOrder}
682
+ /&gt;
683
+ &lt;/&gt;
684
+ )}
685
+ &lt;/main&gt;
686
+ )
687
+ }
688
+
689
+ export function SinglePageCheckout({ eventId }: { eventId: string }) {
690
+ return (
691
+ &lt;CheckoutProvider theme={{ colorScheme: &#39;light&#39;, accent: &#39;#2458d3&#39; }}&gt;
692
+ &lt;SinglePageContents eventId={eventId} /&gt;
693
+ &lt;/CheckoutProvider&gt;
694
+ )
695
+ }</code></pre>
696
+ <p><code>Tickets.onContinue</code> fires after the cart is primed.
697
+ <code>onSelectSeats</code> opens the seat view; without it the
698
+ seat-selection button is hidden in a composed <code>Tickets</code>
699
+ section. <code>SeatMap.onContinue</code> runs after seats are added and
700
+ priced. Without an <code>onContinue</code> prop,
701
+ <code>BillingInfo</code> and <code>AddOns</code> use their combined-form
702
+ behavior instead of showing a separate Continue button. Match the
703
+ billing and payment email/holder settings, as shown. <code>AddOns</code>
704
+ renders nothing when the event has no applicable add-ons; do not skip a
705
+ required one.</p>
706
+ <h3 id="step-by-step-checkout">Step-by-step checkout</h3>
707
+ <p>To make billing and payment separate steps, give
708
+ <code>BillingInfo</code> an <code>onContinue</code> callback. It then
709
+ validates and saves the buyer details before moving on. This example
710
+ keeps the checkout provider mounted for the whole flow; it does not
711
+ change URLs or assume a browser refresh can resume the in-memory
712
+ layout.</p>
713
+ <pre class="tsx"><code>import { useState } from &#39;react&#39;
714
+ import {
715
+ AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
716
+ Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
717
+ } from &#39;tf-checkout-react&#39;
718
+
719
+ type Step = &#39;tickets&#39; | &#39;seats&#39; | &#39;details&#39; | &#39;payment&#39;
720
+
721
+ function StepContents({ eventId }: { eventId: string }) {
722
+ const checkout = useCheckoutContext()
723
+ const [step, setStep] = useState&lt;Step&gt;(&#39;tickets&#39;)
724
+ const [order, setOrder] = useState&lt;PlaceOrderResult | null&gt;(null)
725
+
726
+ if (order) return &lt;p role=&quot;status&quot;&gt;Checking your order status…&lt;/p&gt;
727
+
728
+ return (
729
+ &lt;main&gt;
730
+ {(step === &#39;details&#39; || step === &#39;payment&#39;) &amp;&amp; (
731
+ &lt;TimerBanner seconds={checkout.secondsLeft} /&gt;
732
+ )}
733
+ &lt;div hidden={step !== &#39;tickets&#39;}&gt;
734
+ &lt;Tickets
735
+ eventId={eventId}
736
+ onContinue={() =&gt; setStep(&#39;details&#39;)}
737
+ onSelectSeats={() =&gt; setStep(&#39;seats&#39;)}
738
+ /&gt;
739
+ &lt;/div&gt;
740
+ {step === &#39;seats&#39; &amp;&amp; (
741
+ &lt;&gt;
742
+ &lt;button type=&quot;button&quot; onClick={() =&gt; setStep(&#39;tickets&#39;)}&gt;Back to tickets&lt;/button&gt;
743
+ &lt;SeatMap eventId={eventId} onContinue={() =&gt; setStep(&#39;details&#39;)} /&gt;
744
+ &lt;/&gt;
745
+ )}
746
+ {step === &#39;details&#39; &amp;&amp; (
747
+ &lt;BillingInfo
748
+ eventId={eventId}
749
+ requireEmailConfirmation
750
+ collectTicketHolders
751
+ collectHolderContact
752
+ onContinue={() =&gt; setStep(&#39;payment&#39;)}
753
+ /&gt;
754
+ )}
755
+ {step === &#39;payment&#39; &amp;&amp; (
756
+ &lt;&gt;
757
+ &lt;AddOns eventId={eventId} /&gt;
758
+ &lt;WaiverSigning eventId={eventId} /&gt;
759
+ &lt;Payment
760
+ eventId={eventId}
761
+ requireEmailConfirmation
762
+ collectTicketHolders
763
+ requireHolderContact
764
+ onComplete={setOrder}
765
+ /&gt;
766
+ &lt;/&gt;
767
+ )}
768
+ &lt;/main&gt;
769
+ )
770
+ }
771
+
772
+ export function StepCheckout({ eventId }: { eventId: string }) {
773
+ return &lt;CheckoutProvider&gt;&lt;StepContents eventId={eventId} /&gt;&lt;/CheckoutProvider&gt;
774
+ }</code></pre>
775
+ <p>For separate routes, keep the provider above the routed pages and
776
+ connect the callbacks to your router. A full page reload is a different
777
+ session/navigation problem: <code>ResumedCheckout</code> can attach only
778
+ to an existing cart in the current session, and the old 1.x localStorage
779
+ state is not a migration format. Handle expired reservations, browser
780
+ Back, buyer changes and unconfirmed payments before enabling navigation
781
+ or a new purchase. Do not unmount or reset an in-flight payment merely
782
+ to move between steps.</p>
783
+ <p>The step example is a progressive layout: the next step appears after
784
+ a successful callback. A router can replace <code>setStep</code>, but
785
+ the SDK does not supply a route-based checkout or implement your browser
786
+ Back handling. Do not assume that a successful TypeScript build verifies
787
+ route, refresh or payment behavior; test those flows with your own
788
+ backend and providers.</p>
789
+ <h3 id="accordion-checkout">Accordion checkout</h3>
790
+ <p>The SDK does not export a named accordion component. This host-built
791
+ layout uses native HTML disclosures to group the same SDK sections. The
792
+ payment field stays outside the disclosures so it remains visible while
793
+ the buyer pays. It uses the configuration and
794
+ <code>QueryClientProvider</code> from the quick start.</p>
795
+ <pre class="tsx"><code>import { useState } from &#39;react&#39;
796
+ import {
797
+ AddOns, BillingInfo, CheckoutProvider, Payment, SeatMap,
798
+ Tickets, TimerBanner, WaiverSigning, useCheckoutContext, type PlaceOrderResult,
799
+ } from &#39;tf-checkout-react&#39;
800
+
801
+ function AccordionContents({ eventId }: { eventId: string }) {
802
+ const checkout = useCheckoutContext()
803
+ const [view, setView] = useState&lt;&#39;tickets&#39; | &#39;seats&#39; | &#39;checkout&#39;&gt;(&#39;tickets&#39;)
804
+ const [order, setOrder] = useState&lt;PlaceOrderResult | null&gt;(null)
805
+
806
+ if (order) return &lt;p role=&quot;status&quot;&gt;Checking your order status…&lt;/p&gt;
807
+
808
+ return (
809
+ &lt;main&gt;
810
+ &lt;div hidden={view !== &#39;tickets&#39;}&gt;
811
+ &lt;Tickets
812
+ eventId={eventId}
813
+ onContinue={() =&gt; setView(&#39;checkout&#39;)}
814
+ onSelectSeats={() =&gt; setView(&#39;seats&#39;)}
815
+ /&gt;
816
+ &lt;/div&gt;
817
+ {view === &#39;seats&#39; &amp;&amp; (
818
+ &lt;&gt;
819
+ &lt;button type=&quot;button&quot; onClick={() =&gt; setView(&#39;tickets&#39;)}&gt;Back to tickets&lt;/button&gt;
820
+ &lt;SeatMap eventId={eventId} onContinue={() =&gt; setView(&#39;checkout&#39;)} /&gt;
821
+ &lt;/&gt;
822
+ )}
823
+ {view === &#39;checkout&#39; &amp;&amp; (
824
+ &lt;&gt;
825
+ &lt;TimerBanner seconds={checkout.secondsLeft} /&gt;
826
+ &lt;details open&gt;
827
+ &lt;summary&gt;Add-ons&lt;/summary&gt;
828
+ &lt;AddOns eventId={eventId} /&gt;
829
+ &lt;/details&gt;
830
+ &lt;details open&gt;
831
+ &lt;summary&gt;Buyer and ticket holders&lt;/summary&gt;
832
+ &lt;BillingInfo
833
+ eventId={eventId}
834
+ requireEmailConfirmation
835
+ collectTicketHolders
836
+ collectHolderContact
837
+ /&gt;
838
+ &lt;/details&gt;
839
+ &lt;details open&gt;
840
+ &lt;summary&gt;Waiver&lt;/summary&gt;
841
+ &lt;WaiverSigning eventId={eventId} /&gt;
842
+ &lt;/details&gt;
843
+ &lt;Payment
844
+ eventId={eventId}
845
+ requireEmailConfirmation
846
+ collectTicketHolders
847
+ requireHolderContact
848
+ onComplete={setOrder}
849
+ /&gt;
850
+ &lt;/&gt;
851
+ )}
852
+ &lt;/main&gt;
853
+ )
854
+ }
855
+
856
+ export function AccordionCheckout({ eventId }: { eventId: string }) {
857
+ return &lt;CheckoutProvider&gt;&lt;AccordionContents eventId={eventId} /&gt;&lt;/CheckoutProvider&gt;
858
+ }</code></pre>
859
+ <p>The buyer reserves tickets or seats, then can open or close the form
860
+ groups. Closing a <code>&lt;details&gt;</code> element hides its
861
+ contents without unmounting them. In a production accordion, open the
862
+ relevant group when validation needs the buyer's attention, and make
863
+ sure required add-ons, fields and waivers cannot be missed. Do not hide
864
+ or replace the active payment field during a payment attempt. As with
865
+ the other examples, replace the status placeholder with your own
866
+ verified order-status and support flow.</p>
867
+ <p><code>CheckoutProvider</code> props are <code>children</code>
868
+ (required), <code>value?: UseCheckout</code>,
869
+ <code>theme?: CheckoutTheme</code>, <code>locale?: LocaleCode</code>,
870
+ <code>messages?: Partial&lt;Messages&gt;</code>, and
871
+ <code>className?: string</code>. Use <code>useCheckoutContext()</code>
872
+ inside the provider to read the current checkout and
873
+ <code>useCheckoutValidation()</code> to coordinate validation between
874
+ sections. The provider's default checkout includes the installment
875
+ picker. If supplying your own <code>value</code>, wire any custom
876
+ payment ports you need when creating that checkout.</p>
877
+ <h2 id="checkout-lifecycle">Checkout lifecycle</h2>
878
+ <ol type="1">
879
+ <li>Load the current event catalog and reserve current selections with
880
+ <code>setTickets(eventId, selections)</code>, or reserve seats and call
881
+ <code>setSeats</code> / <code>setSeatsIo</code>. Alternatively
882
+ <code>resumeCart</code> attaches to a cart already owned by this browser
883
+ session. The server owns inventory, expiry and final prices.</li>
884
+ <li>Read <code>customFields</code>, <code>buyerFields</code>,
885
+ conditions, required add-ons, waiver, pricing and payment availability
886
+ from the primed snapshot. Collect the required buyer/holder answers and
887
+ consent. Save them through the corresponding setters. Reprice after
888
+ add-on or currency changes.</li>
889
+ <li>Render only the methods offered for this event and compatible with
890
+ the host. Validate required information, then
891
+ <code>await placeOrder(method)</code> once per buyer action. The engine
892
+ checks preconditions and coordinates concurrent placement.</li>
893
+ <li>Handle the returned <code>PlaceOrderResult</code>, including
894
+ <code>pending</code>, and any ID verification. A result, a redirect, or
895
+ a closed popup alone does not prove that money settled. Reconcile
896
+ authoritative order and provider status before fulfilling or starting a
897
+ new payment when an outcome is uncertain.</li>
898
+ </ol>
899
+ <p><code>status</code> can be <code>idle</code>, <code>priming</code>,
900
+ <code>ready</code>, <code>repricing</code>, <code>placing</code>,
901
+ <code>succeeded</code>, <code>expired</code> or <code>error</code>.
902
+ <code>isBusy</code> includes cart/order operations and an outstanding
903
+ waiver save. <code>secondsLeft</code> is an optional, whole-second
904
+ display countdown derived from <code>expiresAt</code>. When it reaches
905
+ zero the hook expires the cart unless an order is being placed or has
906
+ succeeded. An expired reservation requires the buyer to start again; a
907
+ displayed countdown does not extend a server reservation.</p>
908
+ <p><code>reset()</code> starts a reset and returns <code>void</code>;
909
+ <code>await resetWhenSettled()</code> returns <code>true</code> only
910
+ when reset completed. While a payment is in flight, reset waits for it.
911
+ It returns <code>false</code> if an order must be retained because money
912
+ may have moved, or the checkout is retired. A <code>false</code> result
913
+ does not identify which reason applies. Show neutral guidance and check
914
+ the current session and authoritative order/provider status before
915
+ choosing recovery. <code>PAID_ORDER_PENDING_MESSAGE</code> contains an
916
+ instruction to press Pay again; do not show it for every
917
+ <code>false</code> result or use it as proof that a retry is safe. Do
918
+ not assume a timeout, network error or closed provider page means the
919
+ charge failed. A custom provider page must settle with
920
+ <code>{ event: 'dismiss' }</code> on close/unmount, and other custom
921
+ payment ports must settle, or a waiting reset cannot finish.</p>
922
+ <p>The beta.27 declaration comments for <code>reset</code> and
923
+ <code>PAID_ORDER_PENDING_MESSAGE</code> say pressing Pay again finishes
924
+ an unconfirmed order; the <code>resetWhenSettled</code> comment also
925
+ omits retired checkouts as a reason for <code>false</code>. Those
926
+ comments do not establish that a retry is safe. Use the session and
927
+ reconciliation guidance above.</p>
928
+ <p>Stock <code>Payment</code> can display an engine message telling the
929
+ buyer to press Pay again when payment is unconfirmed. That wording does
930
+ not establish that a retry is safe. If neutral buyer guidance is
931
+ required for uncertain outcomes, use a custom payment flow with
932
+ host-controlled error UI, retain the order and reconcile the current
933
+ session and authoritative order/provider status before recovery.</p>
934
+ <h3 id="tickets-codes-seats-and-waiting-lists">Tickets, codes, seats and
935
+ waiting lists</h3>
936
+ <p><code>Tickets</code> reads the catalog, presents the event's
937
+ promo/access-code controls and waiting-list state, and reserves selected
938
+ ticket lines. <code>initialPromoCode</code> applies once on mount. The
939
+ web picker reads <code>promo</code> / <code>promo_code</code> and
940
+ <code>ttf_r</code> / <code>referrer_id</code> from the URL by default;
941
+ explicit props take precedence. Set
942
+ <code>readAttributionFromUrl={false}</code> to disable this. An
943
+ ambiguous numeric <code>?r=</code> can mean a promotion or referral and
944
+ is not classified by this SDK. Pass a referrer only when its meaning is
945
+ known.</p>
946
+ <p>For headless catalogs, <code>hooks.useTicketsWithMeta(eventId)</code>
947
+ exposes <code>tickets</code>, <code>promo</code>,
948
+ <code>waitingList</code> and <code>bundles</code>. After
949
+ <code>applyPromoCode</code>, refetch the catalog to display changed
950
+ prices or unlocked tickets. Private-event access is a separate server
951
+ operation, <code>ttf.events.authenticate(eventId, password)</code>;
952
+ refetch after success. Do not treat a code or an old catalog as proof
953
+ inventory is reserved. The versioned waiting-list definition controls
954
+ eligibility and choices; <code>waitingList.state</code> can be
955
+ <code>open</code>, <code>closed</code>, <code>hidden</code> or
956
+ <code>unsupported</code>. Use an authoritative offered choice for
957
+ <code>joinWaitingList</code>, or general interest where allowed.
958
+ Unsupported/custom forms may provide an event continuation URL.</p>
959
+ <p>Ticket quantities can survive rotating encrypted IDs <strong>when the
960
+ API supplies a stable canonical <code>selectionKey</code></strong>. Cart
961
+ submissions still use the latest opaque encrypted IDs. For dated
962
+ tickets, deployed canonical keys and numeric price context
963
+ (<code>display_price</code>, <code>price_with_fees</code>,
964
+ <code>fee_included</code>, <code>price_currency</code>,
965
+ <code>price_symbol</code>) must be provided and validated by the API.
966
+ When the optional key is absent, do not assume retention across ID
967
+ rotation.</p>
968
+ <p><code>SeatMap</code> uses the event's configured seat map and server
969
+ reservation. Let the buyer select seats before continuing; availability
970
+ can change. Test the actual map, chart and reservation expiry on the
971
+ target domain and browser. For a headless integration,
972
+ <code>SeatLine</code> uses the server seat reservation key, tier, ticket
973
+ type, option and price; do not manufacture those values from display
974
+ labels. <code>setSeatsIo</code> is a separate path for a seats.io
975
+ selection.</p>
976
+ <h3 id="buyer-fields-consent-and-waivers">Buyer fields, consent and
977
+ waivers</h3>
978
+ <p>The server's checkout configuration determines required buyer fields,
979
+ ticket holders, custom captures, add-ons and waiver.
980
+ <code>buyerFields</code> identifies gated nationality, gender and
981
+ Instagram inputs; <code>customFields</code> contains order, ticket and
982
+ add-on groups. Store order answers in <code>billing.dataCapture</code>,
983
+ each holder's answers in <code>ticketDataCapture</code>, and add-on
984
+ answers via <code>setAddonDataCapture</code>. Holder ticket type IDs
985
+ come from the priced cart, not the opaque catalog ID. Use backend
986
+ country/state IDs for <code>countryId</code> and <code>stateId</code>;
987
+ <code>countryCode</code> / <code>stateCode</code> are payment billing
988
+ codes.</p>
989
+ <p>In beta.27 conditional custom-field requiredness is left to the
990
+ backend and not all hosted-checkout conditional visibility is
991
+ reproduced. Verify the actual event against the deployed checkout,
992
+ including blanks, images, holder scoping and validation errors; do not
993
+ claim parity from the presence of a field alone. Terms and
994
+ <code>additionalConditions</code> are client-side acceptance gates;
995
+ respect the server's own requirements. <code>Payment</code> renders
996
+ condition <code>content</code>, or <code>name</code> as a fallback, as
997
+ HTML. Only supply trusted or appropriately sanitized content, and verify
998
+ the source and handling of server-provided conditions too.</p>
999
+ <p>During cart priming, failed custom-field, checkout-config, add-on or
1000
+ event condition reads fall back to empty/default data. The stock UI
1001
+ cannot show or gate requirements it did not load. Do not treat an empty
1002
+ list as proof that no requirement exists; verify deployment/failure
1003
+ behavior and add tested host safeguards for mandatory fields and
1004
+ acknowledgments. Server validation of required answers is not proof that
1005
+ a condition was acknowledged. Only failed waiver reads other than a 404
1006
+ are recorded in <code>unavailableDetails</code>. Before money may have
1007
+ moved, placement retries an unavailable waiver and blocks if it remains
1008
+ unknown; <code>reloadCheckoutDetails()</code> can also retry the waiver
1009
+ read. A retained order with a possible payment follows separate recovery
1010
+ and needs reconciliation. <code>WaiverSigning</code> handles the SDK's
1011
+ signing flow.</p>
1012
+ <p><strong>Consent limitation in beta.27:</strong> when
1013
+ <code>privacyPolicy</code> is supplied, the stock
1014
+ <code>BillingInfo</code> replaces the Ticket Fairy marketing checkbox
1015
+ with the required privacy checkbox, but both use
1016
+ <code>consent.ttfOptIn</code>; the order sends that value as
1017
+ <code>ttf_opt_in</code>. The privacy acknowledgement and Ticket Fairy
1018
+ marketing choice are therefore not independently captured by this stock
1019
+ path. <code>brandOptIn</code> is a separate value. If your integration
1020
+ requires independent privacy and marketing choices, do not rely on the
1021
+ stock <code>privacyPolicy</code> prop for that requirement; use an
1022
+ alternative whose UI, payload and backend behavior you have
1023
+ verified.</p>
1024
+ <p>Do not combine stock required <code>privacyPolicy</code> with
1025
+ <code>skipBillingWhenProfileComplete</code> /
1026
+ <code>skipWhenProfileComplete</code>. When skipping is eligible, the
1027
+ billing card and its consent controls disappear while
1028
+ <code>Payment</code> can still require the privacy value. The same skip
1029
+ can hide marketing opt-ins; do not assume they remain visible. Keep the
1030
+ billing card available and test both signed-in and guest flows.</p>
1031
+ <h2 id="payments">Payments</h2>
1032
+ <p><code>Payment</code> selects available methods from event/backend
1033
+ configuration and uses the web platform's Stripe, popup and Xendit
1034
+ ports. Supported request shapes in the engine include card, Apple Pay,
1035
+ Google Pay, Stripe redirect methods, OXXO, Xendit card/e-wallets,
1036
+ PayPal, Razorpay, Adyen and payment plans. A type existing in the SDK
1037
+ does <strong>not</strong> mean it is enabled for your event, browser,
1038
+ country, currency, merchant account or deployed backend. Offer the
1039
+ server-returned methods, handle an unavailable or unsupported method,
1040
+ and test each enabled rail with its provider. Wallets require their own
1041
+ provider and domain/device configuration. Redirect/popup methods require
1042
+ allowed popups, return URLs, content security policy and third-party
1043
+ access. Provider configuration and scripts are separate from installing
1044
+ the npm package.</p>
1045
+ <p><code>PlaceOrderResult</code> contains <code>orderHash</code>,
1046
+ <code>free</code>, <code>needIdVerification</code>, and optional
1047
+ <code>currency</code>, <code>paymentIntentId</code>,
1048
+ <code>alreadyPaid</code>, <code>pending</code> and
1049
+ <code>pendingVoucherUrl</code>. <code>alreadyPaid</code> means the
1050
+ server reported a duplicate as already paid; it does not mean this
1051
+ invocation charged again. OXXO vouchers and PayPal can be pending. Show
1052
+ a pending state and voucher link if provided; wait for authoritative
1053
+ confirmation before showing a paid receipt or fulfilling. ID
1054
+ verification may still be required after payment. An ID-verification
1055
+ failure is not a reason to repeat the charge.</p>
1056
+ <p>The stock in-flow <code>Confirmation</code> displays
1057
+ confirmed/ticket-available copy when <code>pending</code> is absent or
1058
+ false; it does not independently verify final settlement. For both paid
1059
+ and free orders, use <code>confirmationMode="redirect"</code> with a
1060
+ host-owned status page, or a custom composed confirmation gated on
1061
+ authoritative order and provider status. Arrange ID verification on the
1062
+ host route when <code>needIdVerification</code> is true; redirect does
1063
+ not render the inline verification. The stock
1064
+ <code>IDVerification</code> and routed <code>OrderIDVerification</code>
1065
+ verified messages say tickets are on their way; they do not check final
1066
+ settlement or issuance. Use host-owned neutral verification and status
1067
+ UI when that copy is premature. If <code>onComplete</code> navigates
1068
+ away or unmounts the checkout, its inline verification cannot appear:
1069
+ keep the provider mounted or handle verification at the destination. For
1070
+ a custom flow, see <a href="#host-owned-id-verification">host-owned ID
1071
+ verification</a>.</p>
1072
+ <p><strong>Zero-total orders:</strong> this SDK ignores the
1073
+ free-registration response body and reports
1074
+ <code>needIdVerification: false</code>. Verification or approval may
1075
+ still be required, and <code>free: true</code> is not proof tickets were
1076
+ issued. The default inline <code>EmbeddedCheckout</code> can
1077
+ nevertheless show confirmed or ticket-available copy while approval or
1078
+ verification is still outstanding. Use
1079
+ <code>confirmationMode="redirect"</code> with host-owned authoritative
1080
+ order and verification status, or a custom composed confirmation gated
1081
+ on that status. If the status is unavailable, contact support. Do not
1082
+ retry payment for a free order.</p>
1083
+ <p><code>OrderConfirmation</code> is a reloadable presentation and does
1084
+ <strong>not</strong> check the order's payment status before showing its
1085
+ default confirmed/ticket-availability copy. Gate it on an authoritative
1086
+ status appropriate for that page. When <code>onComplete</code> reports
1087
+ <code>pending</code>, show a pending page (and any voucher) instead; do
1088
+ not route directly to <code>OrderConfirmation</code> as a paid receipt.
1089
+ The in-flow <code>Confirmation</code> component reads the current result
1090
+ and has a pending state, but the absence of <code>pending</code> is not
1091
+ proof of settlement.</p>
1092
+ <p><code>CardInput</code> renders Stripe Elements and uses the
1093
+ checkout's default card owner; <code>StripePaymentElement</code> is the
1094
+ deferred Elements option when its server config and wallet gates are
1095
+ available. <code>XenditCardInput</code> renders Xendit card fields.
1096
+ <code>Payment</code> wires the right input automatically. When
1097
+ implementing a custom pay step, render the correct input for the
1098
+ selected gateway and keep it mounted and visible for that payment. Do
1099
+ not collect raw card numbers in your own form or logs. Multiple card
1100
+ flows must respect field ownership. With no explicit claim, the web hook
1101
+ claims the default <code>checkout</code> owner's Payment Element if
1102
+ registered, otherwise its <code>CardInput</code>, and refuses if neither
1103
+ is available. For a custom owner, <code>claimCardField(owner)</code>
1104
+ claims a <code>CardInput</code> only; a
1105
+ <code>StripePaymentElement</code> uses
1106
+ <code>cardClaimStep('webPaymentElement', () =&gt; webConfirmer.claimPaymentElement(owner))</code>
1107
+ as the <code>placeOrder</code> <code>claimCard</code> step. For a bare
1108
+ card field, the <code>webCard</code> claim step should call
1109
+ <code>webConfirmer.releasePaymentElement()</code> before
1110
+ <code>claimCardField(owner)</code>. The standard <code>Payment</code>
1111
+ component handles these claims and key changes for you.</p>
1112
+ <p><code>useCheckout({ ports, options })</code> reads options on first
1113
+ render. The <code>ports</code> option merges additional compatible web
1114
+ capabilities over the defaults, but its type excludes
1115
+ <code>confirmer</code>; it cannot replace <code>webConfirmer</code>.
1116
+ <code>options</code> includes <code>redirectReturnUrl</code> and
1117
+ merchant/wallet options. A custom confirmer belongs in the lower-level
1118
+ <code>createEngine</code> configuration, not this web hook option.</p>
1119
+ <p>The engine retains the order when it cannot establish whether a
1120
+ charge moved. A custom confirmer should reject using
1121
+ <code>paymentProviderError(message, outcome)</code>;
1122
+ <code>outcome</code> is <code>declined</code>, <code>cancelled</code>,
1123
+ <code>notStarted</code>, or <code>unknown</code>. Use the first three
1124
+ only when the provider confirms nothing was charged. An unclassified
1125
+ error is treated as unknown. Avoid automatic blind retries and never
1126
+ promise exactly-once charging across your app, backend and provider.</p>
1127
+ <h3 id="host-owned-id-verification">Host-owned ID verification</h3>
1128
+ <p><code>runIdVerification(orderHash, options)</code> does not open the
1129
+ provider on its own. Supply <code>openUrl</code> to validate the URL
1130
+ against your provider and scheme policy and open it in the browser;
1131
+ handle a missing URL or blocked/failed opening in your UI. The engine
1132
+ swallows asynchronous <code>openUrl</code> rejections, so catch and
1133
+ record opening failures inside the callback: polling can otherwise
1134
+ continue without a handoff. Use <code>onPhase</code> for polling state
1135
+ and handle browser returns; <code>registerForegroundListener</code> can
1136
+ trigger a recheck on return and must return an unsubscribe function.</p>
1137
+ <p>Alternatively, <code>onRequired</code> receives the order hash and
1138
+ possibly null URL; if it returns <code>true</code>, the engine resolves
1139
+ <code>undefined</code> without opening or polling, and your host owns
1140
+ both steps. A timeout or poll error rejects with a message promising
1141
+ that payment is safe and tickets will be emailed. Replace that text with
1142
+ neutral status and reconcile authoritative payment, verification and
1143
+ issuance. Verification alone does not prove settlement or issuance.</p>
1144
+ <h2 id="authentication">Authentication</h2>
1145
+ <p>The embedded checkout supplies the event to its built-in
1146
+ <code>AuthModal</code>. A standalone modal can do the same. The host
1147
+ must already provide a query client and initialize the SDK. The checkout
1148
+ callback is deliberately narrow.</p>
1149
+ <pre class="tsx"><code>import { useState } from &#39;react&#39;
1150
+ import { AuthModal } from &#39;tf-checkout-react&#39;
1151
+
1152
+ export function SignIn() {
1153
+ const [open, setOpen] = useState(false)
1154
+ return (
1155
+ &lt;&gt;
1156
+ &lt;button onClick={() =&gt; setOpen(true)}&gt;Sign in&lt;/button&gt;
1157
+ &lt;AuthModal
1158
+ open={open}
1159
+ onClose={() =&gt; setOpen(false)}
1160
+ checkoutEventId=&quot;EVENT_ID&quot;
1161
+ onCheckoutAuthenticated={() =&gt; setOpen(false)}
1162
+ /&gt;
1163
+ &lt;/&gt;
1164
+ )
1165
+ }</code></pre>
1166
+ <p><code>AuthModal</code> props: <code>open</code> and
1167
+ <code>onClose</code> are required; optional
1168
+ <code>checkoutEventId</code>, <code>onCheckoutAuthenticated</code>,
1169
+ <code>initialView</code>, <code>initialEmail</code>,
1170
+ <code>message</code>, <code>allowRegistration</code> (default
1171
+ <code>true</code>), <code>allowPasswordReset</code> (default
1172
+ <code>true</code>), <code>requireRegistrationAddress</code> (default
1173
+ <code>true</code>), <code>registrationFields</code>,
1174
+ <code>logoUrl</code>, <code>onAuthenticated</code> and
1175
+ <code>className</code>. Public checkout auth requires its registered
1176
+ client and matching deployed server contract. Browser checkout
1177
+ authorization uses a popup with state and PKCE; secure browser crypto
1178
+ and popups must be available. The popup may be blocked or closed, and
1179
+ two-factor or email/phone proof can be required. Surface those outcomes
1180
+ rather than assuming sign-in succeeded. The public checkout registration
1181
+ and account completion paths force address collection even if
1182
+ <code>requireRegistrationAddress</code> is <code>false</code>.</p>
1183
+ <p>For a custom UI, <code>hooks.useAuthFlow(options)</code> owns
1184
+ authentication state, validation and transitions, while
1185
+ <code>LoginForm</code>, <code>RegisterForm</code>,
1186
+ <code>ForgotPasswordForm</code>, <code>ResetPasswordForm</code>,
1187
+ <code>TwoFactorForm</code>, <code>EmailCodeForm</code> and
1188
+ <code>PhoneAuthView</code> provide forms/views. <code>LoginForm</code>
1189
+ requires <code>onSubmit</code>; <code>RegisterForm</code> requires
1190
+ <code>onSubmit</code>; <code>ForgotPasswordForm</code> requires
1191
+ <code>onSubmit</code> and <code>onBackToLogin</code>;
1192
+ <code>ResetPasswordForm</code> requires a reset <code>token</code>.
1193
+ <code>TwoFactorForm</code> and <code>EmailCodeForm</code> are controlled
1194
+ views with required state and callbacks; <code>PhoneAuthView</code>
1195
+ requires a <code>PhoneAuthenticationFlow</code>. Their exported
1196
+ <code>*Props</code> types document every field. The individual
1197
+ controlled forms do not turn an arbitrary callback into a complete
1198
+ authenticated session; use the appropriate flow and handle all its
1199
+ states.</p>
1200
+ <h2 id="component-reference">Component reference</h2>
1201
+ <p>Props shown without <code>?</code> are required. All named
1202
+ <code>*Props</code> types below are exported unless stated otherwise;
1203
+ TypeScript declarations in the installed package are the authoritative
1204
+ detail for callback payloads and DTOs.</p>
1205
+ <h3 id="checkout-sections">Checkout sections</h3>
1206
+ <table>
1207
+ <thead>
1208
+ <tr>
1209
+ <th>Export</th>
1210
+ <th>Props and purpose</th>
1211
+ </tr>
1212
+ </thead>
1213
+ <tbody>
1214
+ <tr>
1215
+ <td><code>Tickets</code></td>
1216
+ <td><code>eventId</code>, <code>title?</code>, <code>onContinue?</code>,
1217
+ <code>buttonLabel?</code>, <code>timeSlotDates?</code> (ISO dates),
1218
+ <code>step?</code>, <code>onSelectSeats?</code>,
1219
+ <code>initialPromoCode?</code>, <code>referrer?</code>,
1220
+ <code>readAttributionFromUrl?</code>, <code>className?</code>.
1221
+ <code>onContinue</code> fires after the cart is primed.</td>
1222
+ </tr>
1223
+ <tr>
1224
+ <td><code>SeatMap</code></td>
1225
+ <td><code>eventId</code>, <code>onContinue?</code>, <code>step?</code>,
1226
+ <code>className?</code>. Callback fires after seats are added and
1227
+ priced.</td>
1228
+ </tr>
1229
+ <tr>
1230
+ <td><code>AddOns</code></td>
1231
+ <td><code>eventId</code>, <code>onContinue?</code>,
1232
+ <code>onSkip?</code>, <code>buttonLabel?</code>, <code>eyebrow?</code>,
1233
+ <code>heading?</code>, <code>className?</code>. Skip is hidden for a
1234
+ required add-on.</td>
1235
+ </tr>
1236
+ <tr>
1237
+ <td><code>Bundles</code></td>
1238
+ <td><code>eventId</code>, <code>onPurchased?(orderHash)</code>,
1239
+ <code>onComplete?(order)</code>, <code>confirmationMode?</code>,
1240
+ <code>visible?</code>, <code>heading?</code>, <code>className?</code>.
1241
+ Bundle purchase is its own flow; hide its card field using
1242
+ <code>visible</code> when the section is hidden.</td>
1243
+ </tr>
1244
+ <tr>
1245
+ <td><code>BillingInfo</code></td>
1246
+ <td><code>eventId?</code>, <code>onContinue?</code>,
1247
+ <code>heading?</code>, <code>buttonLabel?</code>, <code>onLogin?</code>,
1248
+ <code>skipWhenProfileComplete?</code>,
1249
+ <code>requireEmailConfirmation?</code>,
1250
+ <code>collectTicketHolders?</code>, <code>collectHolderContact?</code>,
1251
+ <code>ttfOptInLabel?</code>, <code>brandOptInLabel?</code>,
1252
+ <code>privacyPolicy?</code>, <code>showPrivacyError?</code>,
1253
+ <code>step?</code>, <code>className?</code>. Standalone holder
1254
+ collection follows backend gates unless explicitly enabled.</td>
1255
+ </tr>
1256
+ <tr>
1257
+ <td><code>WaiverSigning</code></td>
1258
+ <td><code>eventId</code>, <code>className?</code>. Render before payment
1259
+ for an event requiring a waiver.</td>
1260
+ </tr>
1261
+ <tr>
1262
+ <td><code>Payment</code></td>
1263
+ <td><code>onComplete?</code>, <code>eventId?</code>,
1264
+ <code>requireEmailConfirmation?</code>,
1265
+ <code>collectTicketHolders?</code>, <code>requireHolderContact?</code>,
1266
+ <code>additionalConditions?</code>, <code>requirePrivacyPolicy?</code>,
1267
+ <code>onPrivacyRequired?</code>, <code>showTestCardHint?</code>,
1268
+ <code>className?</code>. Match the paired billing policies.</td>
1269
+ </tr>
1270
+ <tr>
1271
+ <td><code>OrderSummary</code></td>
1272
+ <td><code>eventId?</code>, <code>className?</code>. Uses the current
1273
+ checkout's pricing. <code>Payment</code> already renders it; use it
1274
+ separately when you need a summary elsewhere.</td>
1275
+ </tr>
1276
+ <tr>
1277
+ <td><code>IDVerification</code></td>
1278
+ <td><code>className?</code>. Uses the current checkout/order.</td>
1279
+ </tr>
1280
+ <tr>
1281
+ <td><code>Confirmation</code></td>
1282
+ <td><code>shareUrl?</code>, <code>shareMessage?</code>,
1283
+ <code>viewOrderUrl?</code>, <code>children?</code>,
1284
+ <code>className?</code>. Uses the current checkout result and handles
1285
+ pending presentation. The default share URL and eligibility have the
1286
+ limitations below.</td>
1287
+ </tr>
1288
+ <tr>
1289
+ <td><code>OrderConfirmation</code></td>
1290
+ <td><code>orderHash</code>, <code>title?</code>, <code>message?</code>,
1291
+ <code>helper?</code>, <code>eventTitle?</code>, <code>eventDate?</code>,
1292
+ <code>eventLocation?</code>, <code>viewOrderUrl?</code> (string or
1293
+ function), <code>showReferral?</code>, <code>showShareButtons?</code>,
1294
+ <code>showRewards?</code>, <code>snapchat?</code>,
1295
+ <code>onLoaded?</code>, <code>onError?</code>, <code>className?</code>.
1296
+ Reloads confirmation by hash; the host must gate it on appropriate
1297
+ payment status. The three <code>show*</code> options default to true;
1298
+ Snapchat defaults to false.</td>
1299
+ </tr>
1300
+ <tr>
1301
+ <td><code>OrderIDVerification</code></td>
1302
+ <td><code>orderHash</code>, <code>onVerified?</code>,
1303
+ <code>className?</code>. For a separately routed order.</td>
1304
+ </tr>
1305
+ <tr>
1306
+ <td><code>Rewards</code></td>
1307
+ <td><code>orderHash?</code>, <code>data?</code>, <code>snapchat?</code>,
1308
+ <code>className?</code>. Supply an order hash or an already loaded
1309
+ <code>RewardsPayload</code>; <code>data</code> avoids a fetch.</td>
1310
+ </tr>
1311
+ <tr>
1312
+ <td><code>TicketChange</code></td>
1313
+ <td><code>ticketHash</code>, <code>orderHash?</code>,
1314
+ <code>onChanged?</code>, <code>openUrl?</code>, <code>onLogin?</code>,
1315
+ <code>className?</code>. Change/upgrade availability and any upgrade
1316
+ waitlist come from server options.</td>
1317
+ </tr>
1318
+ <tr>
1319
+ <td><code>Accommodation</code></td>
1320
+ <td><code>eventId</code>. Renders the accommodation selection for an
1321
+ applicable cart; requires checkout context.</td>
1322
+ </tr>
1323
+ </tbody>
1324
+ </table>
1325
+ <p><code>Confirmation</code> defaults <code>shareUrl</code> to
1326
+ <code>window.location.href</code>, displays generic referral copy for
1327
+ non-pending orders, and does not check organizer referral eligibility.
1328
+ The current URL may include unrelated query parameters or lack a
1329
+ buyer-specific referral. <code>EmbeddedCheckout</code> does not expose a
1330
+ <code>shareUrl</code> prop. For a composed <code>Confirmation</code>,
1331
+ pass a verified buyer-specific URL when eligible, or
1332
+ <code>shareUrl=""</code> to suppress sharing. Alternatively use
1333
+ server-backed <code>OrderConfirmation</code> / <code>Rewards</code>
1334
+ where the appropriate status and response support the experience. Check
1335
+ eligibility and attribution against the deployed backend; don't treat
1336
+ the generic link as evidence of a referral.</p>
1337
+ <p><code>OrderConfirmation</code> includes <code>Rewards</code> when its
1338
+ response has a rewards payload unless <code>showRewards={false}</code>.
1339
+ <code>Rewards</code> can also fetch by hash without a React Query
1340
+ provider. Sharing channels depend on organizer configuration and browser
1341
+ capabilities. Snapchat is opt-in and loads <code>sdk.snapkit.com</code>;
1342
+ allow it in the host's CSP only if used. Clipboard and share operations
1343
+ can be denied by the browser or buyer. <code>RewardsLadder</code>
1344
+ (<code>rows</code>, <code>onSubmitDetails?</code>,
1345
+ <code>className?</code>), <code>RewardsTree</code> (<code>tree</code>,
1346
+ <code>className?</code>), <code>RewardsChannels</code>
1347
+ (<code>channels</code>, <code>shareLink</code>,
1348
+ <code>shareMessage</code>, <code>assertCurrent?</code>,
1349
+ <code>shareCardImageUrl?</code>, <code>snapchat?</code>,
1350
+ <code>className?</code>), and <code>RewardsPackCard</code>
1351
+ (<code>pack</code>, <code>onCreate</code>, <code>onJoin</code>,
1352
+ <code>onLeave</code>, <code>assertCurrent?</code>) are available for
1353
+ custom reward layouts.</p>
1354
+ <p>An upgrade waitlist is a separate server-owned ticket-change
1355
+ contract. Valid change-options targets can expose Join or Leave only
1356
+ when the backend offers that organizer-configured flow. A sold-out row
1357
+ alone does not authorize it; malformed targets or entries are ignored.
1358
+ Verify the deployed contract and confirm the server response before
1359
+ presenting an action as completed.</p>
1360
+ <h3 id="account-post-purchase-and-discovery">Account, post-purchase and
1361
+ discovery</h3>
1362
+ <p>These exports are available in the package, but availability and
1363
+ required account authority vary by endpoint. A public checkout buyer is
1364
+ not automatically a full account user. Supply a host sign-in/route
1365
+ callback where applicable.</p>
1366
+ <table>
1367
+ <thead>
1368
+ <tr>
1369
+ <th>Export</th>
1370
+ <th>Props and purpose</th>
1371
+ </tr>
1372
+ </thead>
1373
+ <tbody>
1374
+ <tr>
1375
+ <td><code>TicketRefund</code></td>
1376
+ <td><code>ticketHash</code>, <code>onSubmitted?</code>,
1377
+ <code>onDone?</code>. Presents offered refund options and
1378
+ submission.</td>
1379
+ </tr>
1380
+ <tr>
1381
+ <td><code>TicketGift</code></td>
1382
+ <td><code>ticketHash</code>, <code>onTicketsChanged?</code>,
1383
+ <code>onDone?</code>, <code>locale?</code>. Gift flow.</td>
1384
+ </tr>
1385
+ <tr>
1386
+ <td><code>Passes</code></td>
1387
+ <td><code>onTicketsChanged?</code>, <code>locale?</code>. Customer
1388
+ passes and booking actions.</td>
1389
+ </tr>
1390
+ <tr>
1391
+ <td><code>Trips</code></td>
1392
+ <td><code>onOpen(url)</code>, <code>onPage(query)</code>,
1393
+ <code>data?</code>, <code>locale?</code>, <code>loading?</code>,
1394
+ <code>errorMessage?</code>, <code>onRetry?</code>. Host supplies data
1395
+ and navigation.</td>
1396
+ </tr>
1397
+ <tr>
1398
+ <td><code>AccountProfile</code></td>
1399
+ <td><code>onSaved?(profile, action)</code>. Profile gender/image
1400
+ actions.</td>
1401
+ </tr>
1402
+ <tr>
1403
+ <td><code>AccountInformationSection</code></td>
1404
+ <td><code>orderId</code>, <code>title?</code>, <code>target?</code>,
1405
+ <code>locale?</code>, <code>active?</code>, <code>onSaved?</code>. Order
1406
+ information/answers.</td>
1407
+ </tr>
1408
+ <tr>
1409
+ <td><code>AccountPaymentPlanSection</code></td>
1410
+ <td><code>plan</code>, <code>orderHash</code>, <code>locale?</code>,
1411
+ <code>onOpen?</code>, <code>onReturn?</code>. Payment-plan management
1412
+ for an existing order.</td>
1413
+ </tr>
1414
+ <tr>
1415
+ <td><code>AccountRewardsSection</code></td>
1416
+ <td><code>locale?</code>, <code>onBrowseEvents?</code>,
1417
+ <code>onViewTickets?</code>. Account rewards summary.</td>
1418
+ </tr>
1419
+ <tr>
1420
+ <td><code>AccountDeletion</code></td>
1421
+ <td><code>showHeader?</code>, <code>showExplanation?</code>,
1422
+ <code>locale?</code>, <code>onSignIn?</code>, <code>onDone?</code>,
1423
+ <code>onOpenTeam?</code>. <code>AccountDeletionView</code> additionally
1424
+ requires a <code>deletion</code> flow.</td>
1425
+ </tr>
1426
+ <tr>
1427
+ <td><code>NotificationPreferences</code></td>
1428
+ <td><code>locale?</code>, <code>onBack?</code>, <code>onSignIn?</code>,
1429
+ <code>onSaved?</code>. <code>NotificationPreferencesView</code>
1430
+ additionally requires a <code>preferences</code> flow.</td>
1431
+ </tr>
1432
+ <tr>
1433
+ <td><code>ProfileSettings</code></td>
1434
+ <td><code>mode: 'links' | 'visibility'</code>, <code>onBack?</code>,
1435
+ <code>onSignIn?</code>. <code>ProfileSettingsView</code> additionally
1436
+ requires a <code>settings</code> flow.</td>
1437
+ </tr>
1438
+ <tr>
1439
+ <td><code>AccountEmailEnrichment</code></td>
1440
+ <td>No props. <code>AccountEmailEnrichmentView</code> requires
1441
+ <code>flow</code>.</td>
1442
+ </tr>
1443
+ <tr>
1444
+ <td><code>PhoneAccountProfile</code></td>
1445
+ <td>No props. Phone account profile view.</td>
1446
+ </tr>
1447
+ <tr>
1448
+ <td><code>Interests</code></td>
1449
+ <td><code>onSignIn?</code>. Interest selection.</td>
1450
+ </tr>
1451
+ <tr>
1452
+ <td><code>Streaming</code></td>
1453
+ <td><code>onSignIn?</code>, <code>onOpenMusic?(url, provider?)</code>.
1454
+ Music connections.</td>
1455
+ </tr>
1456
+ <tr>
1457
+ <td><code>Friends</code></td>
1458
+ <td><code>initialCode?</code>, <code>onSignIn?</code>. Friend
1459
+ flows.</td>
1460
+ </tr>
1461
+ <tr>
1462
+ <td><code>SavedEvents</code></td>
1463
+ <td><code>onSignIn?</code>. Saved-event list.</td>
1464
+ </tr>
1465
+ <tr>
1466
+ <td><code>Recommendations</code></td>
1467
+ <td><code>events</code>, <code>enabled?</code>. Recommendations from the
1468
+ supplied <code>AccountEvent[]</code>.</td>
1469
+ </tr>
1470
+ <tr>
1471
+ <td><code>EventComments</code></td>
1472
+ <td><code>eventId</code>, <code>previewKey?</code>,
1473
+ <code>onSignIn?</code>, <code>className?</code>. Discussion with
1474
+ backend-supplied permissions. <code>EventCommentsView</code> accepts a
1475
+ supplied discussion flow.</td>
1476
+ </tr>
1477
+ <tr>
1478
+ <td><code>PostReaction</code></td>
1479
+ <td><code>postId: string | number</code>, <code>onSignIn?</code>.
1480
+ <code>PostReactionControls</code> accepts <code>flow</code> and
1481
+ <code>onSignIn?</code>.</td>
1482
+ </tr>
1483
+ <tr>
1484
+ <td><code>DiscoveryTravel</code></td>
1485
+ <td><code>searchCities</code>, <code>searchEvents</code>,
1486
+ <code>storage?</code>, <code>locale?</code>. Host supplies search
1487
+ functions; see <code>DiscoveryTravelProps</code> for their
1488
+ signatures.</td>
1489
+ </tr>
1490
+ </tbody>
1491
+ </table>
1492
+ <p>For account orders and ticket lists use <code>hooks.useOrders</code>,
1493
+ <code>hooks.useOrder</code>, <code>ttf.orders.list</code>,
1494
+ <code>ttf.orders.get</code> or <code>ttf.orders.myTickets</code>. In
1495
+ this version <code>ttf.orders.get</code> / <code>useOrder</code> take a
1496
+ <strong>numeric order ID string</strong>, not a public order hash;
1497
+ <code>OrderConfirmation</code> takes a hash. The package does not export
1498
+ 1.x <code>MyTicketsContainer</code>, <code>OrdersContainer</code>,
1499
+ <code>OrderDetailsContainer</code> or <code>TicketResaleContainer</code>
1500
+ as drop-in React replacements. Account/resale APIs and hooks can support
1501
+ a host-built screen when the appropriate account session and backend
1502
+ capabilities exist.</p>
1503
+ <h3 id="ui-primitives">UI primitives</h3>
1504
+ <p>Use these within a <code>.tf-checkout</code> styling boundary such as
1505
+ <code>CheckoutProvider</code>; standard HTML attributes apply where the
1506
+ component extends them.</p>
1507
+ <table>
1508
+ <thead>
1509
+ <tr>
1510
+ <th>Export</th>
1511
+ <th>Important props</th>
1512
+ </tr>
1513
+ </thead>
1514
+ <tbody>
1515
+ <tr>
1516
+ <td><code>Card</code></td>
1517
+ <td>HTML <code>div</code> attributes and children.</td>
1518
+ </tr>
1519
+ <tr>
1520
+ <td><code>SectionHeader</code></td>
1521
+ <td><code>title</code>, <code>step?</code>, <code>pills?</code>,
1522
+ <code>className?</code>.</td>
1523
+ </tr>
1524
+ <tr>
1525
+ <td><code>Pill</code></td>
1526
+ <td><code>children</code>, <code>muted?</code>.</td>
1527
+ </tr>
1528
+ <tr>
1529
+ <td><code>Button</code></td>
1530
+ <td>Button attributes,
1531
+ <code>variant?: 'primary' | 'secondary' | 'ghost'</code>,
1532
+ <code>block?</code>, <code>loading?</code>.</td>
1533
+ </tr>
1534
+ <tr>
1535
+ <td><code>Field</code></td>
1536
+ <td><code>children</code>, <code>label?</code>, <code>error?</code>,
1537
+ <code>invalid?</code>, <code>className?</code>; <code>FieldRow</code>
1538
+ takes <code>children</code>, <code>className?</code>.</td>
1539
+ </tr>
1540
+ <tr>
1541
+ <td><code>Input</code>, <code>Textarea</code>, <code>Select</code></td>
1542
+ <td>Corresponding HTML attributes plus <code>invalid?</code>.</td>
1543
+ </tr>
1544
+ <tr>
1545
+ <td><code>Checkbox</code></td>
1546
+ <td>Input attributes plus <code>label?</code>.</td>
1547
+ </tr>
1548
+ <tr>
1549
+ <td><code>CustomFieldInput</code></td>
1550
+ <td><code>field</code>, <code>value</code>, <code>onChange</code>,
1551
+ <code>error?</code>.</td>
1552
+ </tr>
1553
+ <tr>
1554
+ <td><code>CustomFieldGroupFields</code></td>
1555
+ <td><code>group</code>, <code>values</code>,
1556
+ <code>onChange(name, value)</code>, <code>ticketTypeId?</code>;
1557
+ <code>customFieldsComplete</code> is also exported.</td>
1558
+ </tr>
1559
+ <tr>
1560
+ <td><code>PaymentMethods</code></td>
1561
+ <td>Controlled <code>options</code>, <code>selected</code>,
1562
+ <code>onSelect</code>, <code>extraValues</code>,
1563
+ <code>onExtraChange</code>; optional <code>showValidation</code>,
1564
+ <code>children</code>, <code>inputSlotFor</code>,
1565
+ <code>className</code>.</td>
1566
+ </tr>
1567
+ <tr>
1568
+ <td><code>Stepper</code></td>
1569
+ <td><code>value</code>, <code>onChange</code>, <code>min?</code>,
1570
+ <code>max?</code>, <code>step?</code>, <code>disabled?</code>,
1571
+ <code>className?</code>.</td>
1572
+ </tr>
1573
+ <tr>
1574
+ <td><code>QuantitySelect</code></td>
1575
+ <td><code>value</code>, <code>onChange</code>, <code>min?</code>,
1576
+ <code>max?</code>, <code>step?</code>, <code>disabled?</code>,
1577
+ <code>className?</code>, accessible <code>label?</code>.</td>
1578
+ </tr>
1579
+ <tr>
1580
+ <td><code>PriceLine</code></td>
1581
+ <td><code>amount</code>, <code>currency?</code>, <code>original?</code>,
1582
+ <code>note?</code>, <code>className?</code>.</td>
1583
+ </tr>
1584
+ <tr>
1585
+ <td><code>Timer</code></td>
1586
+ <td><code>seconds</code>, <code>urgentAt?</code>, <code>label?</code>,
1587
+ <code>className?</code>. <code>TimerBanner</code> takes
1588
+ <code>seconds?</code>, <code>urgentAt?</code>, <code>message?</code>,
1589
+ <code>className?</code>.</td>
1590
+ </tr>
1591
+ <tr>
1592
+ <td><code>Loader</code></td>
1593
+ <td><code>className?</code>.</td>
1594
+ </tr>
1595
+ <tr>
1596
+ <td><code>SignaturePad</code></td>
1597
+ <td><code>label</code>, <code>clearLabel</code>,
1598
+ <code>onChange(pngDataUrl, inkLength)</code>,
1599
+ <code>disabled?</code>.</td>
1600
+ </tr>
1601
+ <tr>
1602
+ <td><code>FrozenFields</code></td>
1603
+ <td><code>children</code>, <code>frozen?</code>; disables interaction
1604
+ for its nested fields.</td>
1605
+ </tr>
1606
+ </tbody>
1607
+ </table>
1608
+ <p>Additional web exports include <code>themeToVars</code>,
1609
+ <code>cx</code>, <code>I18nProvider</code>, <code>useT</code>,
1610
+ <code>useInstallmentPicker</code>, <code>CardInput</code>,
1611
+ <code>StripePaymentElement</code>, <code>XenditCardInput</code>,
1612
+ <code>claimCardField</code>, <code>webConfirmer</code>,
1613
+ <code>webPorts</code>, <code>webXenditTokenizer</code>, and the
1614
+ <code>createWebStripeConfirmer</code>, <code>createWebPorts</code>,
1615
+ <code>createWebXenditTokenizer</code> factories. Their installed
1616
+ declarations specify complete inputs and outputs. These are lower-level
1617
+ integration points; preserve their payment and session ownership rules
1618
+ when replacing the default flow.</p>
1619
+ <h2 id="headless-apis">Headless APIs</h2>
1620
+ <p><code>useCheckout()</code> returns the snapshot both flat and as
1621
+ <code>snapshot</code>, plus actions. The web version injects browser
1622
+ payment ports; the shared <code>hooks.useCheckout</code> is the
1623
+ lower-level binding and requires an engine configuration. The following
1624
+ example only reserves caller-supplied current catalog selections. It
1625
+ deliberately does not place an order without collecting the event's
1626
+ required data.</p>
1627
+ <pre class="tsx"><code>import { useState } from &#39;react&#39;
1628
+ import { useCheckout, type TicketSelection } from &#39;tf-checkout-react&#39;
1629
+
1630
+ export function ReserveButton(props: {
1631
+ eventId: string
1632
+ selections: TicketSelection[]
1633
+ }) {
1634
+ const checkout = useCheckout()
1635
+ const [message, setMessage] = useState(&#39;&#39;)
1636
+ async function reserve() {
1637
+ try {
1638
+ await checkout.setTickets(props.eventId, props.selections)
1639
+ setMessage(&#39;Tickets reserved&#39;)
1640
+ } catch (error) {
1641
+ setMessage(error instanceof Error ? error.message : &#39;Could not reserve tickets&#39;)
1642
+ }
1643
+ }
1644
+ return (
1645
+ &lt;div&gt;
1646
+ &lt;button disabled={checkout.isBusy} onClick={() =&gt; void reserve()}&gt;
1647
+ Reserve
1648
+ &lt;/button&gt;
1649
+ &lt;p role=&quot;status&quot;&gt;{message}&lt;/p&gt;
1650
+ &lt;/div&gt;
1651
+ )
1652
+ }</code></pre>
1653
+ <p>A <code>TicketSelection</code> has <code>id</code> (current encrypted
1654
+ ticket ID), <code>name</code>, <code>optionName</code>,
1655
+ <code>price</code>, <code>quantity</code> and <code>currency</code>.
1656
+ Construct it from the current catalog, not a stale cached display row.
1657
+ Do not trust client-side prices as the final order amount.</p>
1658
+ <h3 id="snapshot-and-actions">Snapshot and actions</h3>
1659
+ <table>
1660
+ <thead>
1661
+ <tr>
1662
+ <th>Field / action</th>
1663
+ <th>Contract</th>
1664
+ </tr>
1665
+ </thead>
1666
+ <tbody>
1667
+ <tr>
1668
+ <td><code>status</code>, <code>error</code>, <code>order</code>,
1669
+ <code>eventId</code>, <code>expiresAt</code>, <code>secondsLeft</code>,
1670
+ <code>isBusy</code></td>
1671
+ <td>Progress, latest error/result and reservation timing.
1672
+ <code>error</code> is a display string; async actions may also
1673
+ reject.</td>
1674
+ </tr>
1675
+ <tr>
1676
+ <td><code>selections</code>, <code>ticketTypeIds</code>,
1677
+ <code>addOns</code>, <code>breakdown</code>,
1678
+ <code>priceBreakdown</code></td>
1679
+ <td>Cart selections, decrypted ticket type IDs and server pricing.
1680
+ Prefer server-priced output for display.</td>
1681
+ </tr>
1682
+ <tr>
1683
+ <td><code>customFields</code>, <code>buyerFields</code>,
1684
+ <code>fieldGates</code>, <code>holderNamesRequired</code>,
1685
+ <code>requiredAddOns</code>, <code>missingRequiredAddonNames</code></td>
1686
+ <td>Inputs and event gates. Required add-ons sold out are exempt from
1687
+ the missing-add-on check.</td>
1688
+ </tr>
1689
+ <tr>
1690
+ <td><code>billing</code>, <code>holders</code>, <code>consent</code>,
1691
+ <code>conditions</code>, <code>acceptedConditions</code>,
1692
+ <code>existingAccountEmail</code></td>
1693
+ <td>Buyer draft and acceptance state.
1694
+ <code>checkBuyerEmail(email)</code> starts an existing-account check and
1695
+ writes the result to the snapshot.</td>
1696
+ </tr>
1697
+ <tr>
1698
+ <td><code>waiver</code>, <code>waiverSignatures</code>,
1699
+ <code>waiverSigningIndexes</code>, <code>unavailableDetails</code>,
1700
+ <code>orderFixed</code></td>
1701
+ <td>Waiver and order-edit state. Forms are frozen while placing or after
1702
+ the order is charged.</td>
1703
+ </tr>
1704
+ <tr>
1705
+ <td><code>gateway</code>, <code>stripe</code>,
1706
+ <code>paymentStripe</code>, <code>paymentPlan</code>,
1707
+ <code>redirectPaymentMethods</code>, <code>walletAvailability</code>,
1708
+ <code>stripeElementsConfig</code>, <code>currency</code></td>
1709
+ <td>Payment/configuration data after priming. Absence does not authorize
1710
+ a method.</td>
1711
+ </tr>
1712
+ <tr>
1713
+ <td><code>extraItems</code>, <code>extraDraft</code>,
1714
+ <code>extraQuotes</code>, <code>extraRejections</code>,
1715
+ <code>extraExpiresAt</code>, <code>reviewedExtraOrderTotal</code></td>
1716
+ <td>Accommodation/extras state and changed authoritative total. Show a
1717
+ changed total before another Pay action.</td>
1718
+ </tr>
1719
+ <tr>
1720
+ <td><code>setTickets(eventId, selections)</code>,
1721
+ <code>setSeats(eventId, lines)</code>,
1722
+ <code>setSeatsIo(eventId, selection)</code>,
1723
+ <code>resumeCart(eventId, options?)</code></td>
1724
+ <td>Build/price or resume a server cart; return promises.</td>
1725
+ </tr>
1726
+ <tr>
1727
+ <td><code>setAddons(addOns)</code>,
1728
+ <code>setExtraItems(items)</code></td>
1729
+ <td>Reprice/reserve selections asynchronously.
1730
+ <code>setExtraDraft(items | undefined)</code> changes the local
1731
+ draft.</td>
1732
+ </tr>
1733
+ <tr>
1734
+ <td><code>setBilling(billing)</code>,
1735
+ <code>setHolders(holders, options?)</code>,
1736
+ <code>setConsent(consent)</code></td>
1737
+ <td>Commit buyer, holder and marketing data. <code>setHolders</code> can
1738
+ mark backfilled holder indexes.</td>
1739
+ </tr>
1740
+ <tr>
1741
+ <td><code>setAcceptedConditions(map)</code>,
1742
+ <code>acceptCondition(id, accepted)</code>,
1743
+ <code>setAddonDataCapture(map)</code></td>
1744
+ <td>Record condition acceptance and add-on answers.</td>
1745
+ </tr>
1746
+ <tr>
1747
+ <td><code>setWaiverSignature(index, signature, hold?)</code>,
1748
+ <code>holdWaiverSigning(index)</code></td>
1749
+ <td>Coordinate a signature save with the cart/holder it belongs to;
1750
+ release a hold when finished. Prefer <code>WaiverSigning</code> for
1751
+ standard UI.</td>
1752
+ </tr>
1753
+ <tr>
1754
+ <td><code>reloadCheckoutDetails()</code>,
1755
+ <code>syncCurrency(eventId, code?, options?)</code></td>
1756
+ <td>Retry unavailable details or switch/seed event currency. Refresh
1757
+ selection and prices after changing currency.</td>
1758
+ </tr>
1759
+ <tr>
1760
+ <td><code>placeOrder(method?, options?)</code>,
1761
+ <code>runIdVerification(orderHash, options?)</code></td>
1762
+ <td>Place/pay; optionally run verification separately with a host URL
1763
+ opener or takeover. See <a href="#host-owned-id-verification">host-owned
1764
+ ID verification</a>. <code>placeOrder</code> accepts
1765
+ <code>autoRunIdVerification</code>, <code>idVerification</code> and
1766
+ <code>claimCard</code> options.</td>
1767
+ </tr>
1768
+ <tr>
1769
+ <td><code>applyPromoCode(eventId, code)</code>,
1770
+ <code>attributeReferrer(eventId, referrer)</code>,
1771
+ <code>joinWaitingList(eventId, entry)</code></td>
1772
+ <td>Helpers return promises. Refetch catalog after a code changes
1773
+ availability.</td>
1774
+ </tr>
1775
+ <tr>
1776
+ <td><code>reset()</code>, <code>resetWhenSettled()</code></td>
1777
+ <td>Restart subject to payment-settlement protection; see <a
1778
+ href="#checkout-lifecycle">lifecycle</a>.</td>
1779
+ </tr>
1780
+ <tr>
1781
+ <td><code>snapshot</code>, <code>store</code>,
1782
+ <code>isLoggedIn</code></td>
1783
+ <td>Entire state, shared store, and whether the hook sees an
1784
+ authenticated or checkout buyer session. The latter does not imply
1785
+ private-account authority.</td>
1786
+ </tr>
1787
+ </tbody>
1788
+ </table>
1789
+ <p><code>checkBuyerEmail</code> is not itself debounced.
1790
+ <code>BillingInfo</code> delays calls, but a headless host should
1791
+ debounce and coordinate in-flight checks. A late response for an earlier
1792
+ email in the same cart can overwrite the snapshot; compare
1793
+ <code>existingAccountEmail</code> with the current trimmed input before
1794
+ prompting and recheck the current value if needed.</p>
1795
+ <p><code>CheckoutBilling</code> requires <code>firstName</code>,
1796
+ <code>lastName</code>, <code>email</code>; optional fields include
1797
+ <code>confirmEmail</code>, <code>phone</code>, address, country/state
1798
+ IDs and codes, date of birth, nationality, gender, Instagram and
1799
+ <code>dataCapture</code>. <code>CheckoutHolder</code> requires
1800
+ <code>firstName</code>, <code>lastName</code>, <code>email</code>;
1801
+ optional <code>phone</code>, <code>ticketTypeId</code>,
1802
+ <code>ticketDataCapture</code>. <code>CheckoutConsent</code> has boolean
1803
+ <code>ttfOptIn</code> and <code>brandOptIn</code>. Event gates may
1804
+ require additional data even where the TypeScript property is optional.
1805
+ <code>confirmEmail</code> is a UI/preflight value; the order request
1806
+ uses the authoritative email.</p>
1807
+ <p><code>PaymentMethod</code> accepts <code>'card'</code>,
1808
+ <code>'applePay'</code> or <code>'googlePay'</code>.
1809
+ <code>PaymentRequest</code> additionally accepts objects with
1810
+ <code>method: 'auto'</code>, <code>'card'</code>,
1811
+ <code>'applePay'</code>, <code>'googlePay'</code>,
1812
+ <code>'redirect'</code> (<code>methodType</code>), <code>'oxxo'</code>,
1813
+ <code>'xenditEWallet'</code> (<code>walletKey</code>, optional
1814
+ <code>extra.cashtag</code> / <code>extra.phoneNumber</code>),
1815
+ <code>'paypal'</code>, <code>'razorpay'</code> (optional
1816
+ <code>description</code>), <code>'adyen'</code>,
1817
+ <code>'xenditCard'</code>, or <code>'paymentPlan'</code> (optional
1818
+ <code>useSavedCard</code>). Availability and necessary ports are
1819
+ provider-specific. <code>placeOrder()</code> defaults to card; do not
1820
+ use that default for a different gateway.</p>
1821
+ <h3 id="react-query-hooks-and-direct-api">React Query hooks and direct
1822
+ API</h3>
1823
+ <p>The package re-exports the shared core: <code>ttf</code> is a
1824
+ configured domain facade, <code>api</code> contains raw calls,
1825
+ <code>hooks</code> contains React bindings, and DTOs, logic,
1826
+ <code>createEngine</code> and <code>createCheckoutStore</code> are named
1827
+ exports. Network calls usually return promises;
1828
+ <code>ttf.events.filterAddonsForTickets</code> and
1829
+ <code>ttf.order.mapProfileToBilling</code> are synchronous helpers. They
1830
+ do not render UI or replace the engine's sequencing, payment ownership
1831
+ and preflight. Use them directly only when your application owns the
1832
+ corresponding workflow. The installed <code>dist/index.d.ts</code>
1833
+ includes the complete exported signatures. Avoid importing a private
1834
+ shared-core package.</p>
1835
+ <pre class="tsx"><code>import { hooks } from &#39;tf-checkout-react&#39;
1836
+
1837
+ export function CatalogStatus({ eventId }: { eventId: string }) {
1838
+ const catalog = hooks.useTicketsWithMeta(eventId)
1839
+ if (catalog.isPending) return &lt;p&gt;Loading tickets…&lt;/p&gt;
1840
+ if (catalog.isError) return &lt;button onClick={() =&gt; void catalog.refetch()}&gt;Retry&lt;/button&gt;
1841
+ return &lt;p&gt;{catalog.data.tickets.length} ticket types&lt;/p&gt;
1842
+ }</code></pre>
1843
+ <p>Useful hook groups, all imported through <code>hooks</code>:</p>
1844
+ <ul>
1845
+ <li>Catalog: <code>useEvent</code>, <code>useTickets</code>,
1846
+ <code>useTicketsWithMeta</code>, <code>useTimeSlotTickets</code>,
1847
+ <code>useEventAddons</code>, <code>useEventBundles</code>,
1848
+ <code>useTicketCatalog</code>, <code>useCountries</code>,
1849
+ <code>useStates</code>.</li>
1850
+ <li>Authentication/session: <code>useAuthFlow</code>,
1851
+ <code>useAuthSession</code>, <code>useLogin</code>,
1852
+ <code>useRegister</code>, <code>useLogout</code>,
1853
+ <code>useProfile</code>, <code>usePhoneAuthentication</code> and
1854
+ verification mutations. Choose the correct public checkout or account
1855
+ path.</li>
1856
+ <li>Checkout/selection: <code>useCheckout</code>,
1857
+ <code>useAddOnSelection</code>, <code>useSeatSelection</code>,
1858
+ <code>useSeatsIoSelection</code>, <code>useWaitingListForm</code>,
1859
+ <code>useWaiverSigning</code>, <code>useAccommodationSelection</code>,
1860
+ <code>useCheckoutPaymentMethods</code>, <code>useBundleFlow</code>.</li>
1861
+ <li>After purchase/account: <code>useOrders</code>,
1862
+ <code>useOrder</code>, <code>useOrderRewards</code>,
1863
+ <code>useTicketChange</code>, <code>useTicketRefund</code>,
1864
+ <code>useTicketGift</code>, <code>useCustomerPasses</code>,
1865
+ <code>useAccountPreferences</code>,
1866
+ <code>useNotificationPreferences</code>,
1867
+ <code>useAccountDeletion</code>, <code>useFriends</code>,
1868
+ <code>useEventComments</code>, <code>useTrips</code>.</li>
1869
+ </ul>
1870
+ <p>Catalog hooks use an event ID and many are disabled until it is
1871
+ present; query results expose standard React Query loading, error, data
1872
+ and <code>refetch</code> states. The account-order query uses a numeric
1873
+ order ID. Account access is scoped to the buyer session; don't reuse
1874
+ private cached data across sign-out or buyer changes.</p>
1875
+ <p>The <code>ttf</code> facade groups calls under <code>auth</code>,
1876
+ <code>profile</code>, <code>events</code>, <code>cart</code>,
1877
+ <code>order</code>, <code>payment</code>, <code>seatmap</code>,
1878
+ <code>engagement</code>, <code>confirmation</code>,
1879
+ <code>rewards</code>, <code>orders</code>, <code>ticketChanges</code>,
1880
+ <code>resale</code>, <code>refunds</code>, <code>gifts</code>,
1881
+ <code>passes</code>, <code>waivers</code>, <code>extras</code>,
1882
+ <code>trips</code>, <code>preferences</code>, <code>friends</code>,
1883
+ <code>savedEvents</code>, <code>comments</code>, <code>word</code>,
1884
+ <code>preRegistration</code> and <code>delegation</code>. For example,
1885
+ <code>ttf.events.ticketsWithMeta</code> loads a catalog,
1886
+ <code>ttf.geo.countries()</code> loads country choices, and
1887
+ <code>ttf.confirmation.get(orderHash)</code> reads a confirmation. The
1888
+ <code>geo</code> group is also available. Check each method's declared
1889
+ input and backend authority before calling it.</p>
1890
+ <p>Transport errors are normalized as <code>TtfError</code>, with
1891
+ <code>message</code>, HTTP <code>status</code> (<code>0</code> for
1892
+ transport failure), optional <code>code</code>, <code>data</code> and
1893
+ <code>retryAfter</code> seconds. Engine validation and provider errors
1894
+ can also be ordinary errors or typed errors such as
1895
+ <code>UNSUPPORTED_GATEWAY</code>; handle unknown errors as well. Avoid
1896
+ logging raw error data if it may contain personal or payment
1897
+ information.</p>
1898
+ <h3 id="tracking">Tracking</h3>
1899
+ <p>For an integration that is authorized to send event tracking, the
1900
+ explicit facade call is
1901
+ <code>ttf.events.track(eventId, { pageUrl?, page?, orderHash? })</code>.
1902
+ The host owns when it fires, consent, deduplication and any additional
1903
+ analytics pixels. No 1.x pixel setup or automatic event equivalence
1904
+ should be assumed. Avoid sending unnecessary buyer data in URLs or
1905
+ analytics.</p>
1906
+ <h2 id="styling-and-localization">Styling and localization</h2>
1907
+ <p>Pass a <code>theme</code> to <code>EmbeddedCheckout</code>,
1908
+ <code>ResumedCheckout</code> or <code>CheckoutProvider</code>. All
1909
+ tokens are optional:</p>
1910
+ <table>
1911
+ <thead>
1912
+ <tr>
1913
+ <th>Group</th>
1914
+ <th><code>CheckoutTheme</code> keys</th>
1915
+ </tr>
1916
+ </thead>
1917
+ <tbody>
1918
+ <tr>
1919
+ <td>Scheme</td>
1920
+ <td><code>colorScheme: 'light' | 'dark'</code>; when omitted CSS follows
1921
+ the browser/OS preference.</td>
1922
+ </tr>
1923
+ <tr>
1924
+ <td>Colors</td>
1925
+ <td><code>accent</code>, <code>accentHover</code>,
1926
+ <code>accentContrast</code>, <code>surface</code>,
1927
+ <code>surfaceMuted</code>, <code>text</code>, <code>muted</code>,
1928
+ <code>border</code>, <code>error</code>, <code>success</code>.</td>
1929
+ </tr>
1930
+ <tr>
1931
+ <td>Shape</td>
1932
+ <td><code>radiusCard</code>, <code>radiusControl</code>,
1933
+ <code>shadow</code>.</td>
1934
+ </tr>
1935
+ <tr>
1936
+ <td>Type/layout</td>
1937
+ <td><code>font</code>, <code>fontSize</code>,
1938
+ <code>maxWidth</code>.</td>
1939
+ </tr>
1940
+ </tbody>
1941
+ </table>
1942
+ <p>Values are CSS strings mapped to <code>--tf-checkout-*</code> custom
1943
+ properties. The provider adds <code>.tf-checkout</code> and optionally
1944
+ <code>.tf-checkout--light</code> or <code>.tf-checkout--dark</code>;
1945
+ section classes use <code>tf-checkout-*</code>. Theme variables and
1946
+ classes can be overridden by your CSS, but test embedded Stripe iframes
1947
+ and third-party phone/seat-map styling separately. Stripe Elements do
1948
+ not inherit page CSS directly. Preserve readable contrast, visible focus
1949
+ and usable error states in custom themes.</p>
1950
+ <p><code>locale</code> defaults to <code>en-GB</code>; accepted
1951
+ <code>LocaleCode</code> values are <code>en-GB</code>,
1952
+ <code>en-US</code>, <code>es-MX</code>, <code>fr</code>,
1953
+ <code>de</code>, <code>ru</code>, and <code>id</code>. Catalogues can be
1954
+ partial and fall back to English; verify all buyer-facing copy for your
1955
+ event. Pass <code>messages</code> for per-key overrides, or use
1956
+ <code>I18nProvider</code> / <code>useT</code> around standalone
1957
+ components. Event-supplied content and provider pages may have their own
1958
+ language. Test keyboard navigation, screen readers, validation focus,
1959
+ small screens, reduced motion, popups, and the entire host page; an SDK
1960
+ control alone cannot guarantee accessibility of the surrounding
1961
+ experience.</p>
1962
+ <h2 id="migrating-from-1x">Migrating from 1.x</h2>
1963
+ <p>2.x is a new shared-core integration, not a prop-compatible update.
1964
+ Keep the existing 1.x integration pinned until the new flow and backend
1965
+ are verified. There is no automatic translation of old URLs, component
1966
+ props, account sessions or persisted 1.x state.</p>
1967
+ <table>
1968
+ <thead>
1969
+ <tr>
1970
+ <th>1.x integration</th>
1971
+ <th>2.0.0-beta.27 approach</th>
1972
+ </tr>
1973
+ </thead>
1974
+ <tbody>
1975
+ <tr>
1976
+ <td><code>setConfigs({ BASE_URL, ... })</code></td>
1977
+ <td><code>configureCheckout({ env</code> or <code>baseUrl</code>,
1978
+ <code>clientId</code>, <code>clientSecret: ''</code>, ...
1979
+ <code>})</code>; public client registration and session setup are
1980
+ required.</td>
1981
+ </tr>
1982
+ <tr>
1983
+ <td><code>TicketsContainer</code>, <code>SeatMapContainer</code>,
1984
+ <code>AddOnsContainer</code></td>
1985
+ <td><code>EmbeddedCheckout</code> or <code>Tickets</code>,
1986
+ <code>SeatMap</code>, <code>AddOns</code> under
1987
+ <code>CheckoutProvider</code>. Adapt callbacks and navigation.</td>
1988
+ </tr>
1989
+ <tr>
1990
+ <td><code>BillingInfoContainer</code>,
1991
+ <code>PaymentContainer</code></td>
1992
+ <td><code>BillingInfo</code> and <code>Payment</code> with matched
1993
+ policies and the current cart; or embedded flow. Old prop
1994
+ names/callbacks are not a contract.</td>
1995
+ </tr>
1996
+ <tr>
1997
+ <td><code>ConfirmationContainer</code></td>
1998
+ <td><code>Confirmation</code> for the active flow or
1999
+ <code>OrderConfirmation</code> for a reloadable order-hash page. Handle
2000
+ <code>pending</code> and ID verification.</td>
2001
+ </tr>
2002
+ <tr>
2003
+ <td>Legacy login/register/forgot-password modals</td>
2004
+ <td><code>AuthModal</code> or <code>hooks.useAuthFlow</code> and
2005
+ controlled forms. Distinguish event-scoped checkout identity from a full
2006
+ account session.</td>
2007
+ </tr>
2008
+ <tr>
2009
+ <td><code>AccountSettings</code></td>
2010
+ <td>No same-named drop-in replacement is established. Evaluate
2011
+ <code>AccountProfile</code>, <code>ProfileSettings</code>,
2012
+ <code>NotificationPreferences</code> and the account APIs against your
2013
+ required authorized account features.</td>
2014
+ </tr>
2015
+ <tr>
2016
+ <td><code>MyTicketsContainer</code>, order/detail and resale
2017
+ containers</td>
2018
+ <td>No same-named drop-in component in this version. Use supported
2019
+ account APIs/hooks and build the host UI after verifying authorization
2020
+ and deployed backend support.</td>
2021
+ </tr>
2022
+ <tr>
2023
+ <td>Webflow/no-code integration</td>
2024
+ <td>No 2.x drop-in Webflow or no-code checkout integration has been
2025
+ established. Integrate the React checkout in a compatible host or verify
2026
+ a separate integration with Ticket Fairy.</td>
2027
+ </tr>
2028
+ <tr>
2029
+ <td>Promo/access, waiting list, pixel and referral behavior</td>
2030
+ <td>Re-check catalog metadata, code/attribution precedence, waiting-list
2031
+ contract and explicit tracking. Do not infer numeric
2032
+ <code>?r=</code>.</td>
2033
+ </tr>
2034
+ <tr>
2035
+ <td>Legacy single-page state in localStorage</td>
2036
+ <td>Use the 2.x checkout store/engine and server cart; do not copy
2037
+ sensitive state or assume 1.x persisted state can be resumed.</td>
2038
+ </tr>
2039
+ </tbody>
2040
+ </table>
2041
+ <h3 id="migrating-layout-callbacks">Migrating layout callbacks</h3>
2042
+ <p>A callback name change can also change what the host receives. In
2043
+ particular, <code>onContinue</code> does not pass the old callback's
2044
+ response payload:</p>
2045
+ <table>
2046
+ <thead>
2047
+ <tr>
2048
+ <th>1.x usage</th>
2049
+ <th>2.x replacement</th>
2050
+ </tr>
2051
+ </thead>
2052
+ <tbody>
2053
+ <tr>
2054
+ <td><code>TicketsContainer</code>'s <code>getTicketsLabel</code></td>
2055
+ <td><code>Tickets</code>'s <code>buttonLabel</code>.</td>
2056
+ </tr>
2057
+ <tr>
2058
+ <td><code>TicketsContainer</code>'s
2059
+ <code>onAddToCartSuccess(data)</code></td>
2060
+ <td><code>Tickets.onContinue()</code> after reservation; read the
2061
+ current cart through <code>useCheckoutContext()</code> under the
2062
+ provider.</td>
2063
+ </tr>
2064
+ <tr>
2065
+ <td><code>BillingInfoContainer</code>'s
2066
+ <code>handleSubmit(values, helpers, eventId, response)</code></td>
2067
+ <td><code>BillingInfo.onContinue()</code> after validation and save;
2068
+ read the current billing and holders from the checkout context. Omit the
2069
+ callback for combined-form behavior.</td>
2070
+ </tr>
2071
+ <tr>
2072
+ <td><code>AddOnsContainer</code> timer</td>
2073
+ <td>Render <code>TimerBanner</code> with
2074
+ <code>useCheckoutContext().secondsLeft</code> in the host layout.</td>
2075
+ </tr>
2076
+ <tr>
2077
+ <td>Separate 1.x page URLs and localStorage state</td>
2078
+ <td>Keep the 2.x provider mounted across host steps; implement
2079
+ route/refresh handling and verify any existing server cart in the
2080
+ current session.</td>
2081
+ </tr>
2082
+ </tbody>
2083
+ </table>
2084
+ <p>These are migration starting points, not prop-compatible aliases. In
2085
+ 2.x <code>eventId</code> is a string; convert a numeric ID before
2086
+ passing it. Old Material UI theme options, callback payloads and
2087
+ optional page behavior need explicit host work. For the two complete
2088
+ flows see <a href="#choose-a-checkout-layout">Choose a checkout
2089
+ layout</a>; for single-page and stepped alternatives see <a
2090
+ href="#compose-sections">Compose sections</a>.</p>
2091
+ <p>Compare the exact event's ticket types, dated pricing, seats,
2092
+ add-ons, holder questions, conditional fields, consent, waivers, fees,
2093
+ currencies, payment methods, account and post-purchase behavior before
2094
+ switching. Backend rollout and provider acceptance are independent of
2095
+ the npm package publication.</p>
2096
+ <p>The distribution includes standalone widget JavaScript and CSS
2097
+ bundles for other product surfaces. Their presence alone does not
2098
+ establish a supported public checkout-widget API or a 2.x Webflow
2099
+ integration; use the documented React exports unless a separate
2100
+ integration contract has been verified.</p>
2101
+ <h2 id="testing-and-troubleshooting">Testing and troubleshooting</h2>
2102
+ <p>Use a non-production event and provider test configuration. Exercise
2103
+ at least:</p>
2104
+ <ol type="1">
2105
+ <li>A general-admission purchase, free registration, multi-quantity
2106
+ holders, required and unavailable add-ons, custom questions and waiver;
2107
+ inspect server-priced totals before payment.</li>
2108
+ <li>Seated/time-slot and multi-currency events if used; expiry, sold-out
2109
+ changes, promo/access codes, explicit referral attribution and
2110
+ waiting-list states.</li>
2111
+ <li>Guest, existing-account, sign-in, two-factor and
2112
+ sign-out/buyer-switch flows; verify no prior buyer's cart or private
2113
+ data is shown to the next buyer.</li>
2114
+ <li>Every enabled provider: success, decline, cancellation, blocked
2115
+ popup, redirect return, offline/timeout and asynchronous pending
2116
+ settlement. Check the authoritative order/provider before any retry or
2117
+ fulfilment.</li>
2118
+ <li>Refresh, back navigation, multiple clicks, a delayed response,
2119
+ small-screen and keyboard/screen-reader flows. Test on the actual
2120
+ supported browsers, configured origins and deployment environment.</li>
2121
+ </ol>
2122
+ <table>
2123
+ <thead>
2124
+ <tr>
2125
+ <th>Symptom</th>
2126
+ <th>Check</th>
2127
+ </tr>
2128
+ </thead>
2129
+ <tbody>
2130
+ <tr>
2131
+ <td>"SDK is not configured"</td>
2132
+ <td>Run <code>configureCheckout</code> before mounting any SDK component
2133
+ or calling <code>ttf</code>.</td>
2134
+ </tr>
2135
+ <tr>
2136
+ <td>Query context error</td>
2137
+ <td>Wrap the relevant tree in a <code>QueryClientProvider</code> using
2138
+ the same React Query instance as the SDK.</td>
2139
+ </tr>
2140
+ <tr>
2141
+ <td>No styles / CSS build error</td>
2142
+ <td>Confirm the bundler processes package CSS, nested
2143
+ <code>@import</code>s and assets. Check the package entry and stylesheet
2144
+ export.</td>
2145
+ </tr>
2146
+ <tr>
2147
+ <td>Login fails or popup closes</td>
2148
+ <td>Verify the public client, event, deployed auth route, secure browser
2149
+ crypto, popup permission, origin/cookie/CORS settings and any required
2150
+ proof step.</td>
2151
+ </tr>
2152
+ <tr>
2153
+ <td>Cart or pricing missing</td>
2154
+ <td>Verify the event/environment, current ticket IDs, availability,
2155
+ session, network response and that reservation completed. Re-fetch after
2156
+ a code or currency change.</td>
2157
+ </tr>
2158
+ <tr>
2159
+ <td>No seat button</td>
2160
+ <td>The event must offer seating; a composed <code>Tickets</code> needs
2161
+ <code>onSelectSeats</code> connected to a <code>SeatMap</code>
2162
+ view.</td>
2163
+ </tr>
2164
+ <tr>
2165
+ <td>Pay is disabled / validation error</td>
2166
+ <td>Check buyer and holder rules, required add-ons/answers/conditions,
2167
+ privacy acknowledgement, waiver state and cart expiry. Use matching
2168
+ billing and payment policies.</td>
2169
+ </tr>
2170
+ <tr>
2171
+ <td>Payment method unavailable</td>
2172
+ <td>Check the event's returned method list,
2173
+ merchant/currency/device/provider setup, popup/CSP and backend rollout.
2174
+ A union member alone does not enable a rail.</td>
2175
+ </tr>
2176
+ <tr>
2177
+ <td>Payment is pending or outcome uncertain</td>
2178
+ <td>Show the pending state, retain the order and reconcile with the
2179
+ backend/provider. Do not blindly reset, charge again or fulfil.</td>
2180
+ </tr>
2181
+ <tr>
2182
+ <td>Private account data is unavailable</td>
2183
+ <td>A public checkout buyer session is narrower than a full account
2184
+ session; verify the account journey and authority.</td>
2185
+ </tr>
2186
+ </tbody>
2187
+ </table>
2188
+ <p>Only public/non-secret configuration belongs in client bundles,
2189
+ example <code>.env</code> files and browser logs. Order hashes, buyer
2190
+ data and provider responses should be handled as sensitive application
2191
+ data.</p>
2192
+ </main>
2193
+ </body>
2194
+ </html>