tf-checkout-react-native 2.0.0-beta.24 → 2.0.0-beta.26

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.
Files changed (3) hide show
  1. package/README.md +368 -49
  2. package/docs/API.md +69 -17
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,21 +5,73 @@ tickets. Start with `EmbeddedCheckout`, compose individual sections, or own the
5
5
  presentation using `useCheckout` and the shared API. The package includes its
6
6
  private shared core; hosts do not install `tf-checkout-shared`.
7
7
 
8
- This reference is for **`tf-checkout-react-native@2.0.0-beta.24`**, a
8
+ This reference is for **`tf-checkout-react-native@2.0.0-beta.26`**, a
9
9
  prerelease with a different API from 1.x (including its `CheckoutV2`). Pin the
10
10
  version: `latest` and `beta` tags can move; check `npm view tf-checkout-react-native dist-tags`.
11
- The [API reference](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.24/docs/API.md)
12
- covers components and hooks; the [declarations](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.24/dist/index.d.ts)
13
- contain all types. The [web package](https://www.npmjs.com/package/tf-checkout-react/v/2.0.0-beta.24)
11
+ The [API reference](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/docs/API.md)
12
+ covers components and hooks; the [declarations](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/dist/index.d.ts)
13
+ contain all types. The [web package](https://www.npmjs.com/package/tf-checkout-react/v/2.0.0-beta.26)
14
14
  shares the engine but has different UI and ports. Availability depends on the
15
15
  backend, event, gateway, account and device; installation does not establish
16
16
  hosted-checkout parity or payment acceptance.
17
17
 
18
+ ## Choose a ready-made layout
19
+
20
+ The SDK supplies native UI for the checkout steps. Start with the complete
21
+ checkout unless your app needs to control the screens and navigation itself.
22
+
23
+ | I want to… | Use | Where to start |
24
+ | --- | --- | --- |
25
+ | Add a complete checkout | `EmbeddedCheckout` | [Quick start](#requirements-and-installation) |
26
+ | Show ticket selection, seats, buyer details and payment on my own screens | `CheckoutProvider` with the ready-made sections | [Compose sections](#compose-sections-and-navigation) |
27
+ | Add sign-in, registration and recovery | `AuthModal` or individual forms | [Authentication sheet](#a-reusable-authentication-sheet) |
28
+ | Let a buyer change, gift or request a refund for a ticket | `TicketChange`, `TicketGift`, `TicketRefund` | [Ticket management screens](#ticket-management-screens) |
29
+ | Show passes, rewards or account settings | Ready-made account and post-purchase sections | [Screen directory](#ready-made-screens-and-flows) |
30
+
31
+ For example, after you [restore storage and configure the SDK](#initialize-secure-storage-and-configure),
32
+ this renders the complete checkout. Do not mount it until initialization has
33
+ finished. `EmbeddedCheckout` creates its own `CheckoutProvider` and React Query
34
+ client for the checkout; hooks used elsewhere need their own
35
+ `QueryClientProvider`.
36
+
37
+ ```tsx
38
+ import { EmbeddedCheckout, type PlaceOrderResult } from 'tf-checkout-react-native'
39
+
40
+ export function CheckoutScreen({ eventId, onComplete }: {
41
+ eventId: string
42
+ onComplete: (order: PlaceOrderResult) => void
43
+ }) {
44
+ return <EmbeddedCheckout eventId={eventId} confirmationMode="redirect"
45
+ onComplete={onComplete} />
46
+ }
47
+ ```
48
+
49
+ The host owns the order-status route and must reconcile payment before showing
50
+ a paid receipt or fulfilling an order. Follow the setup below before mounting
51
+ this component. The [migration guide](#migration-from-1x) maps the former
52
+ native layouts to the available beta components and calls out missing screens.
53
+
54
+ ## Quick start at a glance
55
+
56
+ 1. [Install the SDK and native peers](#requirements-and-installation), then
57
+ build an Expo development client or a bare native app.
58
+ 2. [Restore credential storage and configure the SDK](#initialize-secure-storage-and-configure).
59
+ Create the two named files shown there, using a **staging** client ID.
60
+ 3. [Mount the complete checkout](#embed-a-checkout) with your test event ID.
61
+ The example waits for setup and handles the order result.
62
+ 4. Run the app on a supported device or simulator. The ticket list should load
63
+ for an available test event; if it does not, see [troubleshooting](#testing-and-troubleshooting).
64
+
65
+ Ask your Ticket Fairy integration contact for a public SDK client ID, the test
66
+ environment and an event configured for your integration. Never put a client
67
+ secret or provider secret key in the app.
68
+
18
69
  ## Contents
19
70
 
20
71
  - [Requirements and installation](#requirements-and-installation)
21
72
  - [Initialize secure storage and configure](#initialize-secure-storage-and-configure)
22
73
  - [Embed a checkout](#embed-a-checkout)
74
+ - [Ready-made screens and flows](#ready-made-screens-and-flows)
23
75
  - [Compose sections and navigation](#compose-sections-and-navigation)
24
76
  - [Checkout section reference](#checkout-section-reference)
25
77
  - [Tickets, seats, codes and attribution](#tickets-seats-codes-and-attribution)
@@ -34,6 +86,10 @@ hosted-checkout parity or payment acceptance.
34
86
 
35
87
  ## Requirements and installation
36
88
 
89
+ Choose the installation command for your app below. Both paths require a
90
+ native build; installing the JavaScript package alone does not add native
91
+ modules to an existing binary.
92
+
37
93
  The package declares Node `>=20.19.4`, React `>=19.1`, React Native `>=0.81`,
38
94
  `@tanstack/react-query >=5`, `@stripe/stripe-react-native >=0.45.0`,
39
95
  `@react-native-clipboard/clipboard >=1.14.0`, `react-native-webview >=13.15.0`,
@@ -49,7 +105,7 @@ identify duplicates.
49
105
  For an Expo project with compatible React and RN versions:
50
106
 
51
107
  ```sh
52
- npx expo install tf-checkout-react-native@2.0.0-beta.24 \
108
+ npx expo install tf-checkout-react-native@2.0.0-beta.26 \
53
109
  @tanstack/react-query @stripe/stripe-react-native \
54
110
  @react-native-clipboard/clipboard react-native-webview \
55
111
  react-native-render-html@6.3.4 expo-secure-store
@@ -76,13 +132,13 @@ using your normal process. For a bare React Native app, install the peers in
76
132
  the app (React and React Native are normally already present):
77
133
 
78
134
  ```sh
79
- npm install tf-checkout-react-native@2.0.0-beta.24 @tanstack/react-query \
135
+ npm install tf-checkout-react-native@2.0.0-beta.26 @tanstack/react-query \
80
136
  @stripe/stripe-react-native @react-native-clipboard/clipboard \
81
137
  react-native-webview react-native-render-html@6.3.4
82
138
  ```
83
139
 
84
140
  Configure autolinking and Stripe's native setup, run `pod install` in the iOS
85
- directory, and rebuild both platforms. Provide a Keychain/Keystore-backed
141
+ directory, and rebuild each platform you support. Provide a Keychain/Keystore-backed
86
142
  storage adapter using a native library appropriate to the host. Consult the
87
143
  [Stripe React Native setup](https://docs.stripe.com/payments/accept-a-payment?platform=react-native)
88
144
  and [Expo SecureStore documentation](https://docs.expo.dev/versions/latest/sdk/securestore/)
@@ -108,12 +164,17 @@ code. Obtain a public SDK client ID authorized for the integration and use an
108
164
  empty `clientSecret` for public checkout; do not substitute a confidential
109
165
  credential. Environment variables compiled into an app are visible to its users.
110
166
 
111
- The SDK reads storage synchronously. The following Expo example asynchronously
112
- restores one protected snapshot first, then makes each subsequent OS write
113
- synchronously *before* publishing the new in-memory snapshot. The methods are
167
+ Create `credentialStorage.ts`. The SDK reads storage synchronously; this Expo
168
+ example asynchronously restores one protected snapshot first, then makes each
169
+ subsequent OS write synchronously *before* publishing the new in-memory snapshot. The methods are
114
170
  not `async` and a failed write throws instead of reporting success. Replace the
115
171
  namespace with an app-owned, environment-specific key.
116
172
 
173
+ For a bare React Native app without Expo modules, implement the same
174
+ `StorageAdapter` with your app's Keychain/Keystore-backed storage instead. Do
175
+ not copy the Expo-specific example unless Expo SecureStore is installed and
176
+ configured in that app.
177
+
117
178
  ```ts
118
179
  // credentialStorage.ts
119
180
  import * as SecureStore from 'expo-secure-store'
@@ -154,6 +215,9 @@ corrupt snapshot or unavailable OS store must be handled explicitly; do not
154
215
  silently report durable sign-in. Migrate old credentials securely or require
155
216
  sign-in again.
156
217
 
218
+ Next create `checkoutSetup.ts`. This example uses staging; switch to a
219
+ production public SDK client ID, event and storage namespace for production.
220
+
157
221
  ```ts
158
222
  // checkoutSetup.ts
159
223
  import { configureCheckout } from 'tf-checkout-react-native'
@@ -163,9 +227,9 @@ let initialization: Promise<void> | undefined
163
227
  export function prepareCheckout(): Promise<void> {
164
228
  if (!initialization) {
165
229
  initialization = (async () => {
166
- const storage = await restoreCredentialStorage('my_app_checkout_prod')
230
+ const storage = await restoreCredentialStorage('my_app_checkout_staging')
167
231
  configureCheckout({
168
- env: 'PROD',
232
+ env: 'STAG',
169
233
  clientId: 'YOUR_PUBLIC_SDK_CLIENT_ID',
170
234
  clientSecret: '',
171
235
  storage,
@@ -200,7 +264,9 @@ access. Do not infer full account authorization from checkout authentication.
200
264
 
201
265
  Mount only after `prepareCheckout` resolves. `EmbeddedCheckout` provides its own
202
266
  `CheckoutProvider` and React Query client. Any separate React Query hooks outside
203
- that subtree need a `QueryClientProvider` of their own.
267
+ that subtree need a `QueryClientProvider` of their own. Put this component in
268
+ `App.tsx` or your checkout screen, and replace `YOUR_EVENT_ID` with an event in
269
+ the same environment as your client ID.
204
270
 
205
271
  ```tsx
206
272
  import React, { useEffect, useState } from 'react'
@@ -240,6 +306,12 @@ export default function EventCheckout() {
240
306
  }
241
307
  ```
242
308
 
309
+ After launching the native app, the event's ticket-selection screen should
310
+ appear. Select a test ticket to reach buyer details and payment. If the catalog
311
+ does not load, check the event, client ID and environment before trying a real
312
+ payment. The example returns the order reference to the host; it does not
313
+ implement an order-status service.
314
+
243
315
  `onComplete` is an order result, not proof of settled payment. `pending: true`
244
316
  requires pending instructions, but `pending !== true` also does not prove
245
317
  capture or settlement. `confirmationMode="inline"` (default) shows the stock
@@ -247,8 +319,9 @@ receipt, which can say tickets are confirmed for a non-pending order before
247
319
  final capture/settlement. Hosts requiring verified paid status should use
248
320
  `"redirect"` or custom UI and reconcile with the authoritative backend and
249
321
  provider before presenting that status or fulfilling. Redirect mode delegates
250
- routing to `onComplete` and keeps checkout mounted during handoff; the host owns
251
- navigation. The example shows a local fallback, not a complete status screen:
322
+ routing to `onComplete` and keeps checkout mounted during handoff; provide that
323
+ callback to navigate, or no host status screen is reached. The example
324
+ shows a local fallback, not a complete status screen:
252
325
  the host must implement reconciliation, retain the order reference and voucher
253
326
  across its navigation/restart, and arrange verification when required. Validate
254
327
  provider URLs against the host's policy before opening them.
@@ -284,6 +357,161 @@ base64 encoding and the image signature, the 2 MiB maximum and any supplied
284
357
  dimensions (at most 4096 pixels per side); the server validates decoded bytes.
285
358
  The host owns permission and picker UX. For the separate event discussion picker, see its props below.
286
359
 
360
+ ## Ready-made screens and flows
361
+
362
+ The SDK has one complete checkout layout, `EmbeddedCheckout`. Its `initialView`
363
+ chooses tickets or seats, and `confirmationMode` chooses an inline receipt or
364
+ host-owned navigation. It also exposes the sections below so you can put them
365
+ on your own screens. These are native React components, not HTML or WebViews
366
+ except where the seat map or a payment provider needs one.
367
+
368
+ | Screen or task | Ready-made components | Setup |
369
+ | --- | --- | --- |
370
+ | Ticket selection and seating | `Tickets`, `SeatMap`, `Bundles` | Put them under one `CheckoutProvider`; pass `eventId`. Connect the tickets callbacks to your navigation. |
371
+ | Checkout details | `AddOns`, `Accommodation`, `BillingInfo`, `WaiverSigning`, `OrderSummary`, `Payment` | Use the same provider and reserved cart. Match billing and payment validation props. |
372
+ | Verify or display a result | `IDVerification`, `Confirmation`, `Rewards` | Verification and confirmation read the active checkout; use an authoritative host status before showing confirmed copy. |
373
+ | Sign in or recover a password | `AuthModal`, `LoginForm`, `RegisterForm`, `ForgotPasswordForm`, `ResetPasswordForm`, `TwoFactorForm`, `EmailCodeForm`, `PhoneAuthentication` | Configure the SDK first. Use the modal for a complete sheet or the forms with a host-owned flow. |
374
+ | Change, gift or request a refund | `TicketChange`, `TicketGift`, `TicketRefund` | Provide a ticket hash and the required buyer/session authority. See the [example below](#ticket-management-screens). |
375
+ | Passes and rewards | `Passes`, `Rewards`, `RewardsLadder`, `RewardsTree`, `AccountRewardsSection` | Use the appropriate signed-in account or order context; eligibility comes from the server. |
376
+ | Account settings and order information | `ProfileSettings`, `NotificationPreferences`, `AccountDeletion`, `AccountInformationSection`, `AccountPaymentPlanSection`, `Streaming`, `Trips`, `AccountEmailEnrichment` | Configure account access and a query provider; the host owns navigation and any required handoff. |
377
+ | Discussion and reactions | `EventDiscussionView`, `PostReaction`, `PostReactionControls`, `PostReactionFeedback` | Supply the required event/discussion or post/flow and authorized session. |
378
+
379
+ `AccountDeletionView`, `ProfileSettingsView`, `NotificationPreferencesView` and
380
+ `StreamingView` are controlled variants: use them when your host already owns
381
+ the corresponding flow. The ordinary component creates that flow for you. See
382
+ the [component API reference](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/docs/API.md#account-and-post-purchase-components)
383
+ for required props and variants.
384
+
385
+ There is no native `MyOrders`, `MyOrderDetails`, `ResaleTickets`, `CheckoutSP`,
386
+ `CheckoutV2` or `ResumedCheckout` layout exported in this version. The
387
+ [migration table](#migration-from-1x) explains what can be composed and what the
388
+ host must build.
389
+
390
+ ### A reusable authentication sheet
391
+
392
+ The complete `EmbeddedCheckout` already opens its built-in sign-in sheet. Use
393
+ `AuthModal` separately when your app owns the sign-in button or wants to show
394
+ the sheet elsewhere. Run `prepareCheckout()` from the quick start before
395
+ mounting this example. Here `checkoutEventId` requests the event-scoped
396
+ checkout sign-in; it is not a full account session.
397
+
398
+ ```tsx
399
+ import React, { useState } from 'react'
400
+ import { Button, Text, View } from 'react-native'
401
+ import { AuthModal, CheckoutProvider } from 'tf-checkout-react-native'
402
+
403
+ export function CheckoutSignIn({ eventId }: { eventId: string }) {
404
+ const [open, setOpen] = useState(false)
405
+ const [notice, setNotice] = useState('')
406
+ return (
407
+ <CheckoutProvider>
408
+ <View>
409
+ <Button title="Sign in for checkout" onPress={() => setOpen(true)} />
410
+ <Text>{notice}</Text>
411
+ <AuthModal open={open} onClose={() => setOpen(false)}
412
+ checkoutEventId={eventId}
413
+ onCheckoutAuthenticated={() => setNotice('Checkout sign-in complete.')} />
414
+ </View>
415
+ </CheckoutProvider>
416
+ )
417
+ }
418
+ ```
419
+
420
+ `open` and `onClose` control the sheet. `allowRegistration` and
421
+ `allowPasswordReset` default to true; `initialEmail` and `logoUrl` customize it.
422
+ For a separately authorized account flow, omit `checkoutEventId`, configure
423
+ the supported account journey and use `onAuthenticated`. If the screen is
424
+ already under your checkout's provider, render `AuthModal` inside that provider
425
+ instead of adding another one.
426
+
427
+ ### Complete a password reset
428
+
429
+ `AuthModal` starts password recovery. Your app handles the reset link and passes
430
+ its token to `ResetPasswordForm`. Configure the SDK before mounting this route;
431
+ the form submits the new password and can offer a way back to sign-in.
432
+
433
+ ```tsx
434
+ import React from 'react'
435
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
436
+ import { CheckoutThemeProvider, ResetPasswordForm } from 'tf-checkout-react-native'
437
+
438
+ const queryClient = new QueryClient()
439
+
440
+ export function PasswordResetScreen({ token, openSignIn }: {
441
+ token: string
442
+ openSignIn: () => void
443
+ }) {
444
+ return <QueryClientProvider client={queryClient}>
445
+ <CheckoutThemeProvider>
446
+ <ResetPasswordForm token={token} onBackToLogin={openSignIn} />
447
+ </CheckoutThemeProvider>
448
+ </QueryClientProvider>
449
+ }
450
+ ```
451
+
452
+ Use your existing query provider if one is already mounted. Handle expired or
453
+ missing links in the host and do not log the reset token.
454
+
455
+ ### Ticket management screens
456
+
457
+ After SDK setup and an authorized buyer session, the following component can
458
+ render one ready-made change, gift, refund or pass screen on a host-owned route.
459
+ Use a current ticket hash from an authorized order. The host owns navigation
460
+ and must refresh its own ticket list after a change. A refund submission is a
461
+ request, not proof the refund has completed.
462
+
463
+ ```tsx
464
+ import React from 'react'
465
+ import { ScrollView } from 'react-native'
466
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
467
+ import {
468
+ CheckoutThemeProvider, Passes, TicketChange, TicketGift, TicketRefund,
469
+ } from 'tf-checkout-react-native'
470
+
471
+ const queryClient = new QueryClient()
472
+
473
+ export function TicketTools({ ticketHash, orderHash, screen, onDone }: {
474
+ ticketHash: string
475
+ orderHash?: string
476
+ screen: 'change' | 'gift' | 'refund'
477
+ onDone: () => void
478
+ }) {
479
+ return (
480
+ <QueryClientProvider client={queryClient}>
481
+ <CheckoutThemeProvider>
482
+ <ScrollView>
483
+ {screen === 'change' && <TicketChange ticketHash={ticketHash}
484
+ orderHash={orderHash} onChanged={onDone} />}
485
+ {screen === 'gift' && <TicketGift ticketHash={ticketHash}
486
+ onDone={onDone} />}
487
+ {screen === 'refund' && <TicketRefund ticketHash={ticketHash}
488
+ onDone={onDone} />}
489
+ </ScrollView>
490
+ </CheckoutThemeProvider>
491
+ </QueryClientProvider>
492
+ )
493
+ }
494
+
495
+ export function MyPasses() {
496
+ return <QueryClientProvider client={queryClient}>
497
+ <CheckoutThemeProvider><Passes /></CheckoutThemeProvider>
498
+ </QueryClientProvider>
499
+ }
500
+ ```
501
+
502
+ `TicketChange` accepts `orderHash` for a supported guest order link and can
503
+ open a hosted page for a paid change. `TicketGift` and `TicketRefund` do not
504
+ accept that prop; check their own authorization and server eligibility. In an
505
+ existing app use its query client instead of creating another provider, and
506
+ clear or scope private query data when the buyer signs out or changes. Coordinate
507
+ host navigation with in-flight actions and check authoritative status on return;
508
+ do not treat leaving a screen as proof that a request did or did not complete.
509
+ In this example `onDone` is host navigation, not a success signal: the gift
510
+ screen can offer its exit before a gift is sent. Use `TicketGift`'s
511
+ `onTicketsChanged` and `TicketRefund`'s `onSubmitted` for their respective
512
+ notifications. `TicketChange.onChanged` runs on Back after a completed
513
+ no-payment change; reconcile a paid change after returning from its hosted page.
514
+
287
515
  ## Compose sections and navigation
288
516
 
289
517
  `CheckoutProvider` owns a native `useCheckout()` instance, a query provider,
@@ -292,12 +520,23 @@ it share the app checkout store. `useCheckoutContext()` reads this instance and
292
520
  throws outside the provider. The following intentionally uses one combined
293
521
  billing/payment form after reservation; callbacks route tickets and seats.
294
522
 
523
+ This is a wiring recipe, not a complete navigation flow. It includes a return
524
+ from the seat view and keeps `Tickets` mounted while switching views. The host
525
+ still needs to implement Edit and Back from checkout, preserve entered details,
526
+ handle seat holds and cart expiry, and guard event/session changes and in-flight
527
+ or retained payments. Use `EmbeddedCheckout` for its built-in Back and guarded
528
+ Edit behavior.
529
+ The seat-view Back button only changes views: it does not itself release reserved
530
+ seats or cancel an already-started reservation or cart priming. Coordinate any
531
+ in-flight work and the hold's expiry or release under your deployed backend
532
+ contract before permitting a conflicting selection.
533
+
295
534
  ```tsx
296
535
  import React, { useState } from 'react'
297
- import { ScrollView, Text, View } from 'react-native'
536
+ import { Button, ScrollView, Text, View } from 'react-native'
298
537
  import {
299
538
  CheckoutProvider, Tickets, SeatMap, AddOns, BillingInfo, WaiverSigning,
300
- OrderSummary, Payment, IDVerification, useCheckoutContext,
539
+ Payment, useCheckoutContext,
301
540
  type PlaceOrderResult,
302
541
  } from 'tf-checkout-react-native'
303
542
 
@@ -312,22 +551,24 @@ function Flow({ eventId, onComplete }: {
312
551
  <Text>Order submitted: {checkout.order.orderHash}. Check payment status.</Text>
313
552
  {checkout.order.pending && <Text>Payment pending.</Text>}
314
553
  {checkout.order.pendingVoucherUrl && <Text selectable>{checkout.order.pendingVoucherUrl}</Text>}
315
- <IDVerification />
554
+ {checkout.order.needIdVerification && <Text>Identity verification is required.</Text>}
316
555
  </View>
317
556
  )
318
557
  return (
319
558
  <ScrollView keyboardShouldPersistTaps="handled">
320
- {view === 'tickets' && <Tickets eventId={eventId}
321
- onSelectSeats={() => setView('seats')}
322
- onContinue={() => setView('checkout')} />}
323
- {view === 'seats' && <SeatMap eventId={eventId}
324
- onContinue={() => setView('checkout')} />}
559
+ <View style={view === 'tickets' ? undefined : { display: 'none' }}>
560
+ <Tickets eventId={eventId} onSelectSeats={() => setView('seats')}
561
+ onContinue={() => setView('checkout')} />
562
+ </View>
563
+ {view === 'seats' && <View>
564
+ <Button title="Back to tickets" onPress={() => setView('tickets')} />
565
+ <SeatMap eventId={eventId} onContinue={() => setView('checkout')} />
566
+ </View>}
325
567
  {view === 'checkout' && <>
326
568
  <AddOns eventId={eventId} />
327
569
  <BillingInfo eventId={eventId} requireEmailConfirmation
328
570
  collectTicketHolders collectHolderContact />
329
571
  <WaiverSigning eventId={eventId} />
330
- <OrderSummary eventId={eventId} />
331
572
  <Payment requireEmailConfirmation collectTicketHolders requireHolderContact
332
573
  onComplete={onComplete} />
333
574
  </>}
@@ -348,10 +589,13 @@ navigation transition depend solely on its `onContinue` unless your host handles
348
589
  that case. With no `onContinue`, `AddOns` and `BillingInfo` use combined-form
349
590
  behavior. Match `BillingInfo`'s email/holder policy to `Payment`'s
350
591
  `requireEmailConfirmation`, `collectTicketHolders` and `requireHolderContact`.
351
- The composed example renders the verification control for a required order;
352
- the buyer must press Verify. Before changing event, leaving payment or starting
353
- another cart, handle in-flight and retained orders as described under
354
- [safe completion](#payments-and-safe-completion).
592
+ The composed example only shows neutral verification-required text: your host
593
+ must arrange the verification and status journey. If its parent `onComplete`
594
+ navigates away or unmounts this component, even that inline status view will
595
+ not appear. Keep the active provider mounted for an inline flow, or handle
596
+ verification and authoritative order status at the destination. Before changing
597
+ event, leaving payment or starting another cart, handle in-flight and retained
598
+ orders as described under [safe completion](#payments-and-safe-completion).
355
599
 
356
600
  `CheckoutProvider` props: `children` (required), `theme`, `pickImage`,
357
601
  `options` (wallet/redirect `CheckoutOptions`), `paymentSheet`, `queryClient`,
@@ -429,12 +673,21 @@ required fields. All props are optional:
429
673
 
430
674
  | Component | Props and behavior |
431
675
  | --- | --- |
432
- | `OrderSummary` | `eventId?`, `locale?`, `messages?`, `translate?`. Displays server-priced cart totals and optional event name. |
676
+ | `OrderSummary` | `eventId?`, `locale?`, `messages?`, `translate?`. Displays server-priced cart totals and optional event name. `Payment` already renders it; use it separately when you need a summary elsewhere. |
433
677
  | `WaiverSigning` | **`eventId`**; `locale?`, `messages?`, `translate?`. Renders only when the event has a waiver; supports the server-offered signing methods. |
434
678
  | `Payment` | `onComplete?(order)`, `eventId?` (currently unused by native payment), `requireEmailConfirmation?`, `collectTicketHolders?`, `requireHolderContact?`, `additionalConditions?`, `requirePrivacyPolicy?`, `onPrivacyRequired?`, `showTestCardHint?`, `locale?`, `messages?`, `translate?`. Standalone boolean defaults are false. It validates, renders eligible methods and submits. |
435
- | `IDVerification` | No props. When required, it shows a Verify button; the buyer must press it to open and poll the provider. A stall proves neither failure nor settlement. |
679
+ | `IDVerification` | No props. When required, it shows a Verify button; the buyer must press it to open and poll the provider. Its verified text says tickets are on their way without checking settlement or issuance. |
436
680
  | `Confirmation` | `shareUrl?`, `shareMessage?`, `viewOrderUrl?`, `message?`, `children?`. Reads the current order. Its stock title and share copy do not independently verify payment settlement or referral eligibility; see below. |
437
681
 
682
+ The stock `IDVerification` verified message says tickets are on their way, but
683
+ verification alone does not establish payment settlement or ticket issuance.
684
+ Use a host-owned verification/status UI around `runIdVerification(orderHash, options)`
685
+ when neutral copy is required, and reconcile the authoritative order/provider
686
+ status. If `onComplete` navigates away, handle verification at the destination;
687
+ unmounting the checkout prevents its inline verification view from appearing.
688
+ See [host-owned ID verification](#host-owned-id-verification) for URL opening,
689
+ return handling and neutral error copy.
690
+
438
691
  `Payment` gates its rendered event conditions, host `additionalConditions` and
439
692
  requested privacy acknowledgment in its UI. Each `EventCondition` is
440
693
  `{ id: string, name: string, content: string, isRequired: boolean }`. These
@@ -540,7 +793,7 @@ and email-confirmation defaults; match it with the paired `Payment` props. The
540
793
  SDK's confirmation email value is a UI check; the order API uses the primary
541
794
  email. Recheck terms, privacy and marketing consent with your own policy.
542
795
 
543
- **Beta.23 consent limitation:** when `privacyPolicy` is supplied, the stock
796
+ **Consent limitation:** when `privacyPolicy` is supplied, the stock
544
797
  privacy checkbox reads and writes `consent.ttfOptIn`, which the order sends as
545
798
  `ttf_opt_in`. It is not independent of the Ticket Fairy marketing flag. The
546
799
  brand opt-in uses a separate value. If both opt-in labels are explicitly empty,
@@ -554,8 +807,10 @@ is required, use a custom flow and a tested backend consent contract.
554
807
  During cart priming, failed custom-field, checkout-config, add-on or event
555
808
  condition reads fall back to empty/default data. The stock UI cannot show or
556
809
  gate requirements it did not load. Only a failed waiver read (except a 404) is
557
- recorded in `unavailableDetails` and retried/gated. Do not treat an empty list as
558
- proof that no requirement exists; verify deployment/failure behavior and add
810
+ recorded in `unavailableDetails`. Before money may have moved, placement retries
811
+ an unavailable waiver and blocks if it remains unknown; a retained order with a
812
+ possible payment follows separate recovery and needs reconciliation. Do not treat
813
+ an empty list as proof that no requirement exists; verify failure behavior and add
559
814
  tested host safeguards for mandatory fields and acknowledgments. Server
560
815
  validation of required answers is not proof that a condition was acknowledged.
561
816
 
@@ -588,9 +843,9 @@ redirect routing when your fulfillment policy requires verified payment.
588
843
  When `needIdVerification` is true, the host must arrange a separate verification
589
844
  journey. Inline `IDVerification` requires the buyer to press Verify; redirect
590
845
  mode does not render it. A composed host can render `IDVerification` under the
591
- active `CheckoutProvider`, or call `runIdVerification(orderHash)` from a custom
592
- flow. Handle navigation/returns; a failed or delayed verification proves neither
593
- payment failure nor settlement.
846
+ active `CheckoutProvider`, or call `runIdVerification(orderHash, options)` from a custom
847
+ flow with the host URL opener described below. Handle navigation/returns; a
848
+ failed or delayed verification proves neither payment failure nor settlement.
594
849
 
595
850
  **Zero-total orders:** this SDK ignores the free-registration response body and
596
851
  reports `needIdVerification: false`. Verification or approval may still be
@@ -614,20 +869,37 @@ is not an exactly-once charging guarantee across every host/provider.
614
869
  `reset()` starts a reset and returns no completion signal. Prefer
615
870
  `await resetWhenSettled()` when navigating to a new checkout: it waits for an
616
871
  in-flight payment and returns `true` only if reset completed. `false` can mean
617
- the original order is retained or the checkout was retired. Show
618
- `PAID_ORDER_PENDING_MESSAGE` where appropriate and reconcile; do not clear the
619
- store, start a new order or promise a refund merely to bypass this guard. A
620
- custom `providerPage` must settle on close/unmount with `{ event: 'dismiss' }`;
621
- other custom async ports must settle too, or reset can wait indefinitely.
872
+ the original order is retained or the checkout was retired; the result does not
873
+ identify which. Show neutral guidance and check the current session and the
874
+ authoritative order and provider status before choosing recovery.
875
+ `PAID_ORDER_PENDING_MESSAGE` tells the buyer to press Pay again; a `false`
876
+ result alone is not enough to use that instruction or establish a safe retry.
877
+ Do not clear the store, start a new order or promise a refund merely to bypass
878
+ this guard. A custom `providerPage` must settle on close/unmount with
879
+ `{ event: 'dismiss' }`; other custom async ports must settle too, or reset can
880
+ wait indefinitely.
881
+
882
+ The beta.26 declaration comments for `reset` and `PAID_ORDER_PENDING_MESSAGE`
883
+ say pressing Pay again finishes an unconfirmed order; the `resetWhenSettled`
884
+ comment also omits retired checkouts as a reason for `false`. Those comments do
885
+ not establish that a retry is safe. Use the session and reconciliation guidance
886
+ above.
887
+
888
+ Stock `Payment` can display an engine message telling the buyer to press Pay
889
+ again when payment is unconfirmed. That wording does not establish that a retry
890
+ is safe. If neutral buyer guidance is required for uncertain outcomes, use a
891
+ custom payment flow with host-controlled error UI, retain the order and reconcile
892
+ the current session and authoritative order/provider status before recovery.
622
893
 
623
894
  ```tsx
624
- import { PAID_ORDER_PENDING_MESSAGE, useCheckoutContext } from 'tf-checkout-react-native'
895
+ import { useCheckoutContext } from 'tf-checkout-react-native'
625
896
 
626
897
  function useStartAgain(setNotice: (message: string) => void) {
627
898
  const checkout = useCheckoutContext()
628
899
  return async () => {
629
900
  if (checkout.status === 'placing') setNotice('Finishing your payment…')
630
- if (!(await checkout.resetWhenSettled())) setNotice(PAID_ORDER_PENDING_MESSAGE)
901
+ const reset = await checkout.resetWhenSettled()
902
+ setNotice(reset ? 'Choose tickets to start again.' : 'Unable to start over. Check your order or contact support.')
631
903
  }
632
904
  }
633
905
  ```
@@ -643,6 +915,24 @@ A custom confirmer can reject with `paymentProviderError(message, outcome)`:
643
915
  three when the provider establishes that no charge occurred. Other rejections
644
916
  are treated as unknown. Preserve the original order and reconcile it.
645
917
 
918
+ ### Host-owned ID verification
919
+
920
+ `runIdVerification(orderHash, options)` does not open the provider on its own.
921
+ Supply `openUrl` to validate the URL against your provider and scheme policy
922
+ and open it on the device; handle a missing URL or failed opening in your UI.
923
+ The engine swallows asynchronous `openUrl` rejections, so catch and record
924
+ opening failures inside the callback: polling can otherwise continue without a
925
+ handoff. Use `onPhase` for polling state and handle app returns;
926
+ `registerForegroundListener` can trigger a recheck on return and must return an
927
+ unsubscribe function.
928
+
929
+ Alternatively, `onRequired` receives the order hash and possibly null URL; if
930
+ it returns `true`, the engine resolves `undefined` without opening or polling,
931
+ and your host owns both steps. A timeout or poll error rejects with a message
932
+ promising that payment is safe and tickets will be emailed. Replace that text
933
+ with neutral status and reconcile authoritative payment, verification and
934
+ issuance. Verification alone does not prove settlement or issuance.
935
+
646
936
  ### Stripe card and PaymentSheet
647
937
 
648
938
  By default, native `Payment` uses Stripe's native `CardInput` for an eligible
@@ -679,7 +969,7 @@ controlled provider must create its `value` with the same `paymentSheet` and
679
969
  supported. In headless UI, use `checkout.paymentSheet?.placeOrder()` when
680
970
  available; the normal `Payment` section chooses it for the eligible card row.
681
971
 
682
- In beta.24 the sheet is limited to eligible non-MXN Stripe PaymentIntents whose
972
+ In beta.26 the sheet is limited to eligible non-MXN Stripe PaymentIntents whose
683
973
  original methods are card alone, or card plus Cash App Pay in USD. It does not
684
974
  admit delayed methods, create a new intent or add a Stripe Customer/saved-card
685
975
  contract. The SDK checks the original intent's identity, amount and currency
@@ -819,7 +1109,7 @@ example only primes the cart.
819
1109
  | `holdWaiverSigning(index)`, `setWaiverSignature(index, signature, hold?)` | Bind a signature to its original cart/holder; release the returned hold after saving. |
820
1110
  | `checkBuyerEmail(email)`, `reloadCheckoutDetails()` | Check for an existing account; retry an unavailable waiver read. |
821
1111
  | `placeOrder(method?, options?)` | Place/pay via an eligible method; returns `Promise<PlaceOrderResult>`. Options include `autoRunIdVerification`, `idVerification`, `claimCard`. |
822
- | `runIdVerification(orderHash, options?)` | Open/poll verification as a separate post-order step. |
1112
+ | `runIdVerification(orderHash, options?)` | Run verification separately with a host URL opener or takeover; see [host-owned ID verification](#host-owned-id-verification). |
823
1113
  | `syncCurrency(eventId, code?, options?)` | Seed/change currency; refetch catalog and re-prime as needed. |
824
1114
  | `applyPromoCode(eventId, promo)`, `attributeReferrer(eventId, referrer)`, `joinWaitingList(eventId, entry)` | Event engagement helpers. |
825
1115
  | `reset()`, `resetWhenSettled()` | Reset subject to payment safety; use the awaited form to know its outcome. |
@@ -879,7 +1169,7 @@ reads require an appropriately authorized account session; the checkout buyer
879
1169
  scope does not grant it. Low-level APIs do not replace checkout preflight or
880
1170
  payment reconciliation.
881
1171
 
882
- The [API reference](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.24/docs/API.md)
1172
+ The [API reference](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/docs/API.md)
883
1173
  includes the full component and hook catalog.
884
1174
 
885
1175
  ## Authentication and account components
@@ -900,7 +1190,7 @@ Additional exports include `TicketChange`, `TicketRefund`, `TicketGift`,
900
1190
  `Streaming`, `PhoneAuthentication`, `AccountEmailEnrichment`,
901
1191
  `EventDiscussionView` and post reactions. Their availability depends on the
902
1192
  deployed backend, authorized account scope and host-owned navigation. See the
903
- [API reference](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.24/docs/API.md)
1193
+ [API reference](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/docs/API.md)
904
1194
  for component variants and required props.
905
1195
 
906
1196
  Standalone account components that use query hooks need a `QueryClientProvider`;
@@ -950,16 +1240,44 @@ against the exact new version, backend and devices. The historical
950
1240
  and [1.0.47 declarations](https://unpkg.com/tf-checkout-react-native@1.0.47/lib/typescript/src/index.d.ts)
951
1241
  describe the old package; examples there are not 2.x instructions.
952
1242
 
953
- | 1.x integration | 2.x beta.24 approach |
1243
+ | 1.x integration | 2.x beta.26 approach |
954
1244
  | --- | --- |
955
1245
  | `setConfig({ EVENT_ID, ENV, ... })` and event-bound global UI | Restore a secure adapter and call `configureCheckout({ env, clientId, clientSecret: '', storage })`; pass `eventId` to the checkout or section. |
1246
+ | `Login` and `ResetPassword` screens | Use `AuthModal` for the built-in sign-in, registration and recovery sheet. Use `ResetPasswordForm` for a token from the host's reset-link route. Adapt callbacks; checkout and full-account sessions have different scopes. |
956
1247
  | `Tickets` callbacks such as `onAddToCartSuccess` / `onPressMyOrders` | `Tickets` uses `onContinue` / `onSelectSeats`; the host owns orders navigation. Rework the host flow, not just prop names. |
957
- | 1.x `Checkout`, `CheckoutV2`, `BillingInfo` and older core components | Use `EmbeddedCheckout` or compose the 2.x sections and `CheckoutProvider`. The 1.x `CheckoutV2` name does not mean this 2.x API. |
1248
+ | 1.x `Checkout`, `CheckoutSP`, `CheckoutV2`, `BillingInfo` and older core components | Use `EmbeddedCheckout` or compose the 2.x sections and `CheckoutProvider`. These 1.x checkout names are not drop-in 2.x exports; the old `CheckoutSP` README link also lacked a matching section. |
1249
+ | `PurchaseConfirmation` | `Confirmation` renders the active checkout result under `CheckoutProvider`, but does not take an order hash to reload a past receipt. Gate any confirmed copy on authoritative status; build a host status page for routed or later visits. |
1250
+ | `MyOrders`, `MyOrderDetails` and `ResaleTickets` | These layouts are not exported in this version. Use the supported order/resale hooks and APIs with an authorized account to build the needed list, detail, resale and PDF/navigation flows. `TicketChange`, `TicketGift`, `TicketRefund` and `Passes` are separate ready-made actions, not replacement order-list or resale screens. |
1251
+ | `SessionHandleType` component refs and `reloadData()` | Use the relevant query hook's `refetch` and the checkout actions for the current flow. Manage authentication and buyer changes in the host; a ref is not a 2.x session contract. |
958
1252
  | 1.x `useCheckout()` mutation | Native `useCheckout()` is a stateful engine binding with `setTickets`, setters and `placeOrder`; query hooks are under `hooks`. |
959
1253
  | Implicit old native storage and session behavior | Supply and restore an OS-protected synchronous adapter. Migrate credentials securely or ask the buyer to sign in again. Checkout-only and account scopes differ. |
960
1254
  | Per-component style/text props from the old UI | Use theme tokens, available render callbacks and section props; rebuild custom presentation where required. |
961
1255
  | Existing Stripe setup | Verify current peer/native builds, receiving account, provider URLs, return scheme, wallets and PaymentSheet separately. |
962
1256
 
1257
+ For example, the old ticket screen could call the host after adding to cart:
1258
+
1259
+ ```text
1260
+ // 1.x only: these callback props are not the 2.x contract
1261
+ <Tickets onAddToCartSuccess={openBilling} onPressMyOrders={openOrders} />
1262
+ ```
1263
+
1264
+ In 2.x, render this screen inside the same `CheckoutProvider` as the rest of
1265
+ your checkout. The host supplies navigation, including its own orders button.
1266
+ `onContinue` signals that the ticket cart is ready; it does not return the old
1267
+ `onAddToCartSuccess` payload.
1268
+
1269
+ ```tsx
1270
+ import { Tickets } from 'tf-checkout-react-native'
1271
+
1272
+ export function TicketSelection({ eventId, openCheckout, openSeats }: {
1273
+ eventId: string
1274
+ openCheckout: () => void
1275
+ openSeats: () => void
1276
+ }) {
1277
+ return <Tickets eventId={eventId} onContinue={openCheckout} onSelectSeats={openSeats} />
1278
+ }
1279
+ ```
1280
+
963
1281
  Rebuild the native binary after replacing native dependencies and pods. The 1.x
964
1282
  My Orders/order-detail screens, PDF handling and resale screen are not drop-in
965
1283
  2.x equivalents: build the needed host UI, navigation and PDF handling around
@@ -985,6 +1303,7 @@ and password-protected event flows against the deployed service.
985
1303
  | --- | --- |
986
1304
  | `TS2304: Cannot find name 'Crypto'` in SDK declarations | A host without DOM and without a compatible ambient `Crypto` type may report this. Prefer compatible host type definitions. `skipLibCheck` skips declaration-file checks, and unresolved `Crypto` can degrade affected types to `any`, allowing invalid `newBundleIdempotencyKey` arguments. Neither option installs runtime crypto. |
987
1305
  | Configuration/storage error | Hydrate first, then pass an object with synchronous `getItem`, `setItem`, `removeItem`; check native storage failures. |
1306
+ | No tickets appear on first launch | Confirm the public client ID, event ID and environment belong together, and that the event has tickets available to this session. Check the catalog request before changing UI code. |
988
1307
  | `No QueryClient set` or provider context error | Wrap standalone query hooks in `QueryClientProvider`, and checkout sections in `CheckoutProvider`; check duplicate React Query copies. |
989
1308
  | Blank chart or missing seat CTA | Confirm event seating support, pass `onSelectSeats`, rebuild WebView, and verify provider/chart/hold contracts. |
990
1309
  | Missing Apple Pay / Google Pay / Link | Check backend eligibility, real receiving account, device support and host wallet configuration; a simulator or local configuration alone may not qualify. |
package/docs/API.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # React Native API reference
2
2
 
3
3
  This reference describes the API and behavior shipped in
4
- `tf-checkout-react-native@2.0.0-beta.24`. Read it alongside the
5
- [package README](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.24/README.md)
4
+ `tf-checkout-react-native@2.0.0-beta.26`. Read it alongside the
5
+ [package README](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/README.md)
6
6
  for installation, secure setup, complete examples, payment safety and
7
- limitations. The [published declarations](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.24/dist/index.d.ts)
7
+ limitations. The [published declarations](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/dist/index.d.ts)
8
8
  are authoritative for exact types and include the remaining DTO fields.
9
9
  The shared core is bundled; do not install its private workspace package.
10
10
  Availability of any operation depends on the deployed backend, event, account,
@@ -15,7 +15,24 @@ its OS-protected synchronous storage adapter. Hooks using React Query need a
15
15
  `QueryClientProvider` (provided inside `CheckoutProvider`). Do not put
16
16
  confidential client secrets into the app.
17
17
 
18
- **TypeScript troubleshooting:** beta.24 declarations reference a global
18
+ ## Find a ready-made screen
19
+
20
+ For a working starting point, follow the README's
21
+ [complete checkout](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/README.md#embed-a-checkout),
22
+ [authentication sheet](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/README.md#a-reusable-authentication-sheet),
23
+ [ticket management](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/README.md#ticket-management-screens),
24
+ or [composed checkout](https://unpkg.com/tf-checkout-react-native@2.0.0-beta.26/README.md#compose-sections-and-navigation)
25
+ examples. The lists below cover their props and the other exported screens.
26
+
27
+ `EmbeddedCheckout` supplies its own checkout/query provider. Standalone
28
+ checkout sections need a shared `CheckoutProvider`; account and post-purchase
29
+ screens that use queries need a `QueryClientProvider` and the appropriate
30
+ buyer authority. A component's presence does not mean the event or backend has
31
+ enabled that feature. The old native `MyOrders`, `MyOrderDetails`,
32
+ `ResaleTickets`, `CheckoutSP` and `CheckoutV2` layouts are not exports here;
33
+ see the README's migration table for alternatives and gaps.
34
+
35
+ **TypeScript troubleshooting:** beta.26 declarations reference a global
19
36
  `Crypto` type. A host configuration excluding DOM and lacking a compatible
20
37
  ambient `Crypto` type may report TS2304 while checking SDK declarations. Supply
21
38
  compatible host type definitions where possible. `skipLibCheck` skips
@@ -25,6 +42,7 @@ compile. Neither a type declaration nor `skipLibCheck` installs runtime crypto.
25
42
 
26
43
  ## Contents
27
44
 
45
+ - [Find a ready-made screen](#find-a-ready-made-screen)
28
46
  - [Checkout components](#checkout-components)
29
47
  - [Account and post-purchase components](#account-and-post-purchase-components)
30
48
  - [Authentication forms](#authentication-forms)
@@ -50,7 +68,9 @@ proof of settlement. The embedded component creates its own provider and does
50
68
  not expose `options`, `paymentSheet` or `shareUrl` props. Use redirect/custom
51
69
  routing and reconcile payment status when confirmed paid status is required.
52
70
  Redirect omits inline verification: when `needIdVerification` is true, the host
53
- must arrange it. Preserve `orderHash` and any `pendingVoucherUrl` for the
71
+ must arrange it. Provide `onComplete` in redirect mode to navigate; without it
72
+ the checkout remains mounted and no host status screen is reached. Preserve
73
+ `orderHash` and any `pendingVoucherUrl` for the
54
74
  order-status journey, including navigation/restart.
55
75
 
56
76
  `CheckoutProvider` takes required `children`, plus `value?: NativeUseCheckout`,
@@ -127,7 +147,7 @@ rendered. Without `onContinue` it mirrors edits into the combined form. A
127
147
  matching email/holder flags and `requirePrivacyPolicy` when the host requires
128
148
  that checkbox. `onPrivacyRequired` lets the host reveal the inline error.
129
149
 
130
- In beta.24 the stock `privacyPolicy` checkbox shares `consent.ttfOptIn`, sent
150
+ In beta.26 the stock `privacyPolicy` checkbox shares `consent.ttfOptIn`, sent
131
151
  as `ttf_opt_in`; it does not capture independent privacy and marketing choices.
132
152
  If both opt-in labels are explicitly empty, consent may not be committed and
133
153
  the privacy gate can remain blocked. `skipWhenProfileComplete` (or embedded
@@ -138,19 +158,34 @@ host needing separate consent must use a custom flow and tested server contract.
138
158
  During priming, failed event custom-field, checkout-config, add-on and condition
139
159
  reads fall back to empty/default data. Neither stock UI nor engine can gate
140
160
  requirements that were not loaded. Only non-404 waiver failures are recorded in
141
- `unavailableDetails` and gated/retried. Verify failure behavior and implement
142
- tested host safeguards for mandatory fields and acknowledgments; server answer
143
- validation does not prove an acknowledgment was made.
161
+ `unavailableDetails`. Before money may have moved, placement retries an unavailable
162
+ waiver and blocks if it remains unknown; a retained order with a possible payment
163
+ follows separate recovery and needs reconciliation. Verify failure behavior and
164
+ implement tested host safeguards for mandatory fields and acknowledgments;
165
+ server answer validation does not prove an acknowledgment was made.
144
166
 
145
167
  `OrderSummary` accepts `eventId`, `locale`, `messages`, `translate` and uses
146
168
  server-priced cart state. `WaiverSigning` requires `eventId` and accepts
147
169
  `locale`, `messages`, `translate`; it returns no section if there is no waiver.
148
170
  `IDVerification` takes no props and renders only when the current order requires
149
171
  verification. The buyer must press its Verify button to open/poll the provider;
150
- it does not run automatically on mount. A redirect/composed host must arrange
151
- this component under the active checkout provider or a custom
152
- `runIdVerification(orderHash)` flow. Verification is separate from payment
153
- settlement. `Confirmation` takes `shareUrl`,
172
+ it does not run automatically on mount. Its verified message says tickets are
173
+ on their way without checking settlement or issuance. Use a host-owned neutral
174
+ verification/status UI around `runIdVerification(orderHash, options)` when that copy is
175
+ premature, and reconcile authoritative order/provider status. If `onComplete`
176
+ navigates away or unmounts the checkout, its inline verification view will not
177
+ appear; keep the provider mounted for inline verification or handle it at the
178
+ destination. To run custom verification, supply `openUrl` to validate and open
179
+ the provider URL on the device; handle a missing URL or a failed opening. The
180
+ engine swallows asynchronous `openUrl` rejections, so catch and record failures
181
+ in that callback while showing neutral status. Handle `onPhase` and app returns;
182
+ `registerForegroundListener` can recheck on return and returns an unsubscribe
183
+ function. Alternatively, return `true` from `onRequired` to take over: the
184
+ engine resolves `undefined` and neither opens nor polls. A timeout or poll error
185
+ rejects with copy promising payment is safe and tickets will be emailed; replace
186
+ it with neutral status and reconcile authoritative payment, verification and
187
+ issuance. Verification alone proves neither settlement nor issuance.
188
+ `Confirmation` takes `shareUrl`,
154
189
  `shareMessage`, `viewOrderUrl`, `message`, `children`; it reads the current
155
190
  order. For every non-pending order, a supplied `shareUrl` triggers stock
156
191
  reward-promising copy without checking eligibility or generating a
@@ -297,7 +332,7 @@ SDK primitive styles; `resolveTheme(partial)` resolves the light/dark tokens.
297
332
 
298
333
  Import these as `hooks.use…`, except the **top-level native** `useCheckout()`
299
334
  and the context/theme hooks in the preceding sections. Parameters below describe
300
- beta.24; consult the declarations for exact returned state, types, generics and
335
+ beta.26; consult the declarations for exact returned state, types, generics and
301
336
  callbacks. Hook state is scoped to the active configuration/session. Avoid using
302
337
  an old async result to mutate a newly signed-in buyer's UI. Some hooks return
303
338
  React Query query/mutation results; flow hooks return their own state, commands
@@ -434,6 +469,10 @@ The facade is not a payment UI or a replacement for the engine's preflight,
434
469
  confirmation and uncertainty handling. Some calls change server state and
435
470
  require an authorized buyer, event, order or other proof. Its domain map:
436
471
 
472
+ `ttf.events.requiredCustomFieldLabels(eventId)` returns `[]` if its lookup
473
+ fails as well as when no matching required order/ticket labels exist. An empty
474
+ result is not proof that the event has no required custom fields.
475
+
437
476
  | Domain | Methods |
438
477
  | --- | --- |
439
478
  | `ttf.events` | `featured`, `details`, `tickets`, `ticketsWithMeta`, `bundles`, `startBundlePurchase`, `info`, `conditions`, `timeSlotTickets`, `customFields`, `requiredCustomFieldLabels`, `addons`, `filterAddonsForTickets`, `submitPromoCode`, `setCurrency`, `authenticate`, `track`, `updateOrderDataCapture`, `updateTicketDataCapture` |
@@ -514,6 +553,10 @@ reset() // void
514
553
  resetWhenSettled() // Promise<boolean>
515
554
  ```
516
555
 
556
+ `runIdVerification` requires the host URL opener or takeover and neutral error
557
+ handling described in the `IDVerification` section above; calling it without
558
+ an opener does not open the provider.
559
+
517
560
  `placeOrder` accepts a simple card/wallet method or a `PaymentRequest` union;
518
561
  review the README's payment section before constructing a custom selector. The
519
562
  `options` can include `autoRunIdVerification`, `idVerification`, and
@@ -521,9 +564,18 @@ review the README's payment section before constructing a custom selector. The
521
564
  is swallowed. A pending order can also request verification; failure of that
522
565
  separate step proves neither payment failure nor settlement. Present its status
523
566
  independently. When money may have moved, preserve and reconcile the original
524
- order. `resetWhenSettled`
525
- returns false for a retained or retired checkout. A provider page, picker or
526
- other custom port must settle on all close/cancel/unmount paths.
567
+ order. `resetWhenSettled` returns false for a retained or retired checkout; check
568
+ the current session and reconcile the order and provider status before recovery.
569
+ The beta.26 declaration comments for `reset` and `PAID_ORDER_PENDING_MESSAGE`
570
+ say pressing Pay again finishes an unconfirmed order; the `resetWhenSettled`
571
+ comment omits retired checkouts as a reason for `false`. Those comments do not
572
+ establish that a retry is safe. A provider page, picker or other custom port must
573
+ settle on all close/cancel/unmount paths.
574
+
575
+ Stock `Payment` can display an engine message telling the buyer to press Pay
576
+ again when payment is unconfirmed. That wording does not prove a retry is safe.
577
+ If neutral guidance is required, use a custom payment flow with host-controlled
578
+ error UI, retain the order and reconcile before recovery.
527
579
 
528
580
  For zero-total orders, this SDK ignores the free-registration response body and
529
581
  reports `needIdVerification: false`. Verification or approval may still be
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tf-checkout-react-native",
3
- "version": "2.0.0-beta.24",
3
+ "version": "2.0.0-beta.26",
4
4
  "description": "TheTicketFairy ReactNative Checkout library",
5
5
  "homepage": "https://github.com/theticketfairy/tf-shared-libraries#readme",
6
6
  "author": "The Ticket Fairy",