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

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