@zippypay/checkout 1.0.0
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 +270 -0
- package/dist/index.cjs +951 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +265 -0
- package/dist/index.d.ts +265 -0
- package/dist/index.min.js +951 -0
- package/dist/index.min.js.map +1 -0
- package/dist/index.mjs +951 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# @zippypay/checkout
|
|
2
|
+
|
|
3
|
+
Browser checkout SDK for **Zippy Pay** merchants. Embed payment UI inline on a checkout page or open it in a modal. Works with vanilla JavaScript, React, Vue, Angular, and any stack that runs modern JavaScript.
|
|
4
|
+
|
|
5
|
+
Styles are scoped inside Shadow DOM — no extra CSS import is required.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @zippypay/checkout
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
yarn add @zippypay/checkout
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Before the SDK runs
|
|
22
|
+
|
|
23
|
+
Your **server** creates a payment session and passes credentials to the checkout page:
|
|
24
|
+
|
|
25
|
+
| Field | Description |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `sessionId` | UUID v4 from `POST /payment-sessions` — safe in URLs |
|
|
28
|
+
| `clientToken` | `zps_…` from the create-session response — **server → browser only** |
|
|
29
|
+
|
|
30
|
+
Never expose `X-Api-Key` or Clerk JWT from browser code. Never put `clientToken` in QR codes, query strings, logs, or analytics.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
### JavaScript / TypeScript
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { ZippyPay } from '@zippypay/checkout';
|
|
40
|
+
|
|
41
|
+
const checkout = ZippyPay.create({
|
|
42
|
+
environment: 'production',
|
|
43
|
+
sessionId: '11111111-1111-4111-8111-111111111111',
|
|
44
|
+
clientToken: 'zps_…',
|
|
45
|
+
mode: 'inline',
|
|
46
|
+
container: '#zippy-checkout',
|
|
47
|
+
theme: { primary: '#2563eb' },
|
|
48
|
+
onComplete: (session) => console.log('Paid', session),
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Modal
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
ZippyPay.create({
|
|
56
|
+
environment: 'production',
|
|
57
|
+
sessionId,
|
|
58
|
+
clientToken,
|
|
59
|
+
mode: 'modal',
|
|
60
|
+
closeOnBackdropClick: true,
|
|
61
|
+
closeOnEscape: true,
|
|
62
|
+
onClose: () => console.log('Modal closed'),
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Web Component
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<script type="module">
|
|
70
|
+
import '@zippypay/checkout';
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<zippy-pay-checkout
|
|
74
|
+
environment="production"
|
|
75
|
+
session-id="11111111-1111-4111-8111-111111111111"
|
|
76
|
+
mode="inline"
|
|
77
|
+
theme-primary="#2563eb"
|
|
78
|
+
></zippy-pay-checkout>
|
|
79
|
+
|
|
80
|
+
<script type="module">
|
|
81
|
+
const el = document.querySelector('zippy-pay-checkout');
|
|
82
|
+
el.clientToken = 'zps_…'; // property, not HTML attribute
|
|
83
|
+
el.addEventListener('zippy-complete', (e) => console.log(e.detail));
|
|
84
|
+
</script>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Script tag (UMD)
|
|
88
|
+
|
|
89
|
+
Serve or bundle is not required — load from a public npm CDN:
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<script src="https://unpkg.com/@zippypay/checkout@1/dist/index.min.js"></script>
|
|
93
|
+
<script>
|
|
94
|
+
ZippyPay.create({
|
|
95
|
+
environment: 'production',
|
|
96
|
+
sessionId: '…',
|
|
97
|
+
clientToken: 'zps_…',
|
|
98
|
+
mode: 'inline',
|
|
99
|
+
container: '#zippy-checkout',
|
|
100
|
+
});
|
|
101
|
+
</script>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Pin the version in production (`@1.0.0` instead of `@1`).
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Environments
|
|
109
|
+
|
|
110
|
+
Pass `environment` — the SDK resolves the API base URL:
|
|
111
|
+
|
|
112
|
+
| Environment | API origin |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `production` | `https://api.zippypay.io` |
|
|
115
|
+
| `staging` | `https://staging.api.zippypay.io` |
|
|
116
|
+
| `development` | Same-origin (empty base — for local proxies) |
|
|
117
|
+
|
|
118
|
+
All requests use the prefix `/api/v1` (e.g. `GET https://api.zippypay.io/api/v1/payment-sessions/:id`).
|
|
119
|
+
|
|
120
|
+
Use the environment where your merchant backend created the session.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
type ZippyPayConfig = {
|
|
128
|
+
environment: 'production' | 'staging' | 'development';
|
|
129
|
+
sessionId: string;
|
|
130
|
+
clientToken: string;
|
|
131
|
+
mode?: 'inline' | 'modal';
|
|
132
|
+
container?: HTMLElement | string; // required for inline
|
|
133
|
+
theme?: ZippyTheme;
|
|
134
|
+
redirectOnComplete?: boolean;
|
|
135
|
+
redirectOnFailure?: boolean;
|
|
136
|
+
closeOnBackdropClick?: boolean;
|
|
137
|
+
closeOnEscape?: boolean;
|
|
138
|
+
onReady?: (session) => void;
|
|
139
|
+
onSessionUpdate?: (session) => void;
|
|
140
|
+
onComplete?: (session) => void;
|
|
141
|
+
onExpired?: (session) => void;
|
|
142
|
+
onError?: (error: ZippyPayError) => void;
|
|
143
|
+
onClose?: () => void;
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Instance methods:** `open()`, `close()` (modal), `destroy()`
|
|
148
|
+
|
|
149
|
+
### Theming
|
|
150
|
+
|
|
151
|
+
| Token | CSS variable | Default |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `primary` | `--zippy-primary` | `#3f63f3` |
|
|
154
|
+
| `primaryForeground` | `--zippy-primary-foreground` | `#ffffff` |
|
|
155
|
+
| `background` | `--zippy-background` | `#ffffff` |
|
|
156
|
+
| `surface` | `--zippy-surface` | `#f8fafc` |
|
|
157
|
+
| `text` | `--zippy-text` | `#0f172a` |
|
|
158
|
+
| `textMuted` | `--zippy-text-muted` | `#64748b` |
|
|
159
|
+
| `border` | `--zippy-border` | `#e2e8f0` |
|
|
160
|
+
| `borderRadius` | `--zippy-radius` | `20px` |
|
|
161
|
+
| `fontFamily` | `--zippy-font-family` | DM Sans stack |
|
|
162
|
+
| `mode` | — | `light` \| `dark` \| `auto` |
|
|
163
|
+
|
|
164
|
+
Web component: use `theme-primary`, `theme-mode`, etc.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Checkout flow
|
|
169
|
+
|
|
170
|
+
1. **Choose method** — QR scan or manual Zippy ID (one-way; cannot switch)
|
|
171
|
+
2. **QR** — `POST …/checkout/start { method: "QR" }` → show QR + pay timer → poll until paid
|
|
172
|
+
3. **Manual** — verify ID → attach payer → pay timer → poll until paid
|
|
173
|
+
|
|
174
|
+
Display the **amount from the GET session response**, not from your page props.
|
|
175
|
+
|
|
176
|
+
Three time boundaries: `expiresAt` (idle), `paymentExpiryAt` (pay window), `absoluteExpiresAt` (hard max).
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Web component events
|
|
181
|
+
|
|
182
|
+
| Event | When |
|
|
183
|
+
|---|---|
|
|
184
|
+
| `zippy-ready` | Session loaded |
|
|
185
|
+
| `zippy-session-update` | Poll update |
|
|
186
|
+
| `zippy-complete` | Payment succeeded |
|
|
187
|
+
| `zippy-expired` | Session expired |
|
|
188
|
+
| `zippy-error` | Terminal / API error |
|
|
189
|
+
| `zippy-close` | Modal closed |
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Framework notes
|
|
194
|
+
|
|
195
|
+
### React
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
'use client';
|
|
199
|
+
|
|
200
|
+
import { useEffect, useRef } from 'react';
|
|
201
|
+
import '@zippypay/checkout';
|
|
202
|
+
|
|
203
|
+
export function ZippyCheckout({ sessionId, clientToken }: Props) {
|
|
204
|
+
const ref = useRef<HTMLElement & { clientToken: string }>(null);
|
|
205
|
+
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
const el = ref.current;
|
|
208
|
+
if (!el) return;
|
|
209
|
+
el.clientToken = clientToken;
|
|
210
|
+
const onComplete = (e: Event) => console.log((e as CustomEvent).detail);
|
|
211
|
+
el.addEventListener('zippy-complete', onComplete);
|
|
212
|
+
return () => el.removeEventListener('zippy-complete', onComplete);
|
|
213
|
+
}, [clientToken]);
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<zippy-pay-checkout
|
|
217
|
+
ref={ref}
|
|
218
|
+
environment="production"
|
|
219
|
+
session-id={sessionId}
|
|
220
|
+
mode="inline"
|
|
221
|
+
/>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Or imperative: `ZippyPay.create({ container: ref.current, … })` and `destroy()` on unmount.
|
|
227
|
+
|
|
228
|
+
### Vue 3
|
|
229
|
+
|
|
230
|
+
Import `@zippypay/checkout`, set `el.clientToken` in `onMounted`, listen for `@zippy-complete`.
|
|
231
|
+
|
|
232
|
+
### Angular
|
|
233
|
+
|
|
234
|
+
Import the package, use `CUSTOM_ELEMENTS_SCHEMA`, set `nativeElement.clientToken` in `ngAfterViewInit`.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## API authentication (SDK)
|
|
239
|
+
|
|
240
|
+
| Header | Value |
|
|
241
|
+
|---|---|
|
|
242
|
+
| `X-Payment-Session-Token` | `zps_…` (preferred) |
|
|
243
|
+
| `Authorization` | `Bearer zps_…` (fallback) |
|
|
244
|
+
|
|
245
|
+
Errors are RFC 7807 `application/problem+json`, surfaced as `ZippyPayError` with `code`, `status`, and `detail`.
|
|
246
|
+
|
|
247
|
+
On **401**: treat the token as invalid; create a new session — do not retry blindly.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Security checklist
|
|
252
|
+
|
|
253
|
+
1. Never bundle `X-Api-Key` in browser code.
|
|
254
|
+
2. Keep `clientToken` in memory only.
|
|
255
|
+
3. Encode only `sessionId` in QR / deep links — never the client token.
|
|
256
|
+
4. Display amount from GET session, not merchant page props.
|
|
257
|
+
5. Ensure your Zippy API environment allows your site origin in CORS for browser calls.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Requirements
|
|
262
|
+
|
|
263
|
+
- Modern browsers with ES2020, `fetch`, Shadow DOM, and Custom Elements
|
|
264
|
+
- Node.js ≥ 18 for local development / bundlers
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## License
|
|
269
|
+
|
|
270
|
+
MIT © Imagine Innovation Limited
|