tf-checkout-react 2.0.0-beta.23 → 2.0.0-beta.25
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.
- package/README.md +831 -279
- package/docs/API.md +540 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,326 +1,878 @@
|
|
|
1
1
|
# tf-checkout-react
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
The shared core is private and bundled into both platform packages. Use React
|
|
10
|
-
18+, React DOM 18+ and React Query 5 on web.
|
|
11
|
-
Never put a confidential OAuth client secret in browser or mobile code. Public
|
|
12
|
-
checkout integrations use registered SDK client IDs and owned buyer sessions.
|
|
13
|
-
|
|
14
|
-
## Install
|
|
15
|
-
|
|
16
|
-
This README describes `2.0.0-beta.23`, the paired 2.x prerelease. Pin it
|
|
17
|
-
explicitly to use this version. `beta` and `latest` are mutable npm tags, not
|
|
18
|
-
guarantees about the highest version; an unqualified install can still resolve
|
|
19
|
-
a stable 1.x package. Check the current dist-tags when choosing a version.
|
|
20
|
-
Publication does not by itself establish backend rollout, device compatibility
|
|
21
|
-
or provider/payment acceptance.
|
|
3
|
+
Ticket Fairy's React checkout for the web. Render the complete checkout, compose
|
|
4
|
+
its sections, or build your own UI against the checkout engine. The package also
|
|
5
|
+
exports authentication, confirmation, rewards, ticket-management and account
|
|
6
|
+
components, plus the shared API and React Query hooks. Which paths a buyer can
|
|
7
|
+
actually use depend on the event, the deployed API, the buyer's session and the
|
|
8
|
+
payment provider.
|
|
22
9
|
|
|
23
|
-
|
|
24
|
-
npm
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
This version preserves quantities across rotating encrypted ticket IDs using
|
|
28
|
-
the API's optional canonical `selectionKey`, while quantity/change APIs and cart
|
|
29
|
-
requests retain the latest encrypted IDs. Deploy and verify the canonical
|
|
30
|
-
base/dated key and dated numeric context before relying on that behavior:
|
|
31
|
-
`display_price`, `price_with_fees`, `fee_included`, `price_currency` and
|
|
32
|
-
`price_symbol`. Missing optional keys retain opaque-ID compatibility without a
|
|
33
|
-
rotation-retention claim. The deployed API must provide and validate that data.
|
|
34
|
-
|
|
35
|
-
Post-purchase upgrade waiting is a separate server-owned contract. Only valid
|
|
36
|
-
change-options targets can expose Join or Leave; malformed target IDs, labels
|
|
37
|
-
or existing entries are ignored. A sold-out row does not enable it. The backend
|
|
38
|
-
must explicitly offer that organizer-configured flow; local receiver validation
|
|
39
|
-
does not prove its deployed availability or a completed join.
|
|
10
|
+
This reference describes **2.0.0-beta.25**. It is a prerelease with a different
|
|
11
|
+
API from 1.x. Pin the version while evaluating it. npm's `latest` and `beta`
|
|
12
|
+
tags can move independently and an unqualified install may select 1.x:
|
|
40
13
|
|
|
41
14
|
```bash
|
|
42
|
-
npm
|
|
15
|
+
npm view tf-checkout-react dist-tags
|
|
16
|
+
npm install tf-checkout-react@2.0.0-beta.25 @tanstack/react-query react react-dom
|
|
43
17
|
```
|
|
44
18
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
19
|
+
The [API reference](https://unpkg.com/tf-checkout-react@2.0.0-beta.25/docs/API.md)
|
|
20
|
+
is included as `docs/API.md` in this package.
|
|
21
|
+
|
|
22
|
+
Contents: [Requirements](#requirements) · [Quick start](#quick-start) ·
|
|
23
|
+
[Configuration](#configuration-and-sessions) · [Embedded checkout](#embeddedcheckout)
|
|
24
|
+
· [Composition](#compose-sections) · [Checkout lifecycle](#checkout-lifecycle)
|
|
25
|
+
· [Payments](#payments) · [Authentication](#authentication) ·
|
|
26
|
+
[Reference](#component-reference) · [Headless APIs](#headless-apis) ·
|
|
27
|
+
[Styling](#styling-and-localization) · [Migration](#migrating-from-1x) ·
|
|
28
|
+
[Testing and troubleshooting](#testing-and-troubleshooting)
|
|
29
|
+
|
|
30
|
+
## Requirements
|
|
31
|
+
|
|
32
|
+
- Node.js 18 or newer for tooling; a React browser application and a bundler
|
|
33
|
+
that handles JavaScript and CSS imports.
|
|
34
|
+
- Peer dependencies: `react >=18`, `react-dom >=18` and
|
|
35
|
+
`@tanstack/react-query >=5`. Supply one compatible copy of each in the host.
|
|
36
|
+
Query-based components and hooks need the host's `QueryClientProvider`.
|
|
37
|
+
- A Ticket Fairy event ID and a **public SDK client ID** registered for this
|
|
38
|
+
integration, together with compatible API and provider configuration. Ask
|
|
39
|
+
your Ticket Fairy integration contact for the appropriate environment and
|
|
40
|
+
event setup. Never put a confidential OAuth client secret in browser code.
|
|
41
|
+
- The shared core and seat renderer are bundled; npm installs the package's
|
|
42
|
+
declared runtime dependencies. No separate shared-core install is required.
|
|
43
|
+
Browser and provider support must be tested for the actual event and device.
|
|
44
|
+
|
|
45
|
+
The package entry imports `react-international-phone/style.css` and its own
|
|
46
|
+
checkout stylesheet. Your bundler must process both those imports and CSS
|
|
47
|
+
`@import` rules. The latter is also exported at
|
|
48
|
+
`tf-checkout-react/checkout.css` for build setups that need an explicit import.
|
|
49
|
+
Its `dist/styles` files and referenced assets are part of the npm package.
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
Configure once before mounting the SDK. Create the query client once rather
|
|
54
|
+
than on every render. Replace the placeholders with an event and a registered
|
|
55
|
+
public client ID in the environment you are using.
|
|
56
56
|
|
|
57
57
|
```tsx
|
|
58
|
+
import { useState } from 'react'
|
|
58
59
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
59
60
|
import { configureCheckout, EmbeddedCheckout } from 'tf-checkout-react'
|
|
60
61
|
|
|
61
|
-
configureCheckout({
|
|
62
|
+
configureCheckout({
|
|
63
|
+
env: 'PROD',
|
|
64
|
+
clientId: 'PUBLIC_SDK_CLIENT_ID',
|
|
65
|
+
clientSecret: '',
|
|
66
|
+
cookieAuth: true,
|
|
67
|
+
})
|
|
62
68
|
|
|
63
69
|
const queryClient = new QueryClient()
|
|
64
70
|
|
|
65
|
-
export
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
export function App() {
|
|
72
|
+
const [notice, setNotice] = useState('')
|
|
73
|
+
return (
|
|
74
|
+
<QueryClientProvider client={queryClient}>
|
|
75
|
+
<EmbeddedCheckout
|
|
76
|
+
eventId="EVENT_ID"
|
|
77
|
+
onComplete={(order) => {
|
|
78
|
+
setNotice(order.pending ? 'Payment pending' : 'Order submitted')
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
<p role="status">{notice}</p>
|
|
82
|
+
</QueryClientProvider>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
79
85
|
```
|
|
80
86
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
87
|
+
Use a test event and the corresponding test client ID with `env: 'STAG'` for
|
|
88
|
+
integration testing. `onComplete` receives a result that may be pending; do not
|
|
89
|
+
fulfil an order merely because this callback fired. See
|
|
90
|
+
[Payments](#payments) for reconciliation and retry guidance.
|
|
91
|
+
|
|
92
|
+
The inline confirmation also offers a generic share link using the current
|
|
93
|
+
page URL without checking referral eligibility. That URL can contain query
|
|
94
|
+
parameters or lack the buyer's referral. Review the
|
|
95
|
+
[confirmation limitations](#checkout-sections) before using the default flow.
|
|
96
|
+
|
|
97
|
+
## Configuration and sessions
|
|
98
|
+
|
|
99
|
+
`configureCheckout(config: TtfConfig)` wraps the shared `configure` function,
|
|
100
|
+
adds a browser `localStorage` adapter and a browser checkout-auth popup, and then
|
|
101
|
+
applies your supplied options. Call it once at client startup, before any SDK
|
|
102
|
+
hook or `ttf` call. Calling it again replaces the global configuration and can
|
|
103
|
+
retire existing session state. Do not reconfigure from a component render.
|
|
104
|
+
|
|
105
|
+
| Option | Meaning |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `clientId`, `clientSecret` | Required strings. For a public browser integration use its registered SDK client ID and an empty `clientSecret`; a confidential secret belongs on a trusted server only. |
|
|
108
|
+
| `env` | `PROD` (default), `STAG`, or `DEV`, selecting `https://www.ticketfairy.com`, `https://test.ticketfairy.com`, or `https://sandbox.ticketfairy.com`. |
|
|
109
|
+
| `baseUrl` | Explicit host overrides `env`, including `''` for same origin behind a proxy. A trailing `/api` is normalized; the SDK appends `/api` for API calls. |
|
|
110
|
+
| `sourceOrigin` | Optional value of the `X-Source-Origin` request header when required for your integration. |
|
|
111
|
+
| `storage` | Synchronous `StorageAdapter` overriding the browser default. `getItem(key)`, `setItem(key, value)`, and `removeItem(key)` are required; optional `flush()` returns `Promise<void>` for a synchronous mirror with asynchronous persistence. |
|
|
112
|
+
| `cookieAuth` | Enables the header-backed Ticket Fairy session path. Use when the integration is set up for a shared session or anonymous cookie cart; browser cookie and CORS policies still apply. |
|
|
113
|
+
| `withCredentials` | Controls automatic HTTP cookie handling; defaults to true in browsers. Cross-origin cookies also require correct server CORS/cookie configuration and browser permission. |
|
|
114
|
+
| `auth` | Function returning additional headers or `undefined`; called for each request. Headers normally merge after SDK headers, but protected requests enforce session isolation: guest bootstrap strips sensitive buyer/session headers after that merge. Use only credentials appropriate to the browser. |
|
|
115
|
+
| `accountAuth` | Opts into first-party account auth routes; default is off. Requires the corresponding backend journey and account authority. |
|
|
116
|
+
| `sdkCheckoutPhoneAuth` | Opts into the first-party phone checkout journey only when its matching backend is deployed. |
|
|
117
|
+
| `browserAuth`, `sdkCheckoutBrowserAuth` | Browser authorization ports for specialized integrations. The web wrapper supplies the checkout popup port when supported; an explicit config value overrides it. |
|
|
118
|
+
|
|
119
|
+
`localStorageAdapter` no-ops outside a browser; `createMemoryStorage()` is an
|
|
120
|
+
exported non-persistent adapter useful for tests. Browser local storage is
|
|
121
|
+
accessible to scripts in the origin. Protect against XSS, avoid logging tokens,
|
|
122
|
+
order links or personal information, and pick an adapter and session lifetime
|
|
123
|
+
appropriate to your application. Logout/session changes need to be coordinated
|
|
124
|
+
with the host: stale UI or a cached profile is not proof of authorization.
|
|
125
|
+
|
|
126
|
+
The public checkout sign-in path establishes an event-scoped buyer identity. It
|
|
127
|
+
does **not** grant a full account session for private tickets or account
|
|
128
|
+
preferences. A full account experience needs the corresponding authorized
|
|
129
|
+
session and backend routes. Two-factor and other proof steps must finish before
|
|
130
|
+
an authentication flow is complete. Do not treat a checkout profile callback as
|
|
131
|
+
permission to read private account data.
|
|
132
|
+
|
|
133
|
+
### Server rendering
|
|
134
|
+
|
|
135
|
+
The default storage adapter is server-safe, and the checkout hook supplies an
|
|
136
|
+
idle server snapshot. Payment elements, popups, DOM effects and browser storage
|
|
137
|
+
need a browser. In SSR frameworks, mount the interactive checkout in a client
|
|
138
|
+
component; do not run a browser checkout on the server or share a configured
|
|
139
|
+
module/session singleton across server requests. Configure the browser before
|
|
140
|
+
rendering that client tree. Confirm that the framework processes the package's
|
|
141
|
+
CSS imports. Static import/SSR compatibility of a particular framework and all
|
|
142
|
+
third-party dependencies should be tested in that framework.
|
|
143
|
+
|
|
144
|
+
## EmbeddedCheckout
|
|
145
|
+
|
|
146
|
+
`EmbeddedCheckout` owns a `CheckoutProvider` and presents ticket/bundle or
|
|
147
|
+
seat selection, add-ons, billing, waivers, payment and inline completion as the
|
|
148
|
+
flow requires. It must be under `QueryClientProvider`.
|
|
149
|
+
|
|
150
|
+
Only `eventId` is required. Callbacks and options are optional.
|
|
151
|
+
|
|
152
|
+
| Prop | Type / default | Description |
|
|
153
|
+
| --- | --- | --- |
|
|
154
|
+
| `eventId` | `string` | Event to sell. |
|
|
155
|
+
| `onComplete` | `(order: PlaceOrderResult) => void` | Result of placement, including an asynchronously pending payment. |
|
|
156
|
+
| `confirmationMode` | `'inline' \| 'redirect'`; `inline` | Inline renders verification/confirmation. Redirect shows a transition; use `onComplete` to navigate. |
|
|
157
|
+
| `initialView` | `'tickets' \| 'seats'`; `tickets` | Initial selection view. |
|
|
158
|
+
| `onViewChange` | `(view: 'tickets' \| 'seats' \| 'checkout') => void` | Reports the visible flow view. |
|
|
159
|
+
| `autoScroll` | `boolean`; `true` | Scroll to buyer details after reservation. |
|
|
160
|
+
| `requireEmailConfirmation` | `boolean`; `true` | Require guests to repeat their email. |
|
|
161
|
+
| `collectTicketHolders` | `boolean`; `true` | Collect one named holder per ticket. |
|
|
162
|
+
| `collectHolderContact` | `boolean`; `true` | Collect holder contact details when holders are collected. |
|
|
163
|
+
| `skipBillingWhenProfileComplete` | `boolean`; `false` | Skip billing only for an eligible complete signed-in profile and compatible holder/custom-field requirements. Payment is not skipped. See the privacy and opt-in limitations below. |
|
|
164
|
+
| `onLogin` | `(email?: string) => void` | Opens host login instead of the built-in modal; the email may be an existing-account match. |
|
|
165
|
+
| `auth` | `false \| EmbeddedCheckoutAuthOptions` | Disable or configure the built-in modal; ignored when `onLogin` is supplied. |
|
|
166
|
+
| `privacyPolicy` | `CheckoutPrivacyPolicy` | `{ url, brandName, linkLabel? }`; adds the host's required privacy acknowledgement. |
|
|
167
|
+
| `additionalConditions` | `EventCondition[]` | Host acknowledgements `{ id, name, content, isRequired }`; required ones gate payment. Content is rendered as HTML: supply trusted or sanitized HTML. |
|
|
168
|
+
| `ttfOptInLabel`, `brandOptInLabel` | `string` | Override the Ticket Fairy opt-in label or add a brand opt-in. The privacy-policy option changes the Ticket Fairy control as described below. |
|
|
169
|
+
| `initialPromoCode`, `referrer`, `readAttributionFromUrl` | `string`, `string \| number`, `boolean` | Apply a code and attribution; URL reading defaults to `true`. |
|
|
170
|
+
| `showTestCardHint` | `boolean`; `false` | Demo-only sandbox card copy. |
|
|
171
|
+
| `theme`, `locale`, `messages`, `className` | `CheckoutTheme`, `LocaleCode`, `Partial<Messages>`, `string` | Appearance, copy and root class. |
|
|
172
|
+
|
|
173
|
+
`EmbeddedCheckoutAuthOptions` accepts `allowRegistration`,
|
|
174
|
+
`allowPasswordReset`, `requireRegistrationAddress`, `logoUrl`,
|
|
175
|
+
`onCheckoutAuthenticated(profile: CheckoutBuyerProfile)` and
|
|
176
|
+
`onAuthenticated(profile: TfProfile)`. The two callbacks represent different
|
|
177
|
+
session authorities; use the one appropriate to your configured journey.
|
|
178
|
+
`requireRegistrationAddress={false}` does not remove the address requirement
|
|
179
|
+
for the public checkout registration or account-completion journey; those
|
|
180
|
+
paths force it on in this version.
|
|
181
|
+
|
|
182
|
+
### Resume a server cart
|
|
183
|
+
|
|
184
|
+
`ResumedCheckout` calls `resumeCart` for an existing cart in the current
|
|
185
|
+
session. It does not create that cart or accept a cart ID as a prop. A resale
|
|
186
|
+
acceptance flow, for example, must create the cart first. The component shows
|
|
187
|
+
billing, waivers and payment and requires the same query provider and
|
|
188
|
+
configuration as the embedded flow.
|
|
132
189
|
|
|
133
190
|
```tsx
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
191
|
+
import { useState } from 'react'
|
|
192
|
+
import { ResumedCheckout } from 'tf-checkout-react'
|
|
193
|
+
|
|
194
|
+
export function ResumePage() {
|
|
195
|
+
const [notice, setNotice] = useState('')
|
|
196
|
+
return (
|
|
197
|
+
<>
|
|
198
|
+
<ResumedCheckout
|
|
199
|
+
eventId="EVENT_ID"
|
|
200
|
+
isFromResale
|
|
201
|
+
confirmationMode="inline"
|
|
202
|
+
onComplete={(order) => setNotice(order.pending ? 'Payment pending' : 'Order submitted')}
|
|
203
|
+
/>
|
|
204
|
+
<p role="status">{notice}</p>
|
|
205
|
+
</>
|
|
206
|
+
)
|
|
207
|
+
}
|
|
142
208
|
```
|
|
143
209
|
|
|
144
|
-
|
|
145
|
-
`
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
210
|
+
Props are `eventId` (required), `isFromResale` (default `false`),
|
|
211
|
+
`onComplete`, `confirmationMode` (default **`redirect`**),
|
|
212
|
+
`requireEmailConfirmation`, `collectTicketHolders`, `collectHolderContact`
|
|
213
|
+
(each default `true`), `privacyPolicy`, `brandOptInLabel`,
|
|
214
|
+
`additionalConditions`, `theme` and `className`. With the default redirect
|
|
215
|
+
mode, route in `onComplete`; otherwise a transition remains visible. Unlike
|
|
216
|
+
`EmbeddedCheckout`, this component does not accept `locale`, `messages`,
|
|
217
|
+
`auth` or `onLogin` props in this version.
|
|
151
218
|
|
|
152
|
-
##
|
|
219
|
+
## Compose sections
|
|
153
220
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
221
|
+
For a different layout, render sections beneath `CheckoutProvider` and the
|
|
222
|
+
host's `QueryClientProvider`. The provider creates a web-wired `useCheckout`
|
|
223
|
+
instance unless `value` is supplied. Sections share its context. The app-wide
|
|
224
|
+
checkout store is shared by default, so separate `useCheckout()` calls are not
|
|
225
|
+
independent carts. Avoid mounting competing checkout flows for different events
|
|
226
|
+
at once; coordinate completion/reset and session transitions in the host.
|
|
157
227
|
|
|
158
228
|
```tsx
|
|
229
|
+
import { useState } from 'react'
|
|
159
230
|
import {
|
|
160
|
-
CheckoutProvider,
|
|
161
|
-
Tickets,
|
|
162
|
-
AddOns,
|
|
163
|
-
BillingInfo,
|
|
164
|
-
Payment,
|
|
165
|
-
OrderSummary,
|
|
231
|
+
AddOns, BillingInfo, CheckoutProvider, OrderSummary, Payment,
|
|
232
|
+
Tickets, WaiverSigning,
|
|
166
233
|
} from 'tf-checkout-react'
|
|
167
234
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
<
|
|
173
|
-
<
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
`QuantitySelect`, `PriceLine`, `Stepper`, `Timer`, `TimerBanner`, `Loader`.
|
|
188
|
-
|
|
189
|
-
**Auth** — `AuthModal`, `LoginForm`, `RegisterForm`, `ForgotPasswordForm`,
|
|
190
|
-
`ResetPasswordForm`.
|
|
191
|
-
|
|
192
|
-
## Rewards
|
|
193
|
-
|
|
194
|
-
After a buyer pays, the Rewards section shows where they stand on the event's
|
|
195
|
-
leaderboard, who their link has brought in, what they can still win, their pack,
|
|
196
|
-
and the card they share.
|
|
197
|
-
|
|
198
|
-
`<OrderConfirmation/>` renders it for you whenever the confirmation response
|
|
199
|
-
carries a `rewards` object. The host supplies `hash` in these examples:
|
|
200
|
-
|
|
201
|
-
```tsx
|
|
202
|
-
<OrderConfirmation orderHash={hash} /> // rewards included
|
|
203
|
-
<OrderConfirmation orderHash={hash} showRewards={false} />
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
Or render it anywhere on its own:
|
|
207
|
-
|
|
208
|
-
```tsx
|
|
209
|
-
import { Rewards } from 'tf-checkout-react'
|
|
210
|
-
;<Rewards orderHash={hash} />
|
|
235
|
+
export function ComposedCheckout() {
|
|
236
|
+
const eventId = 'EVENT_ID'
|
|
237
|
+
const [notice, setNotice] = useState('')
|
|
238
|
+
return (
|
|
239
|
+
<CheckoutProvider theme={{ colorScheme: 'light', accent: '#2458d3' }}>
|
|
240
|
+
<Tickets eventId={eventId} />
|
|
241
|
+
<AddOns eventId={eventId} />
|
|
242
|
+
<BillingInfo eventId={eventId} requireEmailConfirmation />
|
|
243
|
+
<WaiverSigning eventId={eventId} />
|
|
244
|
+
<OrderSummary eventId={eventId} />
|
|
245
|
+
<Payment
|
|
246
|
+
eventId={eventId}
|
|
247
|
+
requireEmailConfirmation
|
|
248
|
+
onComplete={(order) => setNotice(order.pending ? 'Payment pending' : 'Order submitted')}
|
|
249
|
+
/>
|
|
250
|
+
<p role="status">{notice}</p>
|
|
251
|
+
</CheckoutProvider>
|
|
252
|
+
)
|
|
253
|
+
}
|
|
211
254
|
```
|
|
212
255
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
`
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
256
|
+
This is a basic general-admission layout. Use section callbacks to reveal and
|
|
257
|
+
navigate between steps as needed. For seated events wire `Tickets.onSelectSeats`
|
|
258
|
+
to a `SeatMap` view; without the callback its seat-selection CTA is hidden.
|
|
259
|
+
Keep `BillingInfo`'s email/holder rules aligned with `Payment`'s corresponding
|
|
260
|
+
rules. If using a host privacy policy, pass the policy to `BillingInfo`, pass
|
|
261
|
+
`requirePrivacyPolicy` to `Payment`, and use `onPrivacyRequired` to reveal the
|
|
262
|
+
billing error. Render the event's required conditions and waiver, not just a
|
|
263
|
+
card input. Read the consent limitations below before using `privacyPolicy` or
|
|
264
|
+
the billing-skip option. Do not skip add-ons when one is required.
|
|
265
|
+
|
|
266
|
+
`CheckoutProvider` props: `children` (required), `value?: UseCheckout`,
|
|
267
|
+
`theme?: CheckoutTheme`, `locale?: LocaleCode`,
|
|
268
|
+
`messages?: Partial<Messages>`, and `className?: string`. Use
|
|
269
|
+
`useCheckoutContext()` inside the provider. `useCheckoutValidation()` exposes
|
|
270
|
+
`{ attempt, requestValidation }` for coordinating validation between sections;
|
|
271
|
+
both context hooks require a provider. The provider's default checkout includes
|
|
272
|
+
the installment picker. If supplying your own `value`, wire any custom payment
|
|
273
|
+
ports you need when creating that checkout.
|
|
274
|
+
|
|
275
|
+
## Checkout lifecycle
|
|
276
|
+
|
|
277
|
+
1. Load the current event catalog and reserve current selections with
|
|
278
|
+
`setTickets(eventId, selections)`, or reserve seats and call `setSeats` /
|
|
279
|
+
`setSeatsIo`. Alternatively `resumeCart` attaches to a cart already owned by
|
|
280
|
+
this browser session. The server owns inventory, expiry and final prices.
|
|
281
|
+
2. Read `customFields`, `buyerFields`, conditions, required add-ons, waiver,
|
|
282
|
+
pricing and payment availability from the primed snapshot. Collect the
|
|
283
|
+
required buyer/holder answers and consent. Save them through the corresponding
|
|
284
|
+
setters. Reprice after add-on or currency changes.
|
|
285
|
+
3. Render only the methods offered for this event and compatible with the host.
|
|
286
|
+
Validate required information, then `await placeOrder(method)` once per buyer
|
|
287
|
+
action. The engine checks preconditions and coordinates concurrent placement.
|
|
288
|
+
4. Handle the returned `PlaceOrderResult`, including `pending`, and any ID
|
|
289
|
+
verification. A result, a redirect, or a closed popup alone does not prove
|
|
290
|
+
that money settled. Reconcile authoritative order and provider status before
|
|
291
|
+
fulfilling or starting a new payment when an outcome is uncertain.
|
|
292
|
+
|
|
293
|
+
`status` can be `idle`, `priming`, `ready`, `repricing`, `placing`, `succeeded`,
|
|
294
|
+
`expired` or `error`. `isBusy` includes cart/order operations and an outstanding
|
|
295
|
+
waiver save. `secondsLeft` is an optional, whole-second display countdown derived
|
|
296
|
+
from `expiresAt`. When it reaches zero the hook expires the cart unless an order
|
|
297
|
+
is being placed or has succeeded. An expired reservation requires the buyer to
|
|
298
|
+
start again; a displayed countdown does not extend a server reservation.
|
|
299
|
+
|
|
300
|
+
`reset()` starts a reset and returns `void`; `await resetWhenSettled()` returns
|
|
301
|
+
`true` only when reset completed. While a payment is in flight, reset waits for
|
|
302
|
+
it. It returns `false` if an order must be retained because money may have moved,
|
|
303
|
+
or the checkout is retired. A `false` result does not identify which reason
|
|
304
|
+
applies. Show neutral guidance and check the current session and authoritative
|
|
305
|
+
order/provider status before choosing recovery. `PAID_ORDER_PENDING_MESSAGE`
|
|
306
|
+
contains an instruction to press Pay again; do not show it for every `false`
|
|
307
|
+
result or use it as proof that a retry is safe. Do not assume a timeout, network
|
|
308
|
+
error or closed provider page means the charge failed. A custom provider page must
|
|
309
|
+
settle with `{ event: 'dismiss' }` on close/unmount, and other custom payment
|
|
310
|
+
ports must settle, or a waiting reset cannot finish.
|
|
311
|
+
|
|
312
|
+
### Tickets, codes, seats and waiting lists
|
|
313
|
+
|
|
314
|
+
`Tickets` reads the catalog, presents the event's promo/access-code controls and
|
|
315
|
+
waiting-list state, and reserves selected ticket lines. `initialPromoCode`
|
|
316
|
+
applies once on mount. The web picker reads `promo` / `promo_code` and `ttf_r` /
|
|
317
|
+
`referrer_id` from the URL by default; explicit props take precedence. Set
|
|
318
|
+
`readAttributionFromUrl={false}` to disable this. An ambiguous numeric `?r=`
|
|
319
|
+
can mean a promotion or referral and is not classified by this SDK. Pass a
|
|
320
|
+
referrer only when its meaning is known.
|
|
321
|
+
|
|
322
|
+
For headless catalogs, `hooks.useTicketsWithMeta(eventId)` exposes `tickets`,
|
|
323
|
+
`promo`, `waitingList` and `bundles`. After `applyPromoCode`, refetch the
|
|
324
|
+
catalog to display changed prices or unlocked tickets. Private-event access is
|
|
325
|
+
a separate server operation, `ttf.events.authenticate(eventId, password)`;
|
|
326
|
+
refetch after success. Do not treat a code or an old catalog as proof inventory
|
|
327
|
+
is reserved. The versioned waiting-list definition controls eligibility and
|
|
328
|
+
choices; `waitingList.state` can be `open`, `closed`, `hidden` or `unsupported`.
|
|
329
|
+
Use an authoritative offered choice for `joinWaitingList`, or general interest
|
|
330
|
+
where allowed. Unsupported/custom forms may provide an event continuation URL.
|
|
331
|
+
|
|
332
|
+
Ticket quantities can survive rotating encrypted IDs **when the API supplies a
|
|
333
|
+
stable canonical `selectionKey`**. Cart submissions still use the latest
|
|
334
|
+
opaque encrypted IDs. For dated tickets, deployed canonical keys and numeric
|
|
335
|
+
price context (`display_price`, `price_with_fees`, `fee_included`,
|
|
336
|
+
`price_currency`, `price_symbol`) must be provided and validated by the API.
|
|
337
|
+
When the optional key is absent, do not assume retention across ID rotation.
|
|
338
|
+
|
|
339
|
+
`SeatMap` uses the event's configured seat map and server reservation. Let the
|
|
340
|
+
buyer select seats before continuing; availability can change. Test the actual
|
|
341
|
+
map, chart and reservation expiry on the target domain and browser. For a
|
|
342
|
+
headless integration, `SeatLine` uses the server seat reservation key, tier,
|
|
343
|
+
ticket type, option and price; do not manufacture those values from display
|
|
344
|
+
labels. `setSeatsIo` is a separate path for a seats.io selection.
|
|
345
|
+
|
|
346
|
+
### Buyer fields, consent and waivers
|
|
347
|
+
|
|
348
|
+
The server's checkout configuration determines required buyer fields, ticket
|
|
349
|
+
holders, custom captures, add-ons and waiver. `buyerFields` identifies gated
|
|
350
|
+
nationality, gender and Instagram inputs; `customFields` contains order,
|
|
351
|
+
ticket and add-on groups. Store order answers in `billing.dataCapture`, each
|
|
352
|
+
holder's answers in `ticketDataCapture`, and add-on answers via
|
|
353
|
+
`setAddonDataCapture`. Holder ticket type IDs come from the priced cart, not
|
|
354
|
+
the opaque catalog ID. Use backend country/state IDs for `countryId` and
|
|
355
|
+
`stateId`; `countryCode` / `stateCode` are payment billing codes.
|
|
356
|
+
|
|
357
|
+
In beta.25 conditional custom-field requiredness is left to the backend and
|
|
358
|
+
not all hosted-checkout conditional visibility is reproduced. Verify the
|
|
359
|
+
actual event against the deployed checkout, including blanks, images, holder
|
|
360
|
+
scoping and validation errors; do not claim parity from the presence of a
|
|
361
|
+
field alone. Terms and `additionalConditions` are client-side acceptance gates;
|
|
362
|
+
respect the server's own requirements. `Payment` renders condition `content`,
|
|
363
|
+
or `name` as a fallback, as HTML. Only supply trusted or appropriately sanitized
|
|
364
|
+
content, and verify the source and handling of server-provided conditions too.
|
|
365
|
+
Failed waiver reads other than a 404 remain unknown and block placement; use
|
|
366
|
+
`reloadCheckoutDetails()` to retry rather than silently skipping it.
|
|
367
|
+
`WaiverSigning` handles the SDK's signing flow.
|
|
368
|
+
|
|
369
|
+
**Consent limitation in beta.25:** when `privacyPolicy` is supplied, the
|
|
370
|
+
stock `BillingInfo` replaces the Ticket Fairy marketing checkbox with the
|
|
371
|
+
required privacy checkbox, but both use `consent.ttfOptIn`; the order sends
|
|
372
|
+
that value as `ttf_opt_in`. The privacy acknowledgement and Ticket Fairy
|
|
373
|
+
marketing choice are therefore not independently captured by this stock path.
|
|
374
|
+
`brandOptIn` is a separate value. If your integration requires independent
|
|
375
|
+
privacy and marketing choices, do not rely on the stock `privacyPolicy` prop
|
|
376
|
+
for that requirement; use an alternative whose UI, payload and backend behavior
|
|
377
|
+
you have verified.
|
|
378
|
+
|
|
379
|
+
Do not combine stock required `privacyPolicy` with
|
|
380
|
+
`skipBillingWhenProfileComplete` / `skipWhenProfileComplete`. When skipping is
|
|
381
|
+
eligible, the billing card and its consent controls disappear while `Payment`
|
|
382
|
+
can still require the privacy value. The same skip can hide marketing opt-ins;
|
|
383
|
+
do not assume they remain visible. Keep the billing card available and test
|
|
384
|
+
both signed-in and guest flows.
|
|
385
|
+
|
|
386
|
+
## Payments
|
|
387
|
+
|
|
388
|
+
`Payment` selects available methods from event/backend configuration and uses
|
|
389
|
+
the web platform's Stripe, popup and Xendit ports. Supported request shapes in
|
|
390
|
+
the engine include card, Apple Pay, Google Pay, Stripe redirect methods, OXXO,
|
|
391
|
+
Xendit card/e-wallets, PayPal, Razorpay, Adyen and payment plans. A type existing
|
|
392
|
+
in the SDK does **not** mean it is enabled for your event, browser, country,
|
|
393
|
+
currency, merchant account or deployed backend. Offer the server-returned
|
|
394
|
+
methods, handle an unavailable or unsupported method, and test each enabled
|
|
395
|
+
rail with its provider. Wallets require their own provider and domain/device
|
|
396
|
+
configuration. Redirect/popup methods require allowed popups, return URLs,
|
|
397
|
+
content security policy and third-party access. Provider configuration and
|
|
398
|
+
scripts are separate from installing the npm package.
|
|
399
|
+
|
|
400
|
+
`PlaceOrderResult` contains `orderHash`, `free`, `needIdVerification`, and
|
|
401
|
+
optional `currency`, `paymentIntentId`, `alreadyPaid`, `pending` and
|
|
402
|
+
`pendingVoucherUrl`. `alreadyPaid` means the server reported a duplicate as
|
|
403
|
+
already paid; it does not mean this invocation charged again. OXXO vouchers and
|
|
404
|
+
PayPal can be pending. Show a pending state and voucher link if provided; wait
|
|
405
|
+
for authoritative confirmation before showing a paid receipt or fulfilling.
|
|
406
|
+
ID verification may still be required after payment. An ID-verification failure
|
|
407
|
+
is not a reason to repeat the charge.
|
|
408
|
+
|
|
409
|
+
**Zero-total orders:** this SDK ignores the free-registration response body and
|
|
410
|
+
reports `needIdVerification: false`. Verification or approval may still be
|
|
411
|
+
required, and `free: true` is not proof tickets were issued. The default inline
|
|
412
|
+
`EmbeddedCheckout` can nevertheless show confirmed or ticket-available copy
|
|
413
|
+
while approval or verification is still outstanding. Use
|
|
414
|
+
`confirmationMode="redirect"` with host-owned authoritative order and
|
|
415
|
+
verification status, or a custom composed confirmation gated on that status.
|
|
416
|
+
If the status is unavailable, contact support. Do not retry payment for a free
|
|
417
|
+
order.
|
|
418
|
+
|
|
419
|
+
`OrderConfirmation` is a reloadable presentation and does **not** check the
|
|
420
|
+
order's payment status before showing its default confirmed/ticket-availability
|
|
421
|
+
copy. Gate it on an authoritative status appropriate for that page. When
|
|
422
|
+
`onComplete` reports `pending`, show a pending page (and any voucher) instead;
|
|
423
|
+
do not route directly to `OrderConfirmation` as a paid receipt. The in-flow
|
|
424
|
+
`Confirmation` component reads the current result and has a pending state.
|
|
425
|
+
|
|
426
|
+
`CardInput` renders Stripe Elements and uses the checkout's default card owner;
|
|
427
|
+
`StripePaymentElement` is the deferred Elements option when its server config
|
|
428
|
+
and wallet gates are available. `XenditCardInput` renders Xendit card fields.
|
|
429
|
+
`Payment` wires the right input automatically. When implementing a custom pay
|
|
430
|
+
step, render the correct input for the selected gateway and keep it mounted and
|
|
431
|
+
visible for that payment. Do not collect raw card numbers in your own form or
|
|
432
|
+
logs. Multiple card flows must respect field ownership. With no explicit claim,
|
|
433
|
+
the web hook claims the default `checkout` owner's Payment Element if registered,
|
|
434
|
+
otherwise its `CardInput`, and refuses if neither is available. For a custom
|
|
435
|
+
owner, `claimCardField(owner)` claims a `CardInput` only; a
|
|
436
|
+
`StripePaymentElement` uses `cardClaimStep('webPaymentElement', () =>
|
|
437
|
+
webConfirmer.claimPaymentElement(owner))` as the `placeOrder` `claimCard` step.
|
|
438
|
+
For a bare card field, the `webCard` claim step should call
|
|
439
|
+
`webConfirmer.releasePaymentElement()` before `claimCardField(owner)`. The
|
|
440
|
+
standard `Payment` component handles these claims and key changes for you.
|
|
441
|
+
|
|
442
|
+
`useCheckout({ ports, options })` reads options on first render. The `ports`
|
|
443
|
+
option merges additional compatible web capabilities over the defaults, but its
|
|
444
|
+
type excludes `confirmer`; it cannot replace `webConfirmer`. `options` includes
|
|
445
|
+
`redirectReturnUrl` and merchant/wallet options. A custom confirmer belongs in
|
|
446
|
+
the lower-level `createEngine` configuration, not this web hook option.
|
|
447
|
+
|
|
448
|
+
The engine retains the order when it cannot establish whether a charge moved.
|
|
449
|
+
A custom confirmer should reject using `paymentProviderError(message, outcome)`;
|
|
450
|
+
`outcome` is `declined`, `cancelled`, `notStarted`, or `unknown`. Use the first
|
|
451
|
+
three only when the provider confirms nothing was charged. An unclassified
|
|
452
|
+
error is treated as unknown. Avoid automatic blind retries and never promise
|
|
453
|
+
exactly-once charging across your app, backend and provider.
|
|
454
|
+
|
|
455
|
+
## Authentication
|
|
456
|
+
|
|
457
|
+
The embedded checkout supplies the event to its built-in `AuthModal`. A
|
|
458
|
+
standalone modal can do the same. The host must already provide a query client
|
|
459
|
+
and initialize the SDK. The checkout callback is deliberately narrow.
|
|
224
460
|
|
|
225
461
|
```tsx
|
|
226
|
-
|
|
462
|
+
import { useState } from 'react'
|
|
463
|
+
import { AuthModal } from 'tf-checkout-react'
|
|
464
|
+
|
|
465
|
+
export function SignIn() {
|
|
466
|
+
const [open, setOpen] = useState(false)
|
|
467
|
+
return (
|
|
468
|
+
<>
|
|
469
|
+
<button onClick={() => setOpen(true)}>Sign in</button>
|
|
470
|
+
<AuthModal
|
|
471
|
+
open={open}
|
|
472
|
+
onClose={() => setOpen(false)}
|
|
473
|
+
checkoutEventId="EVENT_ID"
|
|
474
|
+
onCheckoutAuthenticated={() => setOpen(false)}
|
|
475
|
+
/>
|
|
476
|
+
</>
|
|
477
|
+
)
|
|
478
|
+
}
|
|
227
479
|
```
|
|
228
480
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
481
|
+
`AuthModal` props: `open` and `onClose` are required; optional
|
|
482
|
+
`checkoutEventId`, `onCheckoutAuthenticated`, `initialView`, `initialEmail`,
|
|
483
|
+
`message`, `allowRegistration` (default `true`), `allowPasswordReset` (default
|
|
484
|
+
`true`), `requireRegistrationAddress` (default `true`), `registrationFields`,
|
|
485
|
+
`logoUrl`, `onAuthenticated` and `className`. Public checkout auth requires its
|
|
486
|
+
registered client and matching deployed server contract. Browser checkout
|
|
487
|
+
authorization uses a popup with state and PKCE; secure browser crypto and
|
|
488
|
+
popups must be available. The popup may be blocked or closed, and two-factor
|
|
489
|
+
or email/phone proof can be required. Surface those outcomes rather than
|
|
490
|
+
assuming sign-in succeeded. The public checkout registration and account
|
|
491
|
+
completion paths force address collection even if `requireRegistrationAddress`
|
|
492
|
+
is `false`.
|
|
493
|
+
|
|
494
|
+
For a custom UI, `hooks.useAuthFlow(options)` owns authentication state,
|
|
495
|
+
validation and transitions, while `LoginForm`, `RegisterForm`,
|
|
496
|
+
`ForgotPasswordForm`, `ResetPasswordForm`, `TwoFactorForm`, `EmailCodeForm` and
|
|
497
|
+
`PhoneAuthView` provide forms/views. `LoginForm` requires `onSubmit`;
|
|
498
|
+
`RegisterForm` requires `onSubmit`; `ForgotPasswordForm` requires `onSubmit`
|
|
499
|
+
and `onBackToLogin`; `ResetPasswordForm` requires a reset `token`.
|
|
500
|
+
`TwoFactorForm` and `EmailCodeForm` are controlled views with required state and
|
|
501
|
+
callbacks; `PhoneAuthView` requires a `PhoneAuthenticationFlow`. Their exported
|
|
502
|
+
`*Props` types document every field. The individual controlled forms do not
|
|
503
|
+
turn an arbitrary callback into a complete authenticated session; use the
|
|
504
|
+
appropriate flow and handle all its states.
|
|
505
|
+
|
|
506
|
+
## Component reference
|
|
507
|
+
|
|
508
|
+
Props shown without `?` are required. All named `*Props` types below are
|
|
509
|
+
exported unless stated otherwise; TypeScript declarations in the installed
|
|
510
|
+
package are the authoritative detail for callback payloads and DTOs.
|
|
511
|
+
|
|
512
|
+
### Checkout sections
|
|
513
|
+
|
|
514
|
+
| Export | Props and purpose |
|
|
515
|
+
| --- | --- |
|
|
516
|
+
| `Tickets` | `eventId`, `title?`, `onContinue?`, `buttonLabel?`, `timeSlotDates?` (ISO dates), `step?`, `onSelectSeats?`, `initialPromoCode?`, `referrer?`, `readAttributionFromUrl?`, `className?`. `onContinue` fires after the cart is primed. |
|
|
517
|
+
| `SeatMap` | `eventId`, `onContinue?`, `step?`, `className?`. Callback fires after seats are added and priced. |
|
|
518
|
+
| `AddOns` | `eventId`, `onContinue?`, `onSkip?`, `buttonLabel?`, `eyebrow?`, `heading?`, `className?`. Skip is hidden for a required add-on. |
|
|
519
|
+
| `Bundles` | `eventId`, `onPurchased?(orderHash)`, `onComplete?(order)`, `confirmationMode?`, `visible?`, `heading?`, `className?`. Bundle purchase is its own flow; hide its card field using `visible` when the section is hidden. |
|
|
520
|
+
| `BillingInfo` | `eventId?`, `onContinue?`, `heading?`, `buttonLabel?`, `onLogin?`, `skipWhenProfileComplete?`, `requireEmailConfirmation?`, `collectTicketHolders?`, `collectHolderContact?`, `ttfOptInLabel?`, `brandOptInLabel?`, `privacyPolicy?`, `showPrivacyError?`, `step?`, `className?`. Standalone holder collection follows backend gates unless explicitly enabled. |
|
|
521
|
+
| `WaiverSigning` | `eventId`, `className?`. Render before payment for an event requiring a waiver. |
|
|
522
|
+
| `Payment` | `onComplete?`, `eventId?`, `requireEmailConfirmation?`, `collectTicketHolders?`, `requireHolderContact?`, `additionalConditions?`, `requirePrivacyPolicy?`, `onPrivacyRequired?`, `showTestCardHint?`, `className?`. Match the paired billing policies. |
|
|
523
|
+
| `OrderSummary` | `eventId?`, `className?`. Uses the current checkout's pricing. |
|
|
524
|
+
| `IDVerification` | `className?`. Uses the current checkout/order. |
|
|
525
|
+
| `Confirmation` | `shareUrl?`, `shareMessage?`, `viewOrderUrl?`, `children?`, `className?`. Uses the current checkout result and handles pending presentation. The default share URL and eligibility have the limitations below. |
|
|
526
|
+
| `OrderConfirmation` | `orderHash`, `title?`, `message?`, `helper?`, `eventTitle?`, `eventDate?`, `eventLocation?`, `viewOrderUrl?` (string or function), `showReferral?`, `showShareButtons?`, `showRewards?`, `snapchat?`, `onLoaded?`, `onError?`, `className?`. Reloads confirmation by hash; the host must gate it on appropriate payment status. The three `show*` options default to true; Snapchat defaults to false. |
|
|
527
|
+
| `OrderIDVerification` | `orderHash`, `onVerified?`, `className?`. For a separately routed order. |
|
|
528
|
+
| `Rewards` | `orderHash?`, `data?`, `snapchat?`, `className?`. Supply an order hash or an already loaded `RewardsPayload`; `data` avoids a fetch. |
|
|
529
|
+
| `TicketChange` | `ticketHash`, `orderHash?`, `onChanged?`, `openUrl?`, `onLogin?`, `className?`. Change/upgrade availability and any upgrade waitlist come from server options. |
|
|
530
|
+
| `Accommodation` | `eventId`. Renders the accommodation selection for an applicable cart; requires checkout context. |
|
|
531
|
+
|
|
532
|
+
`Confirmation` defaults `shareUrl` to `window.location.href`, displays generic
|
|
533
|
+
referral copy for non-pending orders, and does not check organizer referral
|
|
534
|
+
eligibility. The current URL may include unrelated query parameters or lack a
|
|
535
|
+
buyer-specific referral. `EmbeddedCheckout` does not expose a `shareUrl` prop.
|
|
536
|
+
For a composed `Confirmation`, pass a verified buyer-specific URL when eligible,
|
|
537
|
+
or `shareUrl=""` to suppress sharing. Alternatively use server-backed
|
|
538
|
+
`OrderConfirmation` / `Rewards` where the appropriate status and response
|
|
539
|
+
support the experience. Check eligibility and attribution against the deployed
|
|
540
|
+
backend; don't treat the generic link as evidence of a referral.
|
|
541
|
+
|
|
542
|
+
`OrderConfirmation` includes `Rewards` when its response has a rewards
|
|
543
|
+
payload unless `showRewards={false}`. `Rewards` can also fetch by hash without a
|
|
544
|
+
React Query provider. Sharing channels depend on organizer configuration and
|
|
545
|
+
browser capabilities. Snapchat is opt-in and loads `sdk.snapkit.com`; allow it
|
|
546
|
+
in the host's CSP only if used. Clipboard and share operations can be denied by
|
|
547
|
+
the browser or buyer. `RewardsLadder` (`rows`, `onSubmitDetails?`,
|
|
548
|
+
`className?`), `RewardsTree` (`tree`, `className?`), `RewardsChannels`
|
|
549
|
+
(`channels`, `shareLink`, `shareMessage`, `assertCurrent?`,
|
|
550
|
+
`shareCardImageUrl?`, `snapchat?`, `className?`), and `RewardsPackCard`
|
|
551
|
+
(`pack`, `onCreate`, `onJoin`, `onLeave`, `assertCurrent?`) are available for
|
|
552
|
+
custom reward layouts.
|
|
553
|
+
|
|
554
|
+
An upgrade waitlist is a separate server-owned ticket-change contract. Valid
|
|
555
|
+
change-options targets can expose Join or Leave only when the backend offers
|
|
556
|
+
that organizer-configured flow. A sold-out row alone does not authorize it;
|
|
557
|
+
malformed targets or entries are ignored. Verify the deployed contract and
|
|
558
|
+
confirm the server response before presenting an action as completed.
|
|
559
|
+
|
|
560
|
+
### Account, post-purchase and discovery
|
|
561
|
+
|
|
562
|
+
These exports are available in the package, but availability and required
|
|
563
|
+
account authority vary by endpoint. A public checkout buyer is not automatically
|
|
564
|
+
a full account user. Supply a host sign-in/route callback where applicable.
|
|
565
|
+
|
|
566
|
+
| Export | Props and purpose |
|
|
567
|
+
| --- | --- |
|
|
568
|
+
| `TicketRefund` | `ticketHash`, `onSubmitted?`, `onDone?`. Presents offered refund options and submission. |
|
|
569
|
+
| `TicketGift` | `ticketHash`, `onTicketsChanged?`, `onDone?`, `locale?`. Gift flow. |
|
|
570
|
+
| `Passes` | `onTicketsChanged?`, `locale?`. Customer passes and booking actions. |
|
|
571
|
+
| `Trips` | `onOpen(url)`, `onPage(query)`, `data?`, `locale?`, `loading?`, `errorMessage?`, `onRetry?`. Host supplies data and navigation. |
|
|
572
|
+
| `AccountProfile` | `onSaved?(profile, action)`. Profile gender/image actions. |
|
|
573
|
+
| `AccountInformationSection` | `orderId`, `title?`, `target?`, `locale?`, `active?`, `onSaved?`. Order information/answers. |
|
|
574
|
+
| `AccountPaymentPlanSection` | `plan`, `orderHash`, `locale?`, `onOpen?`, `onReturn?`. Payment-plan management for an existing order. |
|
|
575
|
+
| `AccountRewardsSection` | `locale?`, `onBrowseEvents?`, `onViewTickets?`. Account rewards summary. |
|
|
576
|
+
| `AccountDeletion` | `showHeader?`, `showExplanation?`, `locale?`, `onSignIn?`, `onDone?`, `onOpenTeam?`. `AccountDeletionView` additionally requires a `deletion` flow. |
|
|
577
|
+
| `NotificationPreferences` | `locale?`, `onBack?`, `onSignIn?`, `onSaved?`. `NotificationPreferencesView` additionally requires a `preferences` flow. |
|
|
578
|
+
| `ProfileSettings` | `mode: 'links' \| 'visibility'`, `onBack?`, `onSignIn?`. `ProfileSettingsView` additionally requires a `settings` flow. |
|
|
579
|
+
| `AccountEmailEnrichment` | No props. `AccountEmailEnrichmentView` requires `flow`. |
|
|
580
|
+
| `PhoneAccountProfile` | No props. Phone account profile view. |
|
|
581
|
+
| `Interests` | `onSignIn?`. Interest selection. |
|
|
582
|
+
| `Streaming` | `onSignIn?`, `onOpenMusic?(url, provider?)`. Music connections. |
|
|
583
|
+
| `Friends` | `initialCode?`, `onSignIn?`. Friend flows. |
|
|
584
|
+
| `SavedEvents` | `onSignIn?`. Saved-event list. |
|
|
585
|
+
| `Recommendations` | `events`, `enabled?`. Recommendations from the supplied `AccountEvent[]`. |
|
|
586
|
+
| `EventComments` | `eventId`, `previewKey?`, `onSignIn?`, `className?`. Discussion with backend-supplied permissions. `EventCommentsView` accepts a supplied discussion flow. |
|
|
587
|
+
| `PostReaction` | `postId: string \| number`, `onSignIn?`. `PostReactionControls` accepts `flow` and `onSignIn?`. |
|
|
588
|
+
| `DiscoveryTravel` | `searchCities`, `searchEvents`, `storage?`, `locale?`. Host supplies search functions; see `DiscoveryTravelProps` for their signatures. |
|
|
589
|
+
|
|
590
|
+
For account orders and ticket lists use `hooks.useOrders`, `hooks.useOrder`,
|
|
591
|
+
`ttf.orders.list`, `ttf.orders.get` or `ttf.orders.myTickets`. In this version
|
|
592
|
+
`ttf.orders.get` / `useOrder` take a **numeric order ID string**, not a public
|
|
593
|
+
order hash; `OrderConfirmation` takes a hash. The package does not export 1.x
|
|
594
|
+
`MyTicketsContainer`, `OrdersContainer`, `OrderDetailsContainer` or
|
|
595
|
+
`TicketResaleContainer` as drop-in React replacements. Account/resale APIs and
|
|
596
|
+
hooks can support a host-built screen when the appropriate account session and
|
|
597
|
+
backend capabilities exist.
|
|
598
|
+
|
|
599
|
+
### UI primitives
|
|
600
|
+
|
|
601
|
+
Use these within a `.tf-checkout` styling boundary such as `CheckoutProvider`;
|
|
602
|
+
standard HTML attributes apply where the component extends them.
|
|
603
|
+
|
|
604
|
+
| Export | Important props |
|
|
605
|
+
| --- | --- |
|
|
606
|
+
| `Card` | HTML `div` attributes and children. |
|
|
607
|
+
| `SectionHeader` | `title`, `step?`, `pills?`, `className?`. |
|
|
608
|
+
| `Pill` | `children`, `muted?`. |
|
|
609
|
+
| `Button` | Button attributes, `variant?: 'primary' \| 'secondary' \| 'ghost'`, `block?`, `loading?`. |
|
|
610
|
+
| `Field` | `children`, `label?`, `error?`, `invalid?`, `className?`; `FieldRow` takes `children`, `className?`. |
|
|
611
|
+
| `Input`, `Textarea`, `Select` | Corresponding HTML attributes plus `invalid?`. |
|
|
612
|
+
| `Checkbox` | Input attributes plus `label?`. |
|
|
613
|
+
| `CustomFieldInput` | `field`, `value`, `onChange`, `error?`. |
|
|
614
|
+
| `CustomFieldGroupFields` | `group`, `values`, `onChange(name, value)`, `ticketTypeId?`; `customFieldsComplete` is also exported. |
|
|
615
|
+
| `PaymentMethods` | Controlled `options`, `selected`, `onSelect`, `extraValues`, `onExtraChange`; optional `showValidation`, `children`, `inputSlotFor`, `className`. |
|
|
616
|
+
| `Stepper` | `value`, `onChange`, `min?`, `max?`, `step?`, `disabled?`, `className?`. |
|
|
617
|
+
| `QuantitySelect` | `value`, `onChange`, `min?`, `max?`, `step?`, `disabled?`, `className?`, accessible `label?`. |
|
|
618
|
+
| `PriceLine` | `amount`, `currency?`, `original?`, `note?`, `className?`. |
|
|
619
|
+
| `Timer` | `seconds`, `urgentAt?`, `label?`, `className?`. `TimerBanner` takes `seconds?`, `urgentAt?`, `message?`, `className?`. |
|
|
620
|
+
| `Loader` | `className?`. |
|
|
621
|
+
| `SignaturePad` | `label`, `clearLabel`, `onChange(pngDataUrl, inkLength)`, `disabled?`. |
|
|
622
|
+
| `FrozenFields` | `children`, `frozen?`; disables interaction for its nested fields. |
|
|
623
|
+
|
|
624
|
+
Additional web exports include `themeToVars`, `cx`, `I18nProvider`, `useT`,
|
|
625
|
+
`useInstallmentPicker`, `CardInput`, `StripePaymentElement`, `XenditCardInput`,
|
|
626
|
+
`claimCardField`, `webConfirmer`, `webPorts`, `webXenditTokenizer`, and the
|
|
627
|
+
`createWebStripeConfirmer`, `createWebPorts`, `createWebXenditTokenizer`
|
|
628
|
+
factories. Their installed declarations specify complete inputs and outputs.
|
|
629
|
+
These are lower-level integration points; preserve their payment and session
|
|
630
|
+
ownership rules when replacing the default flow.
|
|
631
|
+
|
|
632
|
+
## Headless APIs
|
|
633
|
+
|
|
634
|
+
`useCheckout()` returns the snapshot both flat and as `snapshot`, plus actions.
|
|
635
|
+
The web version injects browser payment ports; the shared `hooks.useCheckout`
|
|
636
|
+
is the lower-level binding and requires an engine configuration. The following
|
|
637
|
+
example only reserves caller-supplied current catalog selections. It deliberately
|
|
638
|
+
does not place an order without collecting the event's required data.
|
|
239
639
|
|
|
240
640
|
```tsx
|
|
641
|
+
import { useState } from 'react'
|
|
241
642
|
import { useCheckout, type TicketSelection } from 'tf-checkout-react'
|
|
242
643
|
|
|
243
|
-
function
|
|
644
|
+
export function ReserveButton(props: {
|
|
645
|
+
eventId: string
|
|
646
|
+
selections: TicketSelection[]
|
|
647
|
+
}) {
|
|
244
648
|
const checkout = useCheckout()
|
|
245
|
-
|
|
649
|
+
const [message, setMessage] = useState('')
|
|
650
|
+
async function reserve() {
|
|
651
|
+
try {
|
|
652
|
+
await checkout.setTickets(props.eventId, props.selections)
|
|
653
|
+
setMessage('Tickets reserved')
|
|
654
|
+
} catch (error) {
|
|
655
|
+
setMessage(error instanceof Error ? error.message : 'Could not reserve tickets')
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return (
|
|
659
|
+
<div>
|
|
660
|
+
<button disabled={checkout.isBusy} onClick={() => void reserve()}>
|
|
661
|
+
Reserve
|
|
662
|
+
</button>
|
|
663
|
+
<p role="status">{message}</p>
|
|
664
|
+
</div>
|
|
665
|
+
)
|
|
246
666
|
}
|
|
247
667
|
```
|
|
248
668
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
`
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
`
|
|
271
|
-
|
|
272
|
-
`
|
|
273
|
-
(
|
|
274
|
-
|
|
669
|
+
A `TicketSelection` has `id` (current encrypted ticket ID), `name`,
|
|
670
|
+
`optionName`, `price`, `quantity` and `currency`. Construct it from the
|
|
671
|
+
current catalog, not a stale cached display row. Do not trust client-side prices
|
|
672
|
+
as the final order amount.
|
|
673
|
+
|
|
674
|
+
### Snapshot and actions
|
|
675
|
+
|
|
676
|
+
| Field / action | Contract |
|
|
677
|
+
| --- | --- |
|
|
678
|
+
| `status`, `error`, `order`, `eventId`, `expiresAt`, `secondsLeft`, `isBusy` | Progress, latest error/result and reservation timing. `error` is a display string; async actions may also reject. |
|
|
679
|
+
| `selections`, `ticketTypeIds`, `addOns`, `breakdown`, `priceBreakdown` | Cart selections, decrypted ticket type IDs and server pricing. Prefer server-priced output for display. |
|
|
680
|
+
| `customFields`, `buyerFields`, `fieldGates`, `holderNamesRequired`, `requiredAddOns`, `missingRequiredAddonNames` | Inputs and event gates. Required add-ons sold out are exempt from the missing-add-on check. |
|
|
681
|
+
| `billing`, `holders`, `consent`, `conditions`, `acceptedConditions`, `existingAccountEmail` | Buyer draft and acceptance state. `checkBuyerEmail(email)` starts an existing-account check and writes the result to the snapshot. |
|
|
682
|
+
| `waiver`, `waiverSignatures`, `waiverSigningIndexes`, `unavailableDetails`, `orderFixed` | Waiver and order-edit state. Forms are frozen while placing or after the order is charged. |
|
|
683
|
+
| `gateway`, `stripe`, `paymentStripe`, `paymentPlan`, `redirectPaymentMethods`, `walletAvailability`, `stripeElementsConfig`, `currency` | Payment/configuration data after priming. Absence does not authorize a method. |
|
|
684
|
+
| `extraItems`, `extraDraft`, `extraQuotes`, `extraRejections`, `extraExpiresAt`, `reviewedExtraOrderTotal` | Accommodation/extras state and changed authoritative total. Show a changed total before another Pay action. |
|
|
685
|
+
| `setTickets(eventId, selections)`, `setSeats(eventId, lines)`, `setSeatsIo(eventId, selection)`, `resumeCart(eventId, options?)` | Build/price or resume a server cart; return promises. |
|
|
686
|
+
| `setAddons(addOns)`, `setExtraItems(items)` | Reprice/reserve selections asynchronously. `setExtraDraft(items \| undefined)` changes the local draft. |
|
|
687
|
+
| `setBilling(billing)`, `setHolders(holders, options?)`, `setConsent(consent)` | Commit buyer, holder and marketing data. `setHolders` can mark backfilled holder indexes. |
|
|
688
|
+
| `setAcceptedConditions(map)`, `acceptCondition(id, accepted)`, `setAddonDataCapture(map)` | Record condition acceptance and add-on answers. |
|
|
689
|
+
| `setWaiverSignature(index, signature, hold?)`, `holdWaiverSigning(index)` | Coordinate a signature save with the cart/holder it belongs to; release a hold when finished. Prefer `WaiverSigning` for standard UI. |
|
|
690
|
+
| `reloadCheckoutDetails()`, `syncCurrency(eventId, code?, options?)` | Retry unavailable details or switch/seed event currency. Refresh selection and prices after changing currency. |
|
|
691
|
+
| `placeOrder(method?, options?)`, `runIdVerification(orderHash, options?)` | Place/pay; optionally run verification separately. `placeOrder` accepts `autoRunIdVerification`, `idVerification` and `claimCard` options. |
|
|
692
|
+
| `applyPromoCode(eventId, code)`, `attributeReferrer(eventId, referrer)`, `joinWaitingList(eventId, entry)` | Helpers return promises. Refetch catalog after a code changes availability. |
|
|
693
|
+
| `reset()`, `resetWhenSettled()` | Restart subject to payment-settlement protection; see [lifecycle](#checkout-lifecycle). |
|
|
694
|
+
| `snapshot`, `store`, `isLoggedIn` | Entire state, shared store, and whether the hook sees an authenticated or checkout buyer session. The latter does not imply private-account authority. |
|
|
695
|
+
|
|
696
|
+
`checkBuyerEmail` is not itself debounced. `BillingInfo` delays calls, but a
|
|
697
|
+
headless host should debounce and coordinate in-flight checks. A late response
|
|
698
|
+
for an earlier email in the same cart can overwrite the snapshot; compare
|
|
699
|
+
`existingAccountEmail` with the current trimmed input before prompting and
|
|
700
|
+
recheck the current value if needed.
|
|
701
|
+
|
|
702
|
+
`CheckoutBilling` requires `firstName`, `lastName`, `email`; optional fields
|
|
703
|
+
include `confirmEmail`, `phone`, address, country/state IDs and codes, date of
|
|
704
|
+
birth, nationality, gender, Instagram and `dataCapture`. `CheckoutHolder`
|
|
705
|
+
requires `firstName`, `lastName`, `email`; optional `phone`, `ticketTypeId`,
|
|
706
|
+
`ticketDataCapture`. `CheckoutConsent` has boolean `ttfOptIn` and
|
|
707
|
+
`brandOptIn`. Event gates may require additional data even where the TypeScript
|
|
708
|
+
property is optional. `confirmEmail` is a UI/preflight value; the order request
|
|
709
|
+
uses the authoritative email.
|
|
710
|
+
|
|
711
|
+
`PaymentMethod` accepts `'card'`, `'applePay'` or `'googlePay'`.
|
|
712
|
+
`PaymentRequest` additionally accepts objects with `method: 'auto'`, `'card'`,
|
|
713
|
+
`'applePay'`, `'googlePay'`, `'redirect'` (`methodType`), `'oxxo'`,
|
|
714
|
+
`'xenditEWallet'` (`walletKey`, optional `extra.cashtag` / `extra.phoneNumber`),
|
|
715
|
+
`'paypal'`, `'razorpay'` (optional `description`), `'adyen'`, `'xenditCard'`,
|
|
716
|
+
or `'paymentPlan'` (optional `useSavedCard`). Availability and necessary ports
|
|
717
|
+
are provider-specific. `placeOrder()` defaults to card; do not use that default
|
|
718
|
+
for a different gateway.
|
|
719
|
+
|
|
720
|
+
### React Query hooks and direct API
|
|
721
|
+
|
|
722
|
+
The package re-exports the shared core: `ttf` is a configured domain facade,
|
|
723
|
+
`api` contains raw calls, `hooks` contains React bindings, and DTOs, logic,
|
|
724
|
+
`createEngine` and `createCheckoutStore` are named exports. `ttf` calls return
|
|
725
|
+
promises; they do not render UI or replace the engine's sequencing, payment
|
|
726
|
+
ownership and preflight. Use them directly only when your application owns the
|
|
727
|
+
corresponding workflow. The installed `dist/index.d.ts` includes the complete
|
|
728
|
+
exported signatures. Avoid importing a private shared-core package.
|
|
275
729
|
|
|
276
730
|
```tsx
|
|
277
|
-
|
|
278
|
-
if (!(await checkout.resetWhenSettled())) setNotice(PAID_ORDER_PENDING_MESSAGE)
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
A custom `providerPage` must resolve `{ event: 'dismiss' }` when it closes or
|
|
282
|
-
unmounts, and other custom ports must settle too, or `resetWhenSettled()` waits.
|
|
731
|
+
import { hooks } from 'tf-checkout-react'
|
|
283
732
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
For direct API access, the shared SDK exports are available from this package,
|
|
291
|
-
including `ttf`, hooks, types and the engine. The package's TypeScript
|
|
292
|
-
declarations describe its public exports.
|
|
293
|
-
|
|
294
|
-
## Card fields
|
|
295
|
-
|
|
296
|
-
`<CardInput />` renders Stripe Elements. `<XenditCardInput />` renders the
|
|
297
|
-
Xendit card form for gateways that use it — both are wired into `<Payment />`
|
|
298
|
-
automatically based on the event's gateway, so you only reach for them directly
|
|
299
|
-
when building a custom payment step.
|
|
300
|
-
|
|
301
|
-
## Development
|
|
302
|
-
|
|
303
|
-
From the repo root:
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
pnpm run start:react
|
|
733
|
+
export function CatalogStatus({ eventId }: { eventId: string }) {
|
|
734
|
+
const catalog = hooks.useTicketsWithMeta(eventId)
|
|
735
|
+
if (catalog.isPending) return <p>Loading tickets…</p>
|
|
736
|
+
if (catalog.isError) return <button onClick={() => void catalog.refetch()}>Retry</button>
|
|
737
|
+
return <p>{catalog.data.tickets.length} ticket types</p>
|
|
738
|
+
}
|
|
307
739
|
```
|
|
308
740
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
`
|
|
323
|
-
`
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
741
|
+
Useful hook groups, all imported through `hooks`:
|
|
742
|
+
|
|
743
|
+
- Catalog: `useEvent`, `useTickets`, `useTicketsWithMeta`,
|
|
744
|
+
`useTimeSlotTickets`, `useEventAddons`, `useEventBundles`, `useTicketCatalog`,
|
|
745
|
+
`useCountries`, `useStates`.
|
|
746
|
+
- Authentication/session: `useAuthFlow`, `useAuthSession`, `useLogin`,
|
|
747
|
+
`useRegister`, `useLogout`, `useProfile`, `usePhoneAuthentication` and
|
|
748
|
+
verification mutations. Choose the correct public checkout or account path.
|
|
749
|
+
- Checkout/selection: `useCheckout`, `useAddOnSelection`, `useSeatSelection`,
|
|
750
|
+
`useSeatsIoSelection`, `useWaitingListForm`, `useWaiverSigning`,
|
|
751
|
+
`useAccommodationSelection`, `useCheckoutPaymentMethods`, `useBundleFlow`.
|
|
752
|
+
- After purchase/account: `useOrders`, `useOrder`, `useOrderRewards`,
|
|
753
|
+
`useTicketChange`, `useTicketRefund`, `useTicketGift`, `useCustomerPasses`,
|
|
754
|
+
`useAccountPreferences`, `useNotificationPreferences`, `useAccountDeletion`,
|
|
755
|
+
`useFriends`, `useEventComments`, `useTrips`.
|
|
756
|
+
|
|
757
|
+
Catalog hooks use an event ID and many are disabled until it is present; query
|
|
758
|
+
results expose standard React Query loading, error, data and `refetch` states.
|
|
759
|
+
The account-order query uses a numeric order ID. Account access is scoped to the
|
|
760
|
+
buyer session; don't reuse private cached data across sign-out or buyer changes.
|
|
761
|
+
|
|
762
|
+
The `ttf` facade groups calls under `auth`, `profile`, `events`, `cart`,
|
|
763
|
+
`order`, `payment`, `seatmap`, `engagement`, `confirmation`, `rewards`,
|
|
764
|
+
`orders`, `ticketChanges`, `resale`, `refunds`, `gifts`, `passes`, `waivers`,
|
|
765
|
+
`extras`, `trips`, `preferences`, `friends`, `savedEvents`, `comments`, `word`,
|
|
766
|
+
`preRegistration` and `delegation`. For example, `ttf.events.ticketsWithMeta`
|
|
767
|
+
loads a catalog, `ttf.geo.countries()` loads country choices, and
|
|
768
|
+
`ttf.confirmation.get(orderHash)` reads a confirmation. The `geo` group is
|
|
769
|
+
also available. Check each method's declared input and backend authority before
|
|
770
|
+
calling it.
|
|
771
|
+
|
|
772
|
+
Transport errors are normalized as `TtfError`, with `message`, HTTP `status`
|
|
773
|
+
(`0` for transport failure), optional `code`, `data` and `retryAfter` seconds.
|
|
774
|
+
Engine validation and provider errors can also be ordinary errors or typed
|
|
775
|
+
errors such as `UNSUPPORTED_GATEWAY`; handle unknown errors as well. Avoid
|
|
776
|
+
logging raw error data if it may contain personal or payment information.
|
|
777
|
+
|
|
778
|
+
### Tracking
|
|
779
|
+
|
|
780
|
+
For an integration that is authorized to send event tracking, the explicit
|
|
781
|
+
facade call is `ttf.events.track(eventId, { pageUrl?, page?, orderHash? })`.
|
|
782
|
+
The host owns when it fires, consent, deduplication and any additional analytics
|
|
783
|
+
pixels. No 1.x pixel setup or automatic event equivalence should be assumed.
|
|
784
|
+
Avoid sending unnecessary buyer data in URLs or analytics.
|
|
785
|
+
|
|
786
|
+
## Styling and localization
|
|
787
|
+
|
|
788
|
+
Pass a `theme` to `EmbeddedCheckout`, `ResumedCheckout` or `CheckoutProvider`.
|
|
789
|
+
All tokens are optional:
|
|
790
|
+
|
|
791
|
+
| Group | `CheckoutTheme` keys |
|
|
792
|
+
| --- | --- |
|
|
793
|
+
| Scheme | `colorScheme: 'light' \| 'dark'`; when omitted CSS follows the browser/OS preference. |
|
|
794
|
+
| Colors | `accent`, `accentHover`, `accentContrast`, `surface`, `surfaceMuted`, `text`, `muted`, `border`, `error`, `success`. |
|
|
795
|
+
| Shape | `radiusCard`, `radiusControl`, `shadow`. |
|
|
796
|
+
| Type/layout | `font`, `fontSize`, `maxWidth`. |
|
|
797
|
+
|
|
798
|
+
Values are CSS strings mapped to `--tf-checkout-*` custom properties. The
|
|
799
|
+
provider adds `.tf-checkout` and optionally `.tf-checkout--light` or
|
|
800
|
+
`.tf-checkout--dark`; section classes use `tf-checkout-*`. Theme variables and
|
|
801
|
+
classes can be overridden by your CSS, but test embedded Stripe iframes and
|
|
802
|
+
third-party phone/seat-map styling separately. Stripe Elements do not inherit
|
|
803
|
+
page CSS directly. Preserve readable contrast, visible focus and usable error
|
|
804
|
+
states in custom themes.
|
|
805
|
+
|
|
806
|
+
`locale` defaults to `en-GB`; accepted `LocaleCode` values are `en-GB`,
|
|
807
|
+
`en-US`, `es-MX`, `fr`, `de`, `ru`, and `id`. Catalogues can be partial and
|
|
808
|
+
fall back to English; verify all buyer-facing copy for your event. Pass
|
|
809
|
+
`messages` for per-key overrides, or use `I18nProvider` / `useT` around
|
|
810
|
+
standalone components. Event-supplied content and provider pages may have
|
|
811
|
+
their own language. Test keyboard navigation, screen readers, validation focus,
|
|
812
|
+
small screens, reduced motion, popups, and the entire host page; an SDK control
|
|
813
|
+
alone cannot guarantee accessibility of the surrounding experience.
|
|
814
|
+
|
|
815
|
+
## Migrating from 1.x
|
|
816
|
+
|
|
817
|
+
2.x is a new shared-core integration, not a prop-compatible update. Keep the
|
|
818
|
+
existing 1.x integration pinned until the new flow and backend are verified.
|
|
819
|
+
There is no automatic translation of old URLs, component props, account
|
|
820
|
+
sessions or persisted 1.x state.
|
|
821
|
+
|
|
822
|
+
| 1.x integration | 2.0.0-beta.25 approach |
|
|
823
|
+
| --- | --- |
|
|
824
|
+
| `setConfigs({ BASE_URL, ... })` | `configureCheckout({ env` or `baseUrl`, `clientId`, `clientSecret: ''`, ... `})`; public client registration and session setup are required. |
|
|
825
|
+
| `TicketsContainer`, `SeatMapContainer`, `AddOnsContainer` | `EmbeddedCheckout` or `Tickets`, `SeatMap`, `AddOns` under `CheckoutProvider`. Adapt callbacks and navigation. |
|
|
826
|
+
| `BillingInfoContainer`, `PaymentContainer` | `BillingInfo` and `Payment` with matched policies and the current cart; or embedded flow. Old prop names/callbacks are not a contract. |
|
|
827
|
+
| `ConfirmationContainer` | `Confirmation` for the active flow or `OrderConfirmation` for a reloadable order-hash page. Handle `pending` and ID verification. |
|
|
828
|
+
| Legacy login/register/forgot-password modals | `AuthModal` or `hooks.useAuthFlow` and controlled forms. Distinguish event-scoped checkout identity from a full account session. |
|
|
829
|
+
| `AccountSettings` | No same-named drop-in replacement is established. Evaluate `AccountProfile`, `ProfileSettings`, `NotificationPreferences` and the account APIs against your required authorized account features. |
|
|
830
|
+
| `MyTicketsContainer`, order/detail and resale containers | No same-named drop-in component in this version. Use supported account APIs/hooks and build the host UI after verifying authorization and deployed backend support. |
|
|
831
|
+
| Webflow/no-code integration | No 2.x drop-in Webflow or no-code checkout integration has been established. Integrate the React checkout in a compatible host or verify a separate integration with Ticket Fairy. |
|
|
832
|
+
| Promo/access, waiting list, pixel and referral behavior | Re-check catalog metadata, code/attribution precedence, waiting-list contract and explicit tracking. Do not infer numeric `?r=`. |
|
|
833
|
+
| Legacy single-page state in localStorage | Use the 2.x checkout store/engine and server cart; do not copy sensitive state or assume 1.x persisted state can be resumed. |
|
|
834
|
+
|
|
835
|
+
Compare the exact event's ticket types, dated pricing, seats, add-ons, holder
|
|
836
|
+
questions, conditional fields, consent, waivers, fees, currencies, payment
|
|
837
|
+
methods, account and post-purchase behavior before switching. Backend rollout
|
|
838
|
+
and provider acceptance are independent of the npm package publication.
|
|
839
|
+
|
|
840
|
+
The distribution includes standalone widget JavaScript and CSS bundles for
|
|
841
|
+
other product surfaces. Their presence alone does not establish a supported
|
|
842
|
+
public checkout-widget API or a 2.x Webflow integration; use the documented
|
|
843
|
+
React exports unless a separate integration contract has been verified.
|
|
844
|
+
|
|
845
|
+
## Testing and troubleshooting
|
|
846
|
+
|
|
847
|
+
Use a non-production event and provider test configuration. Exercise at least:
|
|
848
|
+
|
|
849
|
+
1. A general-admission purchase, free registration, multi-quantity holders,
|
|
850
|
+
required and unavailable add-ons, custom questions and waiver; inspect
|
|
851
|
+
server-priced totals before payment.
|
|
852
|
+
2. Seated/time-slot and multi-currency events if used; expiry, sold-out changes,
|
|
853
|
+
promo/access codes, explicit referral attribution and waiting-list states.
|
|
854
|
+
3. Guest, existing-account, sign-in, two-factor and sign-out/buyer-switch flows;
|
|
855
|
+
verify no prior buyer's cart or private data is shown to the next buyer.
|
|
856
|
+
4. Every enabled provider: success, decline, cancellation, blocked popup,
|
|
857
|
+
redirect return, offline/timeout and asynchronous pending settlement. Check
|
|
858
|
+
the authoritative order/provider before any retry or fulfilment.
|
|
859
|
+
5. Refresh, back navigation, multiple clicks, a delayed response, small-screen
|
|
860
|
+
and keyboard/screen-reader flows. Test on the actual supported browsers,
|
|
861
|
+
configured origins and deployment environment.
|
|
862
|
+
|
|
863
|
+
| Symptom | Check |
|
|
864
|
+
| --- | --- |
|
|
865
|
+
| "SDK is not configured" | Run `configureCheckout` before mounting any SDK component or calling `ttf`. |
|
|
866
|
+
| Query context error | Wrap the relevant tree in a `QueryClientProvider` using the same React Query instance as the SDK. |
|
|
867
|
+
| No styles / CSS build error | Confirm the bundler processes package CSS, nested `@import`s and assets. Check the package entry and stylesheet export. |
|
|
868
|
+
| Login fails or popup closes | Verify the public client, event, deployed auth route, secure browser crypto, popup permission, origin/cookie/CORS settings and any required proof step. |
|
|
869
|
+
| Cart or pricing missing | Verify the event/environment, current ticket IDs, availability, session, network response and that reservation completed. Re-fetch after a code or currency change. |
|
|
870
|
+
| No seat button | The event must offer seating; a composed `Tickets` needs `onSelectSeats` connected to a `SeatMap` view. |
|
|
871
|
+
| Pay is disabled / validation error | Check buyer and holder rules, required add-ons/answers/conditions, privacy acknowledgement, waiver state and cart expiry. Use matching billing and payment policies. |
|
|
872
|
+
| Payment method unavailable | Check the event's returned method list, merchant/currency/device/provider setup, popup/CSP and backend rollout. A union member alone does not enable a rail. |
|
|
873
|
+
| Payment is pending or outcome uncertain | Show the pending state, retain the order and reconcile with the backend/provider. Do not blindly reset, charge again or fulfil. |
|
|
874
|
+
| Private account data is unavailable | A public checkout buyer session is narrower than a full account session; verify the account journey and authority. |
|
|
875
|
+
|
|
876
|
+
Only public/non-secret configuration belongs in client bundles, example `.env`
|
|
877
|
+
files and browser logs. Order hashes, buyer data and provider responses should
|
|
878
|
+
be handled as sensitive application data.
|