@delopay/sdk 0.33.2 → 0.35.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 +102 -0
- package/dist/{chunk-ET3F5U37.js → chunk-45OPT3EW.js} +1 -1
- package/dist/chunk-45OPT3EW.js.map +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-ET3F5U37.js.map +0 -1
package/README.md
CHANGED
|
@@ -171,6 +171,108 @@ const gateway = await delopay.shops.gateways.connect(merchantId, shop.shop_id, {
|
|
|
171
171
|
const gateways = await delopay.shops.gateways.list(merchantId, shop.shop_id);
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
+
### Subscriptions
|
|
175
|
+
|
|
176
|
+
Recurring billing runs through a billing processor connected to the shop (Stripe
|
|
177
|
+
Billing or PayPal). Every subscription call is **profile-scoped** — pass the
|
|
178
|
+
shop's `X-Profile-Id` so the backend can resolve the billing processor (you get
|
|
179
|
+
`IR_04` otherwise):
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const opts = { headers: { 'X-Profile-Id': profileId } };
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Browse plans and estimate cost** before creating anything:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// List purchasable plans (or addons) with their prices
|
|
189
|
+
const plans = await delopay.subscriptions.getItems({ item_type: 'plan' }, opts);
|
|
190
|
+
const priceId = plans[0]?.price_id[0]?.price_id;
|
|
191
|
+
|
|
192
|
+
// Preview what the customer will be charged
|
|
193
|
+
const estimate = await delopay.subscriptions.getEstimate({ item_price_id: priceId }, opts);
|
|
194
|
+
console.log(estimate.amount, estimate.currency, estimate.interval); // 1500 'EUR' 'Month'
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
> **Never send raw card numbers.** The subscription API rejects
|
|
198
|
+
> `payment_method_data.card` with a raw PAN. Cards are collected client-side by
|
|
199
|
+
> the connector's hosted fields (Stripe Elements) so the card never touches your
|
|
200
|
+
> server, keeping raw card data out of your PCI scope. Confirm with a hosted
|
|
201
|
+
> checkout session or a previously-saved token, as shown below.
|
|
202
|
+
|
|
203
|
+
**Recommended: hosted checkout.** Create the subscription server-side, then send
|
|
204
|
+
the buyer to the Delopay hosted checkout with the returned `client_secret`. The
|
|
205
|
+
buyer enters their card in the connector iframe; you never handle the PAN:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
const pending = await delopay.subscriptions.create(
|
|
209
|
+
{
|
|
210
|
+
item_price_id: priceId,
|
|
211
|
+
customer_id: 'cus_abc123',
|
|
212
|
+
payment_details: { return_url: 'https://example.com/subscription/complete' },
|
|
213
|
+
},
|
|
214
|
+
opts,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// Redirect the buyer to the hosted checkout to enter their card.
|
|
218
|
+
const checkoutUrl =
|
|
219
|
+
`https://checkout.delopay.net/pay/${merchantId}/${pending.id}` +
|
|
220
|
+
`?cs=${encodeURIComponent(pending.client_secret ?? '')}`;
|
|
221
|
+
// → res.redirect(checkoutUrl)
|
|
222
|
+
|
|
223
|
+
// Activation arrives via the subscription/invoice webhooks; never trust the
|
|
224
|
+
// client. Reconcile with subscriptions.retrieve(pending.id, opts).
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Saved payment method (off-session).** If the customer already has a saved,
|
|
228
|
+
tokenized payment method, confirm server-side with the token — still no PAN:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const sub = await delopay.subscriptions.createAndConfirm(
|
|
232
|
+
{
|
|
233
|
+
item_price_id: priceId,
|
|
234
|
+
customer_id: 'cus_abc123',
|
|
235
|
+
payment_details: {
|
|
236
|
+
payment_method: 'card',
|
|
237
|
+
payment_method_id: savedPaymentMethodId, // token, not a card number
|
|
238
|
+
setup_future_usage: 'off_session',
|
|
239
|
+
return_url: 'https://example.com/subscription/complete',
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
opts,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
if (sub.redirect_url) {
|
|
246
|
+
// Some processors (e.g. PayPal) still need buyer approval — redirect there.
|
|
247
|
+
} else {
|
|
248
|
+
console.log(sub.status); // 'active'
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
You can also split create and confirm — call `subscriptions.confirm(id, …)` with
|
|
253
|
+
the `client_secret` and a `payment_token` once the buyer has a token. Same rule:
|
|
254
|
+
a `payment_token` / `payment_method_id`, never a raw card.
|
|
255
|
+
|
|
256
|
+
**Manage the lifecycle.** Pause, resume, and cancel take optional timing and
|
|
257
|
+
proration controls; called with no body they act immediately:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
await delopay.subscriptions.pause(sub.id, { pause_option: 'end_of_term' }, opts);
|
|
261
|
+
await delopay.subscriptions.resume(sub.id, undefined, opts);
|
|
262
|
+
await delopay.subscriptions.cancel(
|
|
263
|
+
sub.id,
|
|
264
|
+
{ cancel_option: 'immediately', credit_option_for_current_term_charges: 'prorate' },
|
|
265
|
+
opts,
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
// Retrieve one, or list for the profile
|
|
269
|
+
const current = await delopay.subscriptions.retrieve(sub.id, opts);
|
|
270
|
+
const all = await delopay.subscriptions.list({ limit: 20 }, opts);
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Each billing cycle raises an invoice (`sub.invoice`) with its own payment leg
|
|
274
|
+
(`sub.payment`); track cycle outcomes via the subscription/invoice webhooks.
|
|
275
|
+
|
|
174
276
|
### Webhook verification
|
|
175
277
|
|
|
176
278
|
Delopay signs each outgoing webhook with HMAC-SHA512 over the raw request body and delivers the hex-encoded digest in the `X-Webhook-Signature-512` header. Use `express.raw()` (not `express.json()`) so the bytes reach the verifier unchanged.
|