meterflow 0.6.0 → 0.7.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 +75 -10
- package/dist/client.d.ts +7 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/index.cjs +72 -3
- package/dist/index.js +72 -3
- package/dist/index.mjs +72 -3
- package/dist/resources/credits.d.ts +14 -1
- package/dist/resources/credits.d.ts.map +1 -1
- package/dist/resources/portal.d.ts +24 -0
- package/dist/resources/portal.d.ts.map +1 -0
- package/dist/resources/subscriptions.d.ts +12 -1
- package/dist/resources/subscriptions.d.ts.map +1 -1
- package/dist/resources/webhooks.d.ts +31 -0
- package/dist/resources/webhooks.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ Track what your customers use, enforce credit balances, and manage subscriptions
|
|
|
23
23
|
- [Usage events](#usage-events)
|
|
24
24
|
- [Subscriptions](#subscriptions)
|
|
25
25
|
- [Plans](#plans)
|
|
26
|
+
- [Webhook receipts](#webhook-receipts)
|
|
26
27
|
- [Entitlements — ask before you act](#entitlements--ask-before-you-act)
|
|
27
28
|
- [Idempotency — safe retries for writes](#idempotency--safe-retries-for-writes)
|
|
28
29
|
- [Automatic retries](#automatic-retries)
|
|
@@ -177,15 +178,26 @@ bal.total_granted; // "5250.000000"
|
|
|
177
178
|
bal.total_consumed; // "1705.000000"
|
|
178
179
|
```
|
|
179
180
|
|
|
180
|
-
**Transactions** — the customer's
|
|
181
|
+
**Transactions** — the customer's history, newest first, **a page at a time**:
|
|
181
182
|
|
|
182
183
|
```typescript
|
|
183
|
-
const
|
|
184
|
-
for (const t of
|
|
184
|
+
const page = await client.credits.transactions("customer_123"); // 50 rows by default
|
|
185
|
+
for (const t of page.data) {
|
|
185
186
|
console.log(t.transaction_type, t.amount, t.balance_after, t.description, t.created_at);
|
|
186
187
|
}
|
|
188
|
+
|
|
189
|
+
// The whole history, page by page. `next_cursor` is null once there is nothing after it.
|
|
190
|
+
let cursor: string | undefined;
|
|
191
|
+
do {
|
|
192
|
+
const page = await client.credits.transactions("customer_123", { limit: 200, cursor });
|
|
193
|
+
handle(page.data);
|
|
194
|
+
cursor = page.next_cursor ?? undefined;
|
|
195
|
+
} while (cursor);
|
|
187
196
|
```
|
|
188
197
|
|
|
198
|
+
> **The cursor is opaque.** Pass back exactly what `next_cursor` gave you; do not build one, and do
|
|
199
|
+
> not read anything out of it. `limit` is 1–200 and defaults to 50.
|
|
200
|
+
|
|
189
201
|
> **Amounts are decimal strings.** Balances and amounts come back as strings (`"3545.000000"`) to avoid floating-point drift on money-like values. Parse deliberately (`Number(...)` or a decimal library) when you need arithmetic.
|
|
190
202
|
|
|
191
203
|
### Usage events
|
|
@@ -198,7 +210,7 @@ Record an event every time a customer does the thing you charge for. Events are
|
|
|
198
210
|
await client.usage.record({
|
|
199
211
|
event_name: "images.generated",
|
|
200
212
|
customer_external_id: "customer_123",
|
|
201
|
-
value: 1, // what the meter aggregates: 1 for counts, seconds/MB/etc. for sums
|
|
213
|
+
value: 1, // optional — what the meter aggregates: 1 for counts, seconds/MB/etc. for sums
|
|
202
214
|
properties: {}, // free-form context; {} when unused
|
|
203
215
|
timestamp: new Date().toISOString(), // optional — defaults to arrival time on the server
|
|
204
216
|
});
|
|
@@ -254,7 +266,8 @@ This is usually the difference between fitting a plan and outgrowing it: 1,000 u
|
|
|
254
266
|
|
|
255
267
|
Two things to keep in mind:
|
|
256
268
|
|
|
257
|
-
- **It only helps a `sum` meter.** A `count` meter ignores `value` and counts occurrences, so there each occurrence has to be its own event. `max
|
|
269
|
+
- **It only helps a `sum` meter.** A `count` meter ignores `value` and counts occurrences, so there each occurrence has to be its own event. `max` and `min` read `value` as a measurement, not a quantity to add, and `unique_count` does not read it at all — it counts distinct values of the property its meter names.
|
|
270
|
+
- **`value` is optional.** Leave it out and MeterFlow fills it in: for a `sum`, `max` or `min` meter that names an `aggregation_field`, the numeric value of that property on the event; otherwise `1`. So the event above can be written `properties: { tokens: 1300 }` with no `value`, as long as the meter's `aggregation_field` is `tokens`. An explicit `value` always wins, a property that is absent or is not a number falls through to `1`, and a negative one is refused with a `422`.
|
|
258
271
|
- **Billing is unchanged.** A metered plan limit charges per unit — the event's `value` — so 100 units cost the same whether they arrived as 100 events or one. You are not rounding anyone's bill by batching.
|
|
259
272
|
|
|
260
273
|
**Summary** — a customer's usage, broken down by meter:
|
|
@@ -295,11 +308,16 @@ console.log(sub.status); // "trialing" if the plan has trial days, else "active"
|
|
|
295
308
|
**List / get:**
|
|
296
309
|
|
|
297
310
|
```typescript
|
|
298
|
-
const
|
|
311
|
+
const page = await client.subscriptions.list(); // whole project (in your key's environment)
|
|
299
312
|
const theirs = await client.subscriptions.list({ customer_id: "customer_123" }); // one customer
|
|
313
|
+
const more = await client.subscriptions.list({ limit: 200, cursor: page.next_cursor ?? undefined });
|
|
300
314
|
const one = await client.subscriptions.get(sub.id);
|
|
315
|
+
|
|
316
|
+
page.data.forEach((subscription) => console.log(subscription.customer_external_id, subscription.status));
|
|
301
317
|
```
|
|
302
318
|
|
|
319
|
+
> **`list()` answers a page**, `{ data, next_cursor }` — `get()` still answers one subscription.
|
|
320
|
+
|
|
303
321
|
> Like all reads, these are scoped to the key's environment: a live key lists live subscriptions only, a test key test ones only.
|
|
304
322
|
|
|
305
323
|
**Update** — change status or metadata. Statuses: `active`, `trialing`, `past_due`, `paused`, `canceled`, `expired`:
|
|
@@ -332,6 +350,27 @@ plan.meter_limits; // included units + overage rate per meter
|
|
|
332
350
|
|
|
333
351
|
Typical use: render your pricing page or signup flow from `plans.list()` so it can never drift from what billing actually enforces.
|
|
334
352
|
|
|
353
|
+
### Webhook receipts
|
|
354
|
+
|
|
355
|
+
Webhooks are **read-only** through the SDK too: endpoints are registered in the dashboard, where the signing secret is shown once and never again. What the SDK gives you is the other half — which endpoints exist, and what MeterFlow actually sent them.
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
const endpoints = await client.webhooks.list(); // this project's endpoints
|
|
359
|
+
const receipts = await client.webhooks.deliveries(endpoint_id); // newest first
|
|
360
|
+
receipts[0].event_type; // "usage.recorded"
|
|
361
|
+
receipts[0].status; // "pending" | "retrying" | "success" | "failed"
|
|
362
|
+
receipts[0].response_code; // what your server answered — 200, 500, or null if it never answered
|
|
363
|
+
receipts[0].attempts; // how many times we have tried
|
|
364
|
+
receipts[0].next_retry_at; // when we will try again, or null
|
|
365
|
+
receipts[0].payload; // exactly what we sent
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Typical use: answering "did that event reach my endpoint?" from your own tooling instead of opening the dashboard — and reading `response_body` when the answer is no.
|
|
369
|
+
|
|
370
|
+
Two things to know. The list is capped at the **most recent 100** attempts per endpoint; it is a debugging surface, not an export. And it follows your key: a `mf_test_*` key reads test receipts, a `mf_live_*` key live ones, while the endpoint list itself is shared by both worlds, because an endpoint is configuration and receives events from each.
|
|
371
|
+
|
|
372
|
+
> This is not the same as [verifying webhooks](#verifying-webhooks) below. That proves a request your server just received really came from us; this reads what we sent.
|
|
373
|
+
|
|
335
374
|
### Entitlements — ask before you act
|
|
336
375
|
|
|
337
376
|
The one call to make **before** doing work for a customer: "may they use this feature — and how much is left?" A **hard** limit says no here; recording usage afterwards never blocks, so an app that skips this call gets an honest ledger but no enforcement.
|
|
@@ -340,7 +379,7 @@ The one call to make **before** doing work for a customer: "may they use this fe
|
|
|
340
379
|
const gate = await client.entitlements.check("customer_123", "images.generated");
|
|
341
380
|
|
|
342
381
|
if (!gate.allowed) {
|
|
343
|
-
// gate.reason: "hard_limit_reached" | "no_subscription" | "not_in_plan" | "insufficient_credits"
|
|
382
|
+
// gate.reason: "hard_limit_reached" | "no_subscription" | "not_in_plan" | "insufficient_credits" | "spend_cap_reached"
|
|
344
383
|
return showUpgradePrompt(gate); // gate.used / gate.included / gate.period_end are there for the copy
|
|
345
384
|
}
|
|
346
385
|
|
|
@@ -364,6 +403,30 @@ const { entitlements, period_end } = await client.entitlements.get("customer_123
|
|
|
364
403
|
|
|
365
404
|
Prefer to be told rather than to ask? Subscribe a webhook to `limit.reached` (see below).
|
|
366
405
|
|
|
406
|
+
### The balance portal — a page you don't have to build
|
|
407
|
+
|
|
408
|
+
Mint a short-lived link to a MeterFlow-hosted page showing **one** customer's balance and ledger.
|
|
409
|
+
Call it from your server; send the `url` to that customer.
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
const link = await client.portal.createSession({
|
|
413
|
+
customer_external_id: "customer_123",
|
|
414
|
+
topup_url: "https://acme.test/billing", // your checkout — "buy more" goes here
|
|
415
|
+
return_url: "https://acme.test/app", // where "done" goes
|
|
416
|
+
expires_in_minutes: 60, // default 60, maximum 1440
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
sendEmail(customer.email, `Your balance: ${link.url}`);
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
The token in that link reads **that one customer's** balance and ledger, in the environment of the
|
|
423
|
+
key you minted it with, and nothing else: it cannot write, cannot name another customer, and is
|
|
424
|
+
refused everywhere else in the API. It is never your API key — never send that to anyone.
|
|
425
|
+
|
|
426
|
+
> **MeterFlow never takes the payment.** `topup_url` is a link we carry and hand back to the page;
|
|
427
|
+
> what happens there is between you and your own payment provider. Grant the credits with
|
|
428
|
+
> `credits.grant()` when your checkout tells you it was paid.
|
|
429
|
+
|
|
367
430
|
## Idempotency — safe retries for writes
|
|
368
431
|
|
|
369
432
|
Connections drop. When your app can't tell whether a write arrived, the correct move is to send it again **with the same idempotency key** — MeterFlow recognises the key and acts only once:
|
|
@@ -484,10 +547,12 @@ Every delivery is a flat JSON object (`Content-Type: application/json`) with two
|
|
|
484
547
|
| `subscription.created` | a subscription is created | `customer_id`, `plan_id`, `subscription_id`, `status` |
|
|
485
548
|
| `subscription.updated` | a subscription is updated | `customer_id`, `subscription_id`, `status` |
|
|
486
549
|
| `limit.reached` | a customer first reaches a **hard** or **soft** limit's included units this billing period (once per meter per period; metered limits report through `credit.deducted` instead) | `customer_id`, `subscription_id`, `feature` (the meter's `event_name`), `meter_id`, `limit_type`, `included`, `used`, `period_start`, `period_end` |
|
|
487
|
-
| `balance.low` | a
|
|
550
|
+
| `balance.low` | a spend takes a customer's balance **down through** this endpoint's `low_balance_threshold` — a crossing, so it fires once and not again while they stay below. Raised by both doors that spend: `credits.deduct` and a metered usage charge. **Both crossing events follow from the endpoint's `low_balance_threshold`: set one and the API adds them, clear it and the API removes them — so a line is the only thing to configure.** | `customer_id`, `balance`, `threshold`, `suggested_topup` (the subscription's `topup_amount`, `null` when unset), `transaction_id` |
|
|
488
551
|
| `balance.exhausted` | a balance reaches zero, **or** a request is refused for want of credits (a deduction returning 402, or `entitlements.check` answering `insufficient_credits`). Unlike `balance.low` this repeats: every refused request is its own blocked request | `customer_id`, `balance`, `reason` (`balance_zero` / `insufficient_credits`), `requested_amount` and `feature` where they apply, `transaction_id` on the zero case |
|
|
489
|
-
| `subscription.renewed` | a billing period
|
|
552
|
+
| `subscription.renewed` | a billing period opens — either a paid period rolling forward or a **trial converting** to its first paid period, told apart by `reason` (the renewer emits no `subscription.updated` for either) | `customer_id`, `subscription_id`, `plan_id`, `status`, `reason` (`period_renewed` / `trial_converted`), `current_period_start`, `current_period_end`, `credits_granted` |
|
|
490
553
|
| `subscription.canceled` | a subscription's status becomes canceled — fired **alongside** `subscription.updated`, once, on the call that actually cancels | `customer_id`, `subscription_id`, `plan_id`, `canceled_at` |
|
|
554
|
+
| `balance.topped_up` | a grant takes a customer's balance **up through** this endpoint's `low_balance_threshold` — the upward mirror of `balance.low`, on the same per-endpoint line, so the endpoint told "low" is the one told "recovered". Subscribed together with `balance.low` by setting the threshold, never on its own | `customer_id`, `balance`, `threshold`, `amount`, `transaction_id` |
|
|
555
|
+
| `cap.reached` | a customer's credit spending reaches their subscription's `spend_cap` for the period — once per subscription per period, whether they landed on the cap or were refused by it. A refusal that still leaves headroom is not a reach and does not fire | `customer_id`, `subscription_id`, `cap`, `spent`, `period_start`, `period_end` |
|
|
491
556
|
|
|
492
557
|
For example, a `credit.granted` delivery:
|
|
493
558
|
|
|
@@ -557,6 +622,6 @@ await client.usage.record({
|
|
|
557
622
|
|
|
558
623
|
// Support asks: "what's Ana's situation?"
|
|
559
624
|
const balance = await client.credits.balance("ana");
|
|
560
|
-
const history = await client.credits.transactions("ana");
|
|
625
|
+
const { data: history } = await client.credits.transactions("ana");
|
|
561
626
|
const usage = await client.usage.summary("ana");
|
|
562
627
|
```
|
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,9 @@ import { CreditsResource } from "./resources/credits";
|
|
|
2
2
|
import { UsageResource } from "./resources/usage";
|
|
3
3
|
import { SubscriptionsResource } from "./resources/subscriptions";
|
|
4
4
|
import { PlansResource } from "./resources/plans";
|
|
5
|
+
import { PortalResource } from "./resources/portal";
|
|
5
6
|
import { EntitlementsResource } from "./resources/entitlements";
|
|
7
|
+
import { WebhooksResource } from "./resources/webhooks";
|
|
6
8
|
export interface MeterFlowOptions {
|
|
7
9
|
apiKey: string;
|
|
8
10
|
baseUrl?: string;
|
|
@@ -22,13 +24,18 @@ export declare class MeterFlow {
|
|
|
22
24
|
private _usage?;
|
|
23
25
|
private _subscriptions?;
|
|
24
26
|
private _plans?;
|
|
27
|
+
private _portal?;
|
|
25
28
|
private _entitlements?;
|
|
29
|
+
private _webhooks?;
|
|
26
30
|
constructor(options: MeterFlowOptions);
|
|
31
|
+
get portal(): PortalResource;
|
|
27
32
|
get credits(): CreditsResource;
|
|
28
33
|
get usage(): UsageResource;
|
|
29
34
|
get subscriptions(): SubscriptionsResource;
|
|
30
35
|
get plans(): PlansResource;
|
|
31
36
|
get entitlements(): EntitlementsResource;
|
|
37
|
+
/** Read-only: the endpoints registered for this project, and what we sent them. */
|
|
38
|
+
get webhooks(): WebhooksResource;
|
|
32
39
|
/** @internal — used by resource classes only; not part of the public API */
|
|
33
40
|
request<T>(method: string, path: string, opts?: RequestOptions): Promise<T>;
|
|
34
41
|
}
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,SAAS;IACpB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAE7C,OAAO,CAAC,QAAQ,CAAC,CAAkB;IACnC,OAAO,CAAC,MAAM,CAAC,CAAgB;IAC/B,OAAO,CAAC,cAAc,CAAC,CAAwB;IAC/C,OAAO,CAAC,MAAM,CAAC,CAAgB;IAC/B,OAAO,CAAC,OAAO,CAAC,CAAiB;IACjC,OAAO,CAAC,aAAa,CAAC,CAAuB;IAC7C,OAAO,CAAC,SAAS,CAAC,CAAmB;gBAEzB,OAAO,EAAE,gBAAgB;IAerC,IAAI,MAAM,IAAI,cAAc,CAE3B;IAED,IAAI,OAAO,IAAI,eAAe,CAE7B;IAED,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,IAAI,aAAa,IAAI,qBAAqB,CAEzC;IAED,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,IAAI,YAAY,IAAI,oBAAoB,CAEvC;IAED,mFAAmF;IACnF,IAAI,QAAQ,IAAI,gBAAgB,CAE/B;IAED,4EAA4E;IAC5E,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;CAG5E"}
|
package/dist/index.cjs
CHANGED
|
@@ -35,7 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// package.json
|
|
38
|
-
var version = "0.
|
|
38
|
+
var version = "0.7.0";
|
|
39
39
|
|
|
40
40
|
// src/errors.ts
|
|
41
41
|
var MeterFlowError = class extends Error {
|
|
@@ -245,8 +245,17 @@ var CreditsResource = class {
|
|
|
245
245
|
balance(customerId) {
|
|
246
246
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/balance`);
|
|
247
247
|
}
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
/**
|
|
249
|
+
* One page of the customer's ledger, newest first.
|
|
250
|
+
*
|
|
251
|
+
* The ledger grows with every charge, so it is read a page at a time: `data` holds the rows and
|
|
252
|
+
* `next_cursor` the mark for the page after this one (`null` on the last). Pass it back as
|
|
253
|
+
* `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
254
|
+
*/
|
|
255
|
+
transactions(customerId, query) {
|
|
256
|
+
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/transactions`, {
|
|
257
|
+
...query !== void 0 && { query }
|
|
258
|
+
});
|
|
250
259
|
}
|
|
251
260
|
};
|
|
252
261
|
|
|
@@ -301,6 +310,12 @@ var SubscriptionsResource = class {
|
|
|
301
310
|
...opts?.idempotencyKey !== void 0 && { idempotencyKey: opts.idempotencyKey }
|
|
302
311
|
});
|
|
303
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* One page of the project's subscriptions in this key's environment, newest first.
|
|
315
|
+
*
|
|
316
|
+
* `data` holds the rows and `next_cursor` the mark for the page after this one (`null` on the
|
|
317
|
+
* last). Pass it back as `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
318
|
+
*/
|
|
304
319
|
list(query) {
|
|
305
320
|
return this.client.request("GET", "subscriptions", {
|
|
306
321
|
...query !== void 0 && { query }
|
|
@@ -337,6 +352,29 @@ var PlansResource = class {
|
|
|
337
352
|
}
|
|
338
353
|
};
|
|
339
354
|
|
|
355
|
+
// src/resources/portal.ts
|
|
356
|
+
var PortalResource = class {
|
|
357
|
+
constructor(client) {
|
|
358
|
+
this.client = client;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Mint a link to the hosted balance page for one of your customers.
|
|
362
|
+
*
|
|
363
|
+
* Call this from **your** server and send the `url` to that customer — it carries a short-lived
|
|
364
|
+
* token that can read their balance and their ledger and nothing else, in the environment of the
|
|
365
|
+
* key you called with. It is never your API key, and it can write nothing.
|
|
366
|
+
*
|
|
367
|
+
* The page shows the balance and sends "buy more" to your own checkout (`topup_url`): MeterFlow
|
|
368
|
+
* never takes the payment. `expires_in_minutes` defaults to 60 and may not exceed 1440.
|
|
369
|
+
*
|
|
370
|
+
* The two reads behind the page are **not** on this client by design: they belong to the person
|
|
371
|
+
* holding the link, and this client holds a secret key.
|
|
372
|
+
*/
|
|
373
|
+
createSession(body) {
|
|
374
|
+
return this.client.request("POST", "portal/sessions", { body });
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
340
378
|
// src/resources/entitlements.ts
|
|
341
379
|
var EntitlementsResource = class {
|
|
342
380
|
constructor(client) {
|
|
@@ -354,6 +392,28 @@ var EntitlementsResource = class {
|
|
|
354
392
|
}
|
|
355
393
|
};
|
|
356
394
|
|
|
395
|
+
// src/resources/webhooks.ts
|
|
396
|
+
var WebhooksResource = class {
|
|
397
|
+
constructor(client) {
|
|
398
|
+
this.client = client;
|
|
399
|
+
}
|
|
400
|
+
/** Every endpoint registered for the key's project. Never includes a secret. */
|
|
401
|
+
list() {
|
|
402
|
+
return this.client.request("GET", "webhooks");
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* One endpoint's delivery attempts, newest first: the payload sent, the HTTP status that came
|
|
406
|
+
* back, how many attempts and when the next retry is due.
|
|
407
|
+
*
|
|
408
|
+
* Capped at the most recent 100, and scoped to the key's own environment — a `mf_test_*` key
|
|
409
|
+
* reads test receipts, a `mf_live_*` key live ones. A webhook belonging to another project
|
|
410
|
+
* answers 404.
|
|
411
|
+
*/
|
|
412
|
+
deliveries(webhookId) {
|
|
413
|
+
return this.client.request("GET", `webhooks/${encodeURIComponent(webhookId)}/deliveries`);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
357
417
|
// src/client.ts
|
|
358
418
|
var MeterFlow = class {
|
|
359
419
|
options;
|
|
@@ -361,7 +421,9 @@ var MeterFlow = class {
|
|
|
361
421
|
_usage;
|
|
362
422
|
_subscriptions;
|
|
363
423
|
_plans;
|
|
424
|
+
_portal;
|
|
364
425
|
_entitlements;
|
|
426
|
+
_webhooks;
|
|
365
427
|
constructor(options) {
|
|
366
428
|
if (!options.apiKey.startsWith("mf_live_") && !options.apiKey.startsWith("mf_test_")) {
|
|
367
429
|
throw new Error("apiKey must start with mf_live_ or mf_test_");
|
|
@@ -376,6 +438,9 @@ var MeterFlow = class {
|
|
|
376
438
|
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
377
439
|
};
|
|
378
440
|
}
|
|
441
|
+
get portal() {
|
|
442
|
+
return this._portal ??= new PortalResource(this);
|
|
443
|
+
}
|
|
379
444
|
get credits() {
|
|
380
445
|
return this._credits ??= new CreditsResource(this);
|
|
381
446
|
}
|
|
@@ -391,6 +456,10 @@ var MeterFlow = class {
|
|
|
391
456
|
get entitlements() {
|
|
392
457
|
return this._entitlements ??= new EntitlementsResource(this);
|
|
393
458
|
}
|
|
459
|
+
/** Read-only: the endpoints registered for this project, and what we sent them. */
|
|
460
|
+
get webhooks() {
|
|
461
|
+
return this._webhooks ??= new WebhooksResource(this);
|
|
462
|
+
}
|
|
394
463
|
/** @internal — used by resource classes only; not part of the public API */
|
|
395
464
|
request(method, path, opts) {
|
|
396
465
|
return httpRequest(this.options, method, path, opts);
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// package.json
|
|
38
|
-
var version = "0.
|
|
38
|
+
var version = "0.7.0";
|
|
39
39
|
|
|
40
40
|
// src/errors.ts
|
|
41
41
|
var MeterFlowError = class extends Error {
|
|
@@ -245,8 +245,17 @@ var CreditsResource = class {
|
|
|
245
245
|
balance(customerId) {
|
|
246
246
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/balance`);
|
|
247
247
|
}
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
/**
|
|
249
|
+
* One page of the customer's ledger, newest first.
|
|
250
|
+
*
|
|
251
|
+
* The ledger grows with every charge, so it is read a page at a time: `data` holds the rows and
|
|
252
|
+
* `next_cursor` the mark for the page after this one (`null` on the last). Pass it back as
|
|
253
|
+
* `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
254
|
+
*/
|
|
255
|
+
transactions(customerId, query) {
|
|
256
|
+
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/transactions`, {
|
|
257
|
+
...query !== void 0 && { query }
|
|
258
|
+
});
|
|
250
259
|
}
|
|
251
260
|
};
|
|
252
261
|
|
|
@@ -301,6 +310,12 @@ var SubscriptionsResource = class {
|
|
|
301
310
|
...opts?.idempotencyKey !== void 0 && { idempotencyKey: opts.idempotencyKey }
|
|
302
311
|
});
|
|
303
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* One page of the project's subscriptions in this key's environment, newest first.
|
|
315
|
+
*
|
|
316
|
+
* `data` holds the rows and `next_cursor` the mark for the page after this one (`null` on the
|
|
317
|
+
* last). Pass it back as `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
318
|
+
*/
|
|
304
319
|
list(query) {
|
|
305
320
|
return this.client.request("GET", "subscriptions", {
|
|
306
321
|
...query !== void 0 && { query }
|
|
@@ -337,6 +352,29 @@ var PlansResource = class {
|
|
|
337
352
|
}
|
|
338
353
|
};
|
|
339
354
|
|
|
355
|
+
// src/resources/portal.ts
|
|
356
|
+
var PortalResource = class {
|
|
357
|
+
constructor(client) {
|
|
358
|
+
this.client = client;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Mint a link to the hosted balance page for one of your customers.
|
|
362
|
+
*
|
|
363
|
+
* Call this from **your** server and send the `url` to that customer — it carries a short-lived
|
|
364
|
+
* token that can read their balance and their ledger and nothing else, in the environment of the
|
|
365
|
+
* key you called with. It is never your API key, and it can write nothing.
|
|
366
|
+
*
|
|
367
|
+
* The page shows the balance and sends "buy more" to your own checkout (`topup_url`): MeterFlow
|
|
368
|
+
* never takes the payment. `expires_in_minutes` defaults to 60 and may not exceed 1440.
|
|
369
|
+
*
|
|
370
|
+
* The two reads behind the page are **not** on this client by design: they belong to the person
|
|
371
|
+
* holding the link, and this client holds a secret key.
|
|
372
|
+
*/
|
|
373
|
+
createSession(body) {
|
|
374
|
+
return this.client.request("POST", "portal/sessions", { body });
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
340
378
|
// src/resources/entitlements.ts
|
|
341
379
|
var EntitlementsResource = class {
|
|
342
380
|
constructor(client) {
|
|
@@ -354,6 +392,28 @@ var EntitlementsResource = class {
|
|
|
354
392
|
}
|
|
355
393
|
};
|
|
356
394
|
|
|
395
|
+
// src/resources/webhooks.ts
|
|
396
|
+
var WebhooksResource = class {
|
|
397
|
+
constructor(client) {
|
|
398
|
+
this.client = client;
|
|
399
|
+
}
|
|
400
|
+
/** Every endpoint registered for the key's project. Never includes a secret. */
|
|
401
|
+
list() {
|
|
402
|
+
return this.client.request("GET", "webhooks");
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* One endpoint's delivery attempts, newest first: the payload sent, the HTTP status that came
|
|
406
|
+
* back, how many attempts and when the next retry is due.
|
|
407
|
+
*
|
|
408
|
+
* Capped at the most recent 100, and scoped to the key's own environment — a `mf_test_*` key
|
|
409
|
+
* reads test receipts, a `mf_live_*` key live ones. A webhook belonging to another project
|
|
410
|
+
* answers 404.
|
|
411
|
+
*/
|
|
412
|
+
deliveries(webhookId) {
|
|
413
|
+
return this.client.request("GET", `webhooks/${encodeURIComponent(webhookId)}/deliveries`);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
357
417
|
// src/client.ts
|
|
358
418
|
var MeterFlow = class {
|
|
359
419
|
options;
|
|
@@ -361,7 +421,9 @@ var MeterFlow = class {
|
|
|
361
421
|
_usage;
|
|
362
422
|
_subscriptions;
|
|
363
423
|
_plans;
|
|
424
|
+
_portal;
|
|
364
425
|
_entitlements;
|
|
426
|
+
_webhooks;
|
|
365
427
|
constructor(options) {
|
|
366
428
|
if (!options.apiKey.startsWith("mf_live_") && !options.apiKey.startsWith("mf_test_")) {
|
|
367
429
|
throw new Error("apiKey must start with mf_live_ or mf_test_");
|
|
@@ -376,6 +438,9 @@ var MeterFlow = class {
|
|
|
376
438
|
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
377
439
|
};
|
|
378
440
|
}
|
|
441
|
+
get portal() {
|
|
442
|
+
return this._portal ??= new PortalResource(this);
|
|
443
|
+
}
|
|
379
444
|
get credits() {
|
|
380
445
|
return this._credits ??= new CreditsResource(this);
|
|
381
446
|
}
|
|
@@ -391,6 +456,10 @@ var MeterFlow = class {
|
|
|
391
456
|
get entitlements() {
|
|
392
457
|
return this._entitlements ??= new EntitlementsResource(this);
|
|
393
458
|
}
|
|
459
|
+
/** Read-only: the endpoints registered for this project, and what we sent them. */
|
|
460
|
+
get webhooks() {
|
|
461
|
+
return this._webhooks ??= new WebhooksResource(this);
|
|
462
|
+
}
|
|
394
463
|
/** @internal — used by resource classes only; not part of the public API */
|
|
395
464
|
request(method, path, opts) {
|
|
396
465
|
return httpRequest(this.options, method, path, opts);
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// package.json
|
|
2
|
-
var version = "0.
|
|
2
|
+
var version = "0.7.0";
|
|
3
3
|
|
|
4
4
|
// src/errors.ts
|
|
5
5
|
var MeterFlowError = class extends Error {
|
|
@@ -209,8 +209,17 @@ var CreditsResource = class {
|
|
|
209
209
|
balance(customerId) {
|
|
210
210
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/balance`);
|
|
211
211
|
}
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
/**
|
|
213
|
+
* One page of the customer's ledger, newest first.
|
|
214
|
+
*
|
|
215
|
+
* The ledger grows with every charge, so it is read a page at a time: `data` holds the rows and
|
|
216
|
+
* `next_cursor` the mark for the page after this one (`null` on the last). Pass it back as
|
|
217
|
+
* `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
218
|
+
*/
|
|
219
|
+
transactions(customerId, query) {
|
|
220
|
+
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/transactions`, {
|
|
221
|
+
...query !== void 0 && { query }
|
|
222
|
+
});
|
|
214
223
|
}
|
|
215
224
|
};
|
|
216
225
|
|
|
@@ -265,6 +274,12 @@ var SubscriptionsResource = class {
|
|
|
265
274
|
...opts?.idempotencyKey !== void 0 && { idempotencyKey: opts.idempotencyKey }
|
|
266
275
|
});
|
|
267
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* One page of the project's subscriptions in this key's environment, newest first.
|
|
279
|
+
*
|
|
280
|
+
* `data` holds the rows and `next_cursor` the mark for the page after this one (`null` on the
|
|
281
|
+
* last). Pass it back as `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
282
|
+
*/
|
|
268
283
|
list(query) {
|
|
269
284
|
return this.client.request("GET", "subscriptions", {
|
|
270
285
|
...query !== void 0 && { query }
|
|
@@ -301,6 +316,29 @@ var PlansResource = class {
|
|
|
301
316
|
}
|
|
302
317
|
};
|
|
303
318
|
|
|
319
|
+
// src/resources/portal.ts
|
|
320
|
+
var PortalResource = class {
|
|
321
|
+
constructor(client) {
|
|
322
|
+
this.client = client;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Mint a link to the hosted balance page for one of your customers.
|
|
326
|
+
*
|
|
327
|
+
* Call this from **your** server and send the `url` to that customer — it carries a short-lived
|
|
328
|
+
* token that can read their balance and their ledger and nothing else, in the environment of the
|
|
329
|
+
* key you called with. It is never your API key, and it can write nothing.
|
|
330
|
+
*
|
|
331
|
+
* The page shows the balance and sends "buy more" to your own checkout (`topup_url`): MeterFlow
|
|
332
|
+
* never takes the payment. `expires_in_minutes` defaults to 60 and may not exceed 1440.
|
|
333
|
+
*
|
|
334
|
+
* The two reads behind the page are **not** on this client by design: they belong to the person
|
|
335
|
+
* holding the link, and this client holds a secret key.
|
|
336
|
+
*/
|
|
337
|
+
createSession(body) {
|
|
338
|
+
return this.client.request("POST", "portal/sessions", { body });
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
304
342
|
// src/resources/entitlements.ts
|
|
305
343
|
var EntitlementsResource = class {
|
|
306
344
|
constructor(client) {
|
|
@@ -318,6 +356,28 @@ var EntitlementsResource = class {
|
|
|
318
356
|
}
|
|
319
357
|
};
|
|
320
358
|
|
|
359
|
+
// src/resources/webhooks.ts
|
|
360
|
+
var WebhooksResource = class {
|
|
361
|
+
constructor(client) {
|
|
362
|
+
this.client = client;
|
|
363
|
+
}
|
|
364
|
+
/** Every endpoint registered for the key's project. Never includes a secret. */
|
|
365
|
+
list() {
|
|
366
|
+
return this.client.request("GET", "webhooks");
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* One endpoint's delivery attempts, newest first: the payload sent, the HTTP status that came
|
|
370
|
+
* back, how many attempts and when the next retry is due.
|
|
371
|
+
*
|
|
372
|
+
* Capped at the most recent 100, and scoped to the key's own environment — a `mf_test_*` key
|
|
373
|
+
* reads test receipts, a `mf_live_*` key live ones. A webhook belonging to another project
|
|
374
|
+
* answers 404.
|
|
375
|
+
*/
|
|
376
|
+
deliveries(webhookId) {
|
|
377
|
+
return this.client.request("GET", `webhooks/${encodeURIComponent(webhookId)}/deliveries`);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
321
381
|
// src/client.ts
|
|
322
382
|
var MeterFlow = class {
|
|
323
383
|
options;
|
|
@@ -325,7 +385,9 @@ var MeterFlow = class {
|
|
|
325
385
|
_usage;
|
|
326
386
|
_subscriptions;
|
|
327
387
|
_plans;
|
|
388
|
+
_portal;
|
|
328
389
|
_entitlements;
|
|
390
|
+
_webhooks;
|
|
329
391
|
constructor(options) {
|
|
330
392
|
if (!options.apiKey.startsWith("mf_live_") && !options.apiKey.startsWith("mf_test_")) {
|
|
331
393
|
throw new Error("apiKey must start with mf_live_ or mf_test_");
|
|
@@ -340,6 +402,9 @@ var MeterFlow = class {
|
|
|
340
402
|
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
341
403
|
};
|
|
342
404
|
}
|
|
405
|
+
get portal() {
|
|
406
|
+
return this._portal ??= new PortalResource(this);
|
|
407
|
+
}
|
|
343
408
|
get credits() {
|
|
344
409
|
return this._credits ??= new CreditsResource(this);
|
|
345
410
|
}
|
|
@@ -355,6 +420,10 @@ var MeterFlow = class {
|
|
|
355
420
|
get entitlements() {
|
|
356
421
|
return this._entitlements ??= new EntitlementsResource(this);
|
|
357
422
|
}
|
|
423
|
+
/** Read-only: the endpoints registered for this project, and what we sent them. */
|
|
424
|
+
get webhooks() {
|
|
425
|
+
return this._webhooks ??= new WebhooksResource(this);
|
|
426
|
+
}
|
|
358
427
|
/** @internal — used by resource classes only; not part of the public API */
|
|
359
428
|
request(method, path, opts) {
|
|
360
429
|
return httpRequest(this.options, method, path, opts);
|
|
@@ -3,6 +3,7 @@ import type { components } from "../types/openapi";
|
|
|
3
3
|
type CreditGrantRequest = components["schemas"]["CreditGrantRequest"];
|
|
4
4
|
type CreditDeductRequest = components["schemas"]["CreditDeductRequest"];
|
|
5
5
|
type CreditTransactionResponse = components["schemas"]["CreditTransactionResponse"];
|
|
6
|
+
type CreditTransactionPage = components["schemas"]["CreditTransactionPage"];
|
|
6
7
|
type CreditBalanceResponse = components["schemas"]["CreditBalanceResponse"];
|
|
7
8
|
export interface GrantOptions {
|
|
8
9
|
idempotencyKey?: string;
|
|
@@ -10,13 +11,25 @@ export interface GrantOptions {
|
|
|
10
11
|
export interface DeductOptions {
|
|
11
12
|
idempotencyKey?: string;
|
|
12
13
|
}
|
|
14
|
+
/** One page of a list: how many rows, and where to carry on from. */
|
|
15
|
+
export interface PageQuery {
|
|
16
|
+
limit?: number;
|
|
17
|
+
cursor?: string;
|
|
18
|
+
}
|
|
13
19
|
export declare class CreditsResource {
|
|
14
20
|
private readonly client;
|
|
15
21
|
constructor(client: MeterFlow);
|
|
16
22
|
grant(body: CreditGrantRequest, opts?: GrantOptions): Promise<CreditTransactionResponse>;
|
|
17
23
|
deduct(body: CreditDeductRequest, opts?: DeductOptions): Promise<CreditTransactionResponse>;
|
|
18
24
|
balance(customerId: string): Promise<CreditBalanceResponse>;
|
|
19
|
-
|
|
25
|
+
/**
|
|
26
|
+
* One page of the customer's ledger, newest first.
|
|
27
|
+
*
|
|
28
|
+
* The ledger grows with every charge, so it is read a page at a time: `data` holds the rows and
|
|
29
|
+
* `next_cursor` the mark for the page after this one (`null` on the last). Pass it back as
|
|
30
|
+
* `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
31
|
+
*/
|
|
32
|
+
transactions(customerId: string, query?: PageQuery): Promise<CreditTransactionPage>;
|
|
20
33
|
}
|
|
21
34
|
export {};
|
|
22
35
|
//# sourceMappingURL=credits.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../../src/resources/credits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,CAAC;AACtE,KAAK,mBAAmB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC;AACxE,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C,KAAK,CAAC,IAAI,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAOxF,MAAM,CAAC,IAAI,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAO3F,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAI3D,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../../src/resources/credits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,CAAC;AACtE,KAAK,mBAAmB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC;AACxE,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC;AAC5E,KAAK,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C,KAAK,CAAC,IAAI,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAOxF,MAAM,CAAC,IAAI,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAO3F,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAI3D;;;;;;OAMG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAKpF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MeterFlow } from "../client";
|
|
2
|
+
import type { components } from "../types/openapi";
|
|
3
|
+
type PortalLinkRequest = components["schemas"]["PortalLinkRequest"];
|
|
4
|
+
type PortalLinkResponse = components["schemas"]["PortalLinkResponse"];
|
|
5
|
+
export declare class PortalResource {
|
|
6
|
+
private readonly client;
|
|
7
|
+
constructor(client: MeterFlow);
|
|
8
|
+
/**
|
|
9
|
+
* Mint a link to the hosted balance page for one of your customers.
|
|
10
|
+
*
|
|
11
|
+
* Call this from **your** server and send the `url` to that customer — it carries a short-lived
|
|
12
|
+
* token that can read their balance and their ledger and nothing else, in the environment of the
|
|
13
|
+
* key you called with. It is never your API key, and it can write nothing.
|
|
14
|
+
*
|
|
15
|
+
* The page shows the balance and sends "buy more" to your own checkout (`topup_url`): MeterFlow
|
|
16
|
+
* never takes the payment. `expires_in_minutes` defaults to 60 and may not exceed 1440.
|
|
17
|
+
*
|
|
18
|
+
* The two reads behind the page are **not** on this client by design: they belong to the person
|
|
19
|
+
* holding the link, and this client holds a secret key.
|
|
20
|
+
*/
|
|
21
|
+
createSession(body: PortalLinkRequest): Promise<PortalLinkResponse>;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=portal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/resources/portal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,iBAAiB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,mBAAmB,CAAC,CAAC;AACpE,KAAK,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,CAAC;AAEtE,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAGpE"}
|
|
@@ -3,17 +3,28 @@ import type { components } from "../types/openapi";
|
|
|
3
3
|
type SubscriptionCreateRequest = components["schemas"]["SubscriptionCreateRequest"];
|
|
4
4
|
type SubscriptionUpdateRequest = components["schemas"]["SubscriptionUpdateRequest"];
|
|
5
5
|
type SubscriptionResponse = components["schemas"]["SubscriptionResponse"];
|
|
6
|
+
type SubscriptionPage = components["schemas"]["SubscriptionPage"];
|
|
6
7
|
export interface CreateOptions {
|
|
7
8
|
idempotencyKey?: string;
|
|
8
9
|
}
|
|
9
10
|
export interface ListQuery {
|
|
10
11
|
customer_id?: string;
|
|
12
|
+
/** Rows per page, 1–200 (50 by default). */
|
|
13
|
+
limit?: number;
|
|
14
|
+
/** `next_cursor` from the previous page; omit for the first. */
|
|
15
|
+
cursor?: string;
|
|
11
16
|
}
|
|
12
17
|
export declare class SubscriptionsResource {
|
|
13
18
|
private readonly client;
|
|
14
19
|
constructor(client: MeterFlow);
|
|
15
20
|
create(body: SubscriptionCreateRequest, opts?: CreateOptions): Promise<SubscriptionResponse>;
|
|
16
|
-
|
|
21
|
+
/**
|
|
22
|
+
* One page of the project's subscriptions in this key's environment, newest first.
|
|
23
|
+
*
|
|
24
|
+
* `data` holds the rows and `next_cursor` the mark for the page after this one (`null` on the
|
|
25
|
+
* last). Pass it back as `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
26
|
+
*/
|
|
27
|
+
list(query?: ListQuery): Promise<SubscriptionPage>;
|
|
17
28
|
get(subscriptionId: string): Promise<SubscriptionResponse>;
|
|
18
29
|
update(subscriptionId: string, body: SubscriptionUpdateRequest, opts?: {
|
|
19
30
|
idempotencyKey?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../src/resources/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,oBAAoB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../src/resources/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,oBAAoB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,CAAC;AAC1E,KAAK,gBAAgB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,kBAAkB,CAAC,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C,MAAM,CAAC,IAAI,EAAE,yBAAyB,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAO5F;;;;;OAKG;IACH,IAAI,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAMlD,GAAG,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAI1D,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,EAAE,IAAI,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAOlI,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { MeterFlow } from "../client";
|
|
2
|
+
import type { components } from "../types/openapi";
|
|
3
|
+
type WebhookResponse = components["schemas"]["WebhookResponse"];
|
|
4
|
+
type WebhookDeliveryResponse = components["schemas"]["WebhookDeliveryResponse"];
|
|
5
|
+
/**
|
|
6
|
+
* Webhook **receipts** — read-only on purpose.
|
|
7
|
+
*
|
|
8
|
+
* An endpoint is registered, edited and deleted in the dashboard, where the signing secret is
|
|
9
|
+
* shown once and never again. What an SDK consumer needs at 3am is the other half: which
|
|
10
|
+
* endpoints exist, and what MeterFlow actually sent them. That is this.
|
|
11
|
+
*
|
|
12
|
+
* Not to be confused with `meterflow/webhook`, which verifies the signature on a webhook your
|
|
13
|
+
* server has just received. This reads what we sent; that proves we sent it.
|
|
14
|
+
*/
|
|
15
|
+
export declare class WebhooksResource {
|
|
16
|
+
private readonly client;
|
|
17
|
+
constructor(client: MeterFlow);
|
|
18
|
+
/** Every endpoint registered for the key's project. Never includes a secret. */
|
|
19
|
+
list(): Promise<WebhookResponse[]>;
|
|
20
|
+
/**
|
|
21
|
+
* One endpoint's delivery attempts, newest first: the payload sent, the HTTP status that came
|
|
22
|
+
* back, how many attempts and when the next retry is due.
|
|
23
|
+
*
|
|
24
|
+
* Capped at the most recent 100, and scoped to the key's own environment — a `mf_test_*` key
|
|
25
|
+
* reads test receipts, a `mf_live_*` key live ones. A webhook belonging to another project
|
|
26
|
+
* answers 404.
|
|
27
|
+
*/
|
|
28
|
+
deliveries(webhookId: string): Promise<WebhookDeliveryResponse[]>;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../../src/resources/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,eAAe,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC,CAAC;AAChE,KAAK,uBAAuB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,yBAAyB,CAAC,CAAC;AAEhF;;;;;;;;;GASG;AACH,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C,gFAAgF;IAChF,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAIlC;;;;;;;OAOG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC;CAGlE"}
|