zuplo 6.69.5 → 6.69.8
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/docs/articles/monetization/api-access.mdx +130 -0
- package/docs/articles/monetization/features.mdx +39 -8
- package/docs/articles/monetization/index.mdx +25 -24
- package/docs/articles/monetization/meters.mdx +19 -6
- package/docs/articles/monetization/monetization-policy.md +35 -20
- package/docs/articles/monetization/plans.mdx +25 -8
- package/docs/articles/monetization/private-plans.md +9 -0
- package/docs/articles/monetization/quickstart.md +15 -9
- package/docs/articles/monetization/stripe-integration.md +95 -50
- package/docs/articles/monetization/subscription-lifecycle.md +38 -18
- package/docs/articles/monetization/troubleshooting.md +5 -2
- package/docs/dev-portal/zudoku/configuration/authentication-auth0.md +22 -0
- package/docs/dev-portal/zudoku/configuration/authentication-azure-ad.md +18 -0
- package/docs/dev-portal/zudoku/configuration/authentication-clerk.md +17 -0
- package/docs/dev-portal/zudoku/configuration/authentication-firebase.md +7 -0
- package/docs/dev-portal/zudoku/configuration/authentication-openid.md +27 -0
- package/docs/dev-portal/zudoku/configuration/authentication-supabase.md +35 -0
- package/docs/dev-portal/zudoku/configuration/docs.md +16 -0
- package/docs/dev-portal/zudoku/extending/hooks.md +243 -0
- package/docs/dev-portal/zudoku/markdown/frontmatter.md +19 -0
- package/docs/policies/upstream-gcp-service-auth-inbound/schema.json +6 -0
- package/package.json +4 -4
|
@@ -12,9 +12,9 @@ announced.
|
|
|
12
12
|
|
|
13
13
|
:::
|
|
14
14
|
|
|
15
|
-
Zuplo uses Stripe to
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
Zuplo uses Stripe to collect payments. Zuplo is the system of record for plans,
|
|
16
|
+
subscriptions, features, entitlements, and metered usage; Stripe is the system
|
|
17
|
+
of record for **money** — customers, invoices, and payment collection.
|
|
18
18
|
|
|
19
19
|
## How it works
|
|
20
20
|
|
|
@@ -22,19 +22,21 @@ The integration flow:
|
|
|
22
22
|
|
|
23
23
|
1. You define plans, features, and meters in Zuplo
|
|
24
24
|
2. You connect your Stripe account via the Zuplo Portal
|
|
25
|
-
3.
|
|
26
|
-
|
|
25
|
+
3. Plans, features, and rate cards stay in Zuplo's catalog — Stripe is used only
|
|
26
|
+
at billing time
|
|
27
27
|
4. Customers subscribe through your Developer Portal via Stripe Checkout
|
|
28
|
-
5. Stripe
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
7. As the customer uses the API, the monetization policy meters usage in real
|
|
28
|
+
5. Stripe collects the payment method and Zuplo creates the subscription with an
|
|
29
|
+
API key scoped to the plan's entitlements
|
|
30
|
+
6. As the customer uses the API, the monetization policy meters usage in real
|
|
32
31
|
time
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
7. At the end of each billing period, Zuplo issues a Stripe Invoice for fixed
|
|
33
|
+
fees and usage-based charges
|
|
35
34
|
|
|
36
|
-
Throughout this flow, Zuplo is the source of truth for access control
|
|
37
|
-
|
|
35
|
+
Throughout this flow, Zuplo is the source of truth for access control,
|
|
36
|
+
plans/rate cards, and metered usage. Stripe is the source of truth for payment
|
|
37
|
+
state and tax. **Stripe Subscriptions, Products, Prices, and Billing Meters are
|
|
38
|
+
not used** — Zuplo manages those concepts internally and only materializes them
|
|
39
|
+
in Stripe at the moment a charge is needed (as invoice line items).
|
|
38
40
|
|
|
39
41
|
## Connecting your Stripe account
|
|
40
42
|
|
|
@@ -45,8 +47,19 @@ metering. Stripe is the source of truth for payment state.
|
|
|
45
47
|
3. Enter a **Name** and paste your **Stripe API Key**
|
|
46
48
|
4. Click **Save**
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
:::tip
|
|
51
|
+
|
|
52
|
+
To script the same flow (CI, infrastructure-as-code, etc.) use the
|
|
53
|
+
[Stripe setup API](./api-access.mdx#stripe-setup-and-billing-readiness) — it
|
|
54
|
+
exposes `POST /setup/stripe`, `GET /billing-readiness`, and key-rotation
|
|
55
|
+
endpoints with the same prefix validation as the UI.
|
|
56
|
+
|
|
57
|
+
:::
|
|
58
|
+
|
|
59
|
+
The connection authorizes Zuplo to manage Stripe objects on your behalf —
|
|
60
|
+
specifically Customers, Checkout Sessions, Customer Portal Sessions, Invoices,
|
|
61
|
+
and Tax Calculations. See
|
|
62
|
+
[What Zuplo creates in Stripe](#what-zuplo-creates-in-stripe) for the full list.
|
|
50
63
|
|
|
51
64
|
### Test mode vs. live mode
|
|
52
65
|
|
|
@@ -143,20 +156,23 @@ new key must:
|
|
|
143
156
|
|
|
144
157
|
## What Zuplo creates in Stripe
|
|
145
158
|
|
|
146
|
-
|
|
147
|
-
|
|
159
|
+
Zuplo's catalog — plans, features, rate cards, and entitlements — is stored in
|
|
160
|
+
Zuplo. Stripe is used only at the points where money or payment state is
|
|
161
|
+
involved.
|
|
162
|
+
|
|
163
|
+
The objects that Zuplo creates or manages in your Stripe account:
|
|
148
164
|
|
|
149
|
-
|
|
|
150
|
-
|
|
|
151
|
-
|
|
|
152
|
-
|
|
|
153
|
-
|
|
|
154
|
-
|
|
|
155
|
-
|
|
|
165
|
+
| Object | When it's created |
|
|
166
|
+
| ------------------------------- | -------------------------------------------------------------------------- |
|
|
167
|
+
| Stripe Customer | When a developer first subscribes — one Stripe Customer per Zuplo customer |
|
|
168
|
+
| Stripe Checkout Session | When a developer subscribes to a plan that requires a payment method |
|
|
169
|
+
| Stripe Customer Portal Session | When a developer opens **Manage Billing** in the Developer Portal |
|
|
170
|
+
| Stripe Invoice and Invoice Item | At the end of each billing period for fixed and usage-based charges |
|
|
171
|
+
| Stripe Tax Calculation | At invoice time when [tax collection](./tax-collection.md) is enabled |
|
|
172
|
+
| Stripe Webhook Endpoint | Once on connection, so Zuplo can react to payment events |
|
|
156
173
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
be overwritten on the next plan publish.
|
|
174
|
+
To see what Zuplo has created, look under **Customers** and **Invoices** in your
|
|
175
|
+
Stripe dashboard.
|
|
160
176
|
|
|
161
177
|
## Subscription flow
|
|
162
178
|
|
|
@@ -164,7 +180,8 @@ be overwritten on the next plan publish.
|
|
|
164
180
|
|
|
165
181
|
When a customer clicks "Subscribe" in your Developer Portal:
|
|
166
182
|
|
|
167
|
-
1. A Stripe Checkout Session is created
|
|
183
|
+
1. A Stripe Checkout Session is created so the customer can enter a payment
|
|
184
|
+
method
|
|
168
185
|
2. The customer is redirected to Stripe Checkout to enter payment details
|
|
169
186
|
3. On successful payment, the subscription is created
|
|
170
187
|
4. An API key is generated scoped to the subscription's plan entitlements
|
|
@@ -175,22 +192,38 @@ When a customer clicks "Subscribe" in your Developer Portal:
|
|
|
175
192
|
|
|
176
193
|
When a customer changes their plan through the Developer Portal:
|
|
177
194
|
|
|
178
|
-
1.
|
|
179
|
-
2.
|
|
195
|
+
1. Zuplo records the plan change and recalculates the customer's entitlements
|
|
196
|
+
2. Any prorated amount is reflected on the customer's next Stripe Invoice
|
|
180
197
|
3. The customer's entitlements update immediately
|
|
181
198
|
4. The API key remains the same; its associated quota changes in real time
|
|
182
199
|
|
|
183
|
-
|
|
184
|
-
|
|
200
|
+
Zuplo uses **max_consumption_based proration** so customers can't game
|
|
201
|
+
mid-period upgrades and downgrades — see
|
|
202
|
+
[Subscription Lifecycle → Proration behavior](./subscription-lifecycle.md#proration-behavior)
|
|
203
|
+
for the detailed model and examples.
|
|
185
204
|
|
|
186
205
|
### Cancellation
|
|
187
206
|
|
|
188
|
-
When a customer cancels
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
207
|
+
When a customer cancels through the Developer Portal, the timing of the
|
|
208
|
+
cancellation depends on whether the current phase has billable items:
|
|
209
|
+
|
|
210
|
+
- **Paid phases** — the portal sends `timing: "next_billing_cycle"`. The
|
|
211
|
+
subscription is scheduled to cancel at the end of the current billing
|
|
212
|
+
period, the customer retains access until then, and the API key stops
|
|
213
|
+
working at period end.
|
|
214
|
+
- **Free phases** — the portal sends `timing: "immediate"`. With nothing to
|
|
215
|
+
invoice at period end, there's no billing period to wait out, so the
|
|
216
|
+
subscription cancels and access is revoked right away. Two situations fall
|
|
217
|
+
into this branch:
|
|
218
|
+
- The customer is on a **free trial phase** (the first phase of a plan
|
|
219
|
+
with a later paid phase) and cancels before the trial converts.
|
|
220
|
+
- The customer is on a **free plan** — a plan whose only phase has no
|
|
221
|
+
billable rate cards (every rate card's `price` is `null`).
|
|
222
|
+
|
|
223
|
+
For programmatic cancellation, see
|
|
224
|
+
[Cancellation](./subscription-lifecycle.md#cancellation) in the Subscription
|
|
225
|
+
Lifecycle guide — the API endpoint accepts a `timing` parameter to control
|
|
226
|
+
this same behavior explicitly.
|
|
194
227
|
|
|
195
228
|
## Proration
|
|
196
229
|
|
|
@@ -203,10 +236,13 @@ invoice.
|
|
|
203
236
|
|
|
204
237
|
For plans with usage-based pricing (per-unit, tiered, pay-as-you-go), usage is
|
|
205
238
|
tracked in real time by the `MonetizationInboundPolicy`. Each API request
|
|
206
|
-
increments the meter immediately. At the end of the billing period,
|
|
207
|
-
|
|
239
|
+
increments the meter immediately. At the end of the billing period, Zuplo
|
|
240
|
+
generates a Stripe Invoice with line items for the period's fixed fees and
|
|
241
|
+
metered usage, and Stripe collects payment.
|
|
208
242
|
|
|
209
|
-
You don't need to implement usage reporting or run any batch jobs
|
|
243
|
+
You don't need to implement usage reporting or run any batch jobs — and Zuplo
|
|
244
|
+
does **not** call Stripe Billing Meters; metered usage is materialized as
|
|
245
|
+
invoice line items directly.
|
|
210
246
|
|
|
211
247
|
## Handling failed payments
|
|
212
248
|
|
|
@@ -222,8 +258,11 @@ Stripe retries the payment.
|
|
|
222
258
|
| `failed` | Access blocked after grace period (configurable) |
|
|
223
259
|
| `uncollectible` | Access blocked |
|
|
224
260
|
|
|
225
|
-
The grace period is configurable
|
|
226
|
-
|
|
261
|
+
The grace period is configurable, with customer metadata overriding plan
|
|
262
|
+
metadata, which overrides the bucket-level `maxPaymentOverdueDays`. Default is 3
|
|
263
|
+
days. See
|
|
264
|
+
[Subscription and payment validation](./monetization-policy.md#subscription-and-payment-validation)
|
|
265
|
+
for the full resolution order.
|
|
227
266
|
|
|
228
267
|
## Customer portal
|
|
229
268
|
|
|
@@ -260,13 +299,19 @@ After connecting Stripe and publishing plans:
|
|
|
260
299
|
1. Open your Developer Portal
|
|
261
300
|
2. Subscribe to a plan using test card `4242 4242 4242 4242`
|
|
262
301
|
3. Verify in Stripe Dashboard:
|
|
263
|
-
-
|
|
264
|
-
|
|
265
|
-
-
|
|
302
|
+
- **Customers** — a customer was created with correct metadata and test card
|
|
303
|
+
attached
|
|
304
|
+
- **Developers → Webhooks** — the Zuplo-managed webhook endpoint is
|
|
305
|
+
registered and recent events show `200` responses
|
|
266
306
|
4. Make API requests and verify:
|
|
267
307
|
- Requests succeed within quota
|
|
268
|
-
- `403 Forbidden` returned when quota exceeded (hard
|
|
308
|
+
- `403 Forbidden` returned when quota exceeded (hard-limit plans)
|
|
269
309
|
- Usage visible in the Developer Portal dashboard
|
|
270
|
-
5.
|
|
271
|
-
|
|
272
|
-
- Stripe
|
|
310
|
+
5. Wait for the next billing cycle (or trigger a manual invoice in test mode)
|
|
311
|
+
and verify:
|
|
312
|
+
- **Invoices** — a Stripe Invoice was created with line items matching your
|
|
313
|
+
plan's fixed fees and metered usage
|
|
314
|
+
6. Cancel the subscription in the Developer Portal and verify:
|
|
315
|
+
- Access is revoked after the billing period ends
|
|
316
|
+
- The Zuplo subscription shows `canceled` in the API and Developer Portal
|
|
317
|
+
(Stripe doesn't track this — there is no Stripe Subscription to look at)
|
|
@@ -27,8 +27,9 @@ trials, upgrades, downgrades, cancellation, and reactivation.
|
|
|
27
27
|
:::note
|
|
28
28
|
|
|
29
29
|
Access is also governed by payment status. If a payment is overdue beyond the
|
|
30
|
-
grace period (default 3 days,
|
|
31
|
-
|
|
30
|
+
grace period (default 3 days), access is blocked even for active subscriptions.
|
|
31
|
+
The grace period is configurable per-customer, per-plan, or per-bucket — see
|
|
32
|
+
[Subscription and payment validation](./monetization-policy.md#subscription-and-payment-validation).
|
|
32
33
|
|
|
33
34
|
:::
|
|
34
35
|
|
|
@@ -56,14 +57,17 @@ curl -X POST https://dev.zuplo.com/v3/metering/{bucketId}/subscriptions \
|
|
|
56
57
|
-H "Authorization: Bearer {API_KEY}" \
|
|
57
58
|
-H "Content-Type: application/json" \
|
|
58
59
|
-d '{
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"stripeCustomerId": "cus_stripe_xyz"
|
|
60
|
+
"plan": { "key": "pro" },
|
|
61
|
+
"customerId": "01J9ZX2A8R0K8H6VG2C1A0K3WP"
|
|
62
62
|
}'
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
`plan` references the target plan by its `key` (and optionally `version`).
|
|
66
|
+
Provide either `customerId` (the OpenMeter customer ULID, format
|
|
67
|
+
`^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$`) or `customerKey` (your own
|
|
68
|
+
identifier). Optional fields include `timing` (`"immediate"` by default,
|
|
69
|
+
`"next_billing_cycle"`, or an RFC 3339 timestamp), `startingPhase`, `name`,
|
|
70
|
+
`description`, `metadata`, `alignment`, and `billingAnchor`.
|
|
67
71
|
|
|
68
72
|
## Free trials
|
|
69
73
|
|
|
@@ -185,15 +189,24 @@ Customers can change plans from the Subscriptions page in the Developer Portal:
|
|
|
185
189
|
|
|
186
190
|
### Programmatic (API)
|
|
187
191
|
|
|
192
|
+
Plan changes go through the dedicated `change` endpoint, which closes the
|
|
193
|
+
current subscription and starts a new one on the target plan:
|
|
194
|
+
|
|
188
195
|
```bash
|
|
189
|
-
curl -X
|
|
196
|
+
curl -X POST https://dev.zuplo.com/v3/metering/{bucketId}/subscriptions/{subscriptionId}/change \
|
|
190
197
|
-H "Authorization: Bearer {API_KEY}" \
|
|
191
198
|
-H "Content-Type: application/json" \
|
|
192
199
|
-d '{
|
|
193
|
-
"
|
|
200
|
+
"timing": "immediate",
|
|
201
|
+
"plan": { "key": "enterprise" }
|
|
194
202
|
}'
|
|
195
203
|
```
|
|
196
204
|
|
|
205
|
+
`timing` accepts `"immediate"`, `"next_billing_cycle"`, or an RFC 3339
|
|
206
|
+
timestamp. To preview the proration credit before committing, call
|
|
207
|
+
`POST /v3/metering/{bucketId}/subscriptions/{subscriptionId}/change/estimate-credit`
|
|
208
|
+
with the same body.
|
|
209
|
+
|
|
197
210
|
### Proration behavior
|
|
198
211
|
|
|
199
212
|
When a customer changes plans mid-billing-period, Zuplo uses
|
|
@@ -255,9 +268,21 @@ Customers can cancel from the Developer Portal subscriptions page:
|
|
|
255
268
|
|
|
256
269
|
```bash
|
|
257
270
|
curl -X POST https://dev.zuplo.com/v3/metering/{bucketId}/subscriptions/{subscriptionId}/cancel \
|
|
258
|
-
-H "Authorization: Bearer {API_KEY}"
|
|
271
|
+
-H "Authorization: Bearer {API_KEY}" \
|
|
272
|
+
-H "Content-Type: application/json" \
|
|
273
|
+
-d '{
|
|
274
|
+
"timing": "next_billing_cycle"
|
|
275
|
+
}'
|
|
259
276
|
```
|
|
260
277
|
|
|
278
|
+
`timing` controls when the cancellation takes effect:
|
|
279
|
+
|
|
280
|
+
- Omitted (or `"immediate"`) — the subscription is canceled immediately and
|
|
281
|
+
access stops right away. Use this for refund-style flows.
|
|
282
|
+
- `"next_billing_cycle"` — access continues until the end of the current billing
|
|
283
|
+
period, then is revoked. This matches the Developer Portal default.
|
|
284
|
+
- An RFC 3339 timestamp — schedule cancellation at a specific time.
|
|
285
|
+
|
|
261
286
|
### Cancellation behavior
|
|
262
287
|
|
|
263
288
|
| Scenario | Default behavior |
|
|
@@ -276,14 +301,9 @@ curl -X POST https://dev.zuplo.com/v3/metering/{bucketId}/subscriptions/{subscri
|
|
|
276
301
|
-H "Authorization: Bearer {API_KEY}"
|
|
277
302
|
```
|
|
278
303
|
|
|
279
|
-
This removes the pending cancellation. The subscription continues as normal.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
```bash
|
|
284
|
-
curl -X POST https://dev.zuplo.com/v3/metering/{bucketId}/subscriptions/{subscriptionId}/restore \
|
|
285
|
-
-H "Authorization: Bearer {API_KEY}"
|
|
286
|
-
```
|
|
304
|
+
This removes the pending cancellation. The subscription continues as normal. For
|
|
305
|
+
a subscription whose period has already ended, create a new subscription on the
|
|
306
|
+
same plan instead.
|
|
287
307
|
|
|
288
308
|
## Multiple subscriptions
|
|
289
309
|
|
|
@@ -30,8 +30,11 @@ announced.
|
|
|
30
30
|
-H "Authorization: Bearer {API_KEY}"
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Fix: Either resolve the payment issue in Stripe, or adjust the grace period
|
|
34
|
-
|
|
33
|
+
Fix: Either resolve the payment issue in Stripe, or adjust the grace period.
|
|
34
|
+
The window resolves customer metadata → plan metadata → bucket configuration
|
|
35
|
+
→ 3-day default. See
|
|
36
|
+
[Subscription and payment validation](./monetization-policy.md#subscription-and-payment-validation)
|
|
37
|
+
for details.
|
|
35
38
|
|
|
36
39
|
2. **Customer is using the wrong API key.** Each subscription generates its own
|
|
37
40
|
key. If the customer has multiple subscriptions or regenerated their key,
|
|
@@ -154,6 +154,28 @@ When the prompt parameter is omitted (empty string), Auth0 will:
|
|
|
154
154
|
- Silently authenticate the user if they have a valid session
|
|
155
155
|
- Redirect to the login page if no valid session exists
|
|
156
156
|
|
|
157
|
+
### Customizing Sign-up
|
|
158
|
+
|
|
159
|
+
By default Auth0 already adds `screen_hint=signup` when a user clicks Register. To send users to a
|
|
160
|
+
different page (or hide Register entirely):
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
authentication: {
|
|
164
|
+
type: "auth0",
|
|
165
|
+
domain: "your-domain.us.auth0.com",
|
|
166
|
+
clientId: "<your-auth0-client-id>",
|
|
167
|
+
|
|
168
|
+
// Send Register to a separate URL (absolute → external, relative → in-app)
|
|
169
|
+
signUp: { url: "/register" },
|
|
170
|
+
|
|
171
|
+
// Or pass extra params to the Auth0 authorize URL on sign-up
|
|
172
|
+
signUp: { authorizationParams: { connection: "your-signup-connection" } },
|
|
173
|
+
|
|
174
|
+
// Hide Register UI entirely. Visual only — configure Auth0 to actually block sign-ups.
|
|
175
|
+
disableSignUp: true,
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
157
179
|
## Troubleshooting
|
|
158
180
|
|
|
159
181
|
### Common Issues
|
|
@@ -178,6 +178,24 @@ To allow external partners access:
|
|
|
178
178
|
3. Invite guest users to your directory
|
|
179
179
|
4. Grant appropriate permissions to your application
|
|
180
180
|
|
|
181
|
+
### Customizing Sign-up
|
|
182
|
+
|
|
183
|
+
Azure AD B2C usually handles sign-up via a separate user flow. To send users there, point Register
|
|
184
|
+
at the URL of that flow (or any other page):
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
authentication: {
|
|
188
|
+
type: "azureb2c",
|
|
189
|
+
// ...
|
|
190
|
+
|
|
191
|
+
// Absolute URL → external redirect, relative path → in-app navigate
|
|
192
|
+
signUp: { url: "https://your-tenant.b2clogin.com/your-tenant.onmicrosoft.com/B2C_1_SignUp/oauth2/v2.0/authorize?..." },
|
|
193
|
+
|
|
194
|
+
// Hide Register entirely. Visual only — sign-ups are still controlled by your B2C policy.
|
|
195
|
+
disableSignUp: true,
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
181
199
|
## User Data
|
|
182
200
|
|
|
183
201
|
Azure AD provides rich user profile data through OpenID Connect:
|
|
@@ -84,6 +84,23 @@ that provides 10,000 monthly active users.
|
|
|
84
84
|
|
|
85
85
|
You should also ensure your site's domain is added as an allowed origin in the Clerk dashboard.
|
|
86
86
|
|
|
87
|
+
5. **Customizing Sign-up (Optional)**
|
|
88
|
+
|
|
89
|
+
To send Register to a different page, or hide it entirely:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
authentication: {
|
|
93
|
+
type: "clerk",
|
|
94
|
+
clerkPubKey: "<your-clerk-publishable-key>",
|
|
95
|
+
|
|
96
|
+
// Absolute URL → external redirect, relative path → in-app navigate
|
|
97
|
+
signUp: { url: "/register" },
|
|
98
|
+
|
|
99
|
+
// Hide Register UI. Visual only — configure Clerk to actually block sign-ups.
|
|
100
|
+
disableSignUp: true,
|
|
101
|
+
},
|
|
102
|
+
```
|
|
103
|
+
|
|
87
104
|
</Stepper>
|
|
88
105
|
|
|
89
106
|
## Troubleshooting
|
|
@@ -52,6 +52,13 @@ export default {
|
|
|
52
52
|
// "microsoft", "apple", "yahoo", "password", "emailLink"
|
|
53
53
|
// If not specified, all enabled providers in Firebase will be available
|
|
54
54
|
providers: ["google", "github", "password"],
|
|
55
|
+
// Optional: disable the sign-up UI for invite-only setups. Defaults to false.
|
|
56
|
+
// When true, the Register button and "Sign up" link are hidden, and /signup shows a message.
|
|
57
|
+
// Visual only — also disable sign-ups in your Firebase project for real enforcement.
|
|
58
|
+
disableSignUp: true,
|
|
59
|
+
// Optional: send Register to a separate URL instead of /signup
|
|
60
|
+
// (absolute URL → external redirect, relative path → in-app navigate)
|
|
61
|
+
signUp: { url: "/register" },
|
|
55
62
|
// Optional: configure redirect URLs after authentication
|
|
56
63
|
redirectToAfterSignIn: "/docs",
|
|
57
64
|
redirectToAfterSignUp: "/getting-started",
|
|
@@ -92,6 +92,33 @@ You can confirm your issuer URL is correct by opening `<issuer>/.well-known/open
|
|
|
92
92
|
a browser. It should return a JSON document listing `authorization_endpoint`, `token_endpoint`,
|
|
93
93
|
`userinfo_endpoint`, and `jwks_uri`.
|
|
94
94
|
|
|
95
|
+
## Customizing Sign-up
|
|
96
|
+
|
|
97
|
+
By default Register and Sign in both call the OIDC authorize endpoint, so users land on the same
|
|
98
|
+
login page. Two options change that:
|
|
99
|
+
|
|
100
|
+
```typescript title="zudoku.config.ts"
|
|
101
|
+
{
|
|
102
|
+
authentication: {
|
|
103
|
+
type: "openid",
|
|
104
|
+
clientId: "<your-client-id>",
|
|
105
|
+
issuer: "<the-issuer-url>",
|
|
106
|
+
|
|
107
|
+
// Send Register to a separate URL (absolute → external redirect, relative → in-app navigate)
|
|
108
|
+
signUp: { url: "/register" },
|
|
109
|
+
|
|
110
|
+
// Or pass extra params to the authorize URL on sign-up only (e.g. Keycloak)
|
|
111
|
+
signUp: { authorizationParams: { kc_action: "register" } },
|
|
112
|
+
|
|
113
|
+
// Hide Register UI entirely. Visual only — still configure your IdP to block sign-ups.
|
|
114
|
+
disableSignUp: true,
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
When `disableSignUp` is `true`, the Register button on the protected-route login dialog is hidden
|
|
120
|
+
and `/signup` shows an "Invitation required" page.
|
|
121
|
+
|
|
95
122
|
## User Profile
|
|
96
123
|
|
|
97
124
|
After sign-in Dev Portal calls the provider's
|
|
@@ -247,6 +247,16 @@ authentication: {
|
|
|
247
247
|
// Optional: When true, sign-in and sign-up pages show only OAuth buttons (no email/password)
|
|
248
248
|
onlyThirdPartyProviders: true,
|
|
249
249
|
|
|
250
|
+
// Optional: When true, the sign-up UI is disabled (for invite-only setups).
|
|
251
|
+
// Must also be disabled in the Supabase dashboard under
|
|
252
|
+
// Authentication → Configuration → Sign In / Providers → Allow new users to sign up.
|
|
253
|
+
// Defaults to false.
|
|
254
|
+
disableSignUp: true,
|
|
255
|
+
|
|
256
|
+
// Optional: send Register to a separate URL instead of /signup
|
|
257
|
+
// (absolute URL → external redirect, relative path → in-app navigate)
|
|
258
|
+
signUp: { url: "/register" },
|
|
259
|
+
|
|
250
260
|
// Optional: Redirect URLs after authentication events
|
|
251
261
|
redirectToAfterSignUp: "/welcome",
|
|
252
262
|
redirectToAfterSignIn: "/dashboard",
|
|
@@ -311,6 +321,31 @@ CREATE TRIGGER on_auth_user_created
|
|
|
311
321
|
FOR EACH ROW EXECUTE PROCEDURE public.handle_new_user();
|
|
312
322
|
```
|
|
313
323
|
|
|
324
|
+
## Invite-only sign-ups
|
|
325
|
+
|
|
326
|
+
To launch an invite-only portal where new users can only be created by an admin, set
|
|
327
|
+
`disableSignUp: true` in your Dev Portal config **and** disable new sign-ups in the Supabase dashboard
|
|
328
|
+
(**Authentication** → **Configuration** → **Sign In / Providers** → clear **Allow new users to sign
|
|
329
|
+
up**). When `disableSignUp` is `true`:
|
|
330
|
+
|
|
331
|
+
- The "Don't have an account? Sign up." link is hidden on the sign-in page.
|
|
332
|
+
- The Register button is hidden on the protected-route login dialog.
|
|
333
|
+
- Navigating to `/signup` shows an "Invitation required" message instead of a form.
|
|
334
|
+
|
|
335
|
+
```ts title="zudoku.config.ts"
|
|
336
|
+
export default {
|
|
337
|
+
authentication: {
|
|
338
|
+
type: "supabase",
|
|
339
|
+
supabaseUrl: "https://your-project.supabase.co",
|
|
340
|
+
supabaseKey: "<your-publishable-key>",
|
|
341
|
+
disableSignUp: true,
|
|
342
|
+
},
|
|
343
|
+
};
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Create users directly from the Supabase dashboard (**Authentication** → **Users** → **Add user**) or
|
|
347
|
+
via the Supabase admin API.
|
|
348
|
+
|
|
314
349
|
## Troubleshooting
|
|
315
350
|
|
|
316
351
|
### Common Issues
|
|
@@ -183,6 +183,22 @@ The `url` should be a template where the file path will be appended. For example
|
|
|
183
183
|
in a `docs/pages/` directory, the URL might be
|
|
184
184
|
`https://github.com/your-org/your-repo/edit/main/docs/pages`.
|
|
185
185
|
|
|
186
|
+
#### `fullWidth`
|
|
187
|
+
|
|
188
|
+
**Type:** `boolean` **Default:** `false`
|
|
189
|
+
|
|
190
|
+
Whether pages should use the full available width (hiding the table of contents sidebar) by default.
|
|
191
|
+
When enabled, the table of contents is accessible via an "On this page" toggle in the page header.
|
|
192
|
+
Combine with `toc: false` to hide the table of contents entirely.
|
|
193
|
+
|
|
194
|
+
```tsx title="zudoku.config.tsx"
|
|
195
|
+
docs: {
|
|
196
|
+
defaultOptions: {
|
|
197
|
+
fullWidth: true, // Use full-width layout for all pages by default
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
186
202
|
#### `copyPage`
|
|
187
203
|
|
|
188
204
|
**Type:** `boolean` **Default:** `undefined`
|