@timbro/payments 0.1.0-next.2 → 0.1.0-next.4

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 CHANGED
@@ -8,54 +8,51 @@ Payments; an administrator key, which the owner creates and names in the Workspa
8
8
  settings, also administers the business and its Merchant Accounts. Keys are additive: creating another one,
9
9
  of either kind, never retires the keys you already use.
10
10
 
11
- Each Payment create request supplies one immutable `source` coordinate and one tagged `sale` snapshot. `source.id` and `source.version` remain stable across credential rotation and retries; `idempotencyKey` remains the HTTP command retry key.
11
+ Each Payment is identified by an immutable `paymentReference` within the merchant and TEST/LIVE scope. The SDK derives a stable HTTP idempotency key from that identity and retries payment creation a bounded number of times. Optional `source` coordinates preserve an upstream order identity; `saleReference` remains a searchable business label and may repeat.
12
12
 
13
- Payment reads preserve that source, the canonical sale, amount, voluntary tip,
14
- collected `totalAmount`, stable capture allocations with sanitized payment
15
- method summaries, and the fiscal recipient projection needed by an ERP.
13
+ Payment reads preserve that source, the canonical sale, decimal money values,
14
+ Checkout URL, stable capture allocations with sanitized payment method
15
+ summaries, and the fiscal recipient projection needed by an ERP.
16
16
 
17
- Use `amount_only` when the adapter has only a payable amount. This variant cannot request fiscal issuance:
17
+ Use the amount form when the adapter has one payable amount. Declare the tax
18
+ included in that amount; Timbro does not infer a tax rate for an amount-only
19
+ request. Omitting `tax` lets an explicitly configured merchant policy apply or
20
+ returns an input error when no policy covers the sale. Omitting `invoicing`
21
+ means no fiscal issuance is requested:
18
22
 
19
23
  ```ts
20
24
  import { createTimbroPayments } from "@timbro/payments";
21
25
 
22
26
  const timbro = createTimbroPayments({ apiKey: process.env.TIMBRO_PAYMENTS_SECRET_KEY });
23
27
  const payment = await timbro.payments.create({
24
- idempotencyKey: "create-order-123",
25
- source: { id: "odoo:pos.order:123", version: "7" },
26
- sale: {
27
- kind: "amount_only",
28
- reference: "order-123",
29
- description: "Consumo en el comercio",
30
- amount: { currency: "DOP", value: "1250.00" },
31
- },
32
- invoicing: null,
28
+ paymentReference: "order-123-payment-1",
29
+ amount: { currency: "DOP", value: "1250.00" },
30
+ description: "Consumo en el comercio",
31
+ tax: { includedAmount: "190.68" },
33
32
  });
33
+ return Response.redirect(payment.checkout.url);
34
34
  ```
35
35
 
36
- Use `itemized` when the adapter has commercial lines. Each line carries its fiscal description and exact decimal price; optional `product` data is presentation metadata:
36
+ Use the itemized form when the adapter has commercial lines. Each line carries
37
+ its description, exact decimal price, and tax treatment. Fiscal item fields
38
+ become required when invoicing needs them:
37
39
 
38
40
  ```ts
39
41
  await timbro.payments.create({
40
- idempotencyKey: "create-coffee-126",
42
+ paymentReference: "order-126-payment-1",
41
43
  source: { id: "odoo:pos.order:126", version: "3" },
42
- sale: { kind: "itemized", reference: "coffee-126", currency: "DOP",
43
- items: [{
44
- id: "coffee", description: "Café",
45
- product: { id: "product-7", sku: "CAFE-7", imageUrl: "https://merchant.example/cafe.png" },
46
- quantity: "1", unit: "unit", unitPrice: "118.00", kind: "good",
47
- tax: { kind: "itbis_18", included: true },
48
- }],
49
- totals: { net: "100.00", tax: "18.00", legalTip: "0.00", total: "118.00" } },
50
- invoicing: null,
44
+ currency: "DOP",
45
+ items: [{ description: "Café", quantity: "2", unitPrice: "118.00",
46
+ tax: { kind: "itbis_18", included: true } }],
47
+ expectedTotals: { net: "200.00", tax: "36.00", legalTip: "0.00", total: "236.00" },
51
48
  });
49
+ ```
52
50
 
53
- `sale.totals.total` is the commercial payable amount. A `non_billable` line may
54
- be collected without entering the fiscal amount. The returned breakdown names
55
- the invariant explicitly: `payableTotalMinorUnits` equals
56
- `fiscalDeclaredTotalMinorUnits + nonBillableMinorUnits`. Legal tip is included
57
- once in the fiscal declared total; voluntary tip is added only to collected
58
- `totalAmount`.
51
+ Timbro computes line rounding and totals once. `expectedTotals` lets the caller
52
+ assert agreement with its accounting snapshot. Product IDs, line IDs, quantity,
53
+ unit, and good/service kind are optional for payment-only lines; invoicing
54
+ requires the fiscal details it consumes. Money fields on Payment and Refund
55
+ resources use `{ currency, value }` decimal strings.
59
56
 
60
57
  Refunds are durable full or partial resources with idempotent create, retrieve,
61
58
  and list operations. Provider outcome and fiscal note coordination are separate.
@@ -63,11 +60,9 @@ The Gateway reserves captured allocation balances before provider work begins:
63
60
 
64
61
  ```ts
65
62
  const refund = await timbro.refunds.create({
66
- idempotencyKey: "refund-order-124-1",
67
63
  paymentId: payment.id,
68
- source: { id: "odoo:pos.order:124:refund:1", version: "1" },
69
- reference: "order-124-return-1",
70
- amount: { currency: "DOP", minorUnits: 12500 },
64
+ refundReference: "order-124-return-1",
65
+ amount: { currency: "DOP", value: "125.00" },
71
66
  // Optional for split Payments; omit to reserve across every captured allocation.
72
67
  allocationIds: payment.capturedPayment?.allocations.map(({ id }) => id),
73
68
  });
@@ -75,7 +70,7 @@ const refund = await timbro.refunds.create({
75
70
 
76
71
  The Refund response keeps `allocationIds` and exact `allocationAmounts` so an
77
72
  ERP can reconcile one or more split-payer allocations without exceeding any
78
- captured minor-unit balance. The Refund row owns the durable provider binding,
73
+ captured balance. The Refund row owns the durable provider binding,
79
74
  submission fence, and recovery schedule. Test-mode CardNet full refunds use the
80
75
  Ztrans submission and same-key inquiry path. Partial, split, live-mode, Azul,
81
76
  and sandbox paths remain `operator_required` before remote money movement.
@@ -116,27 +111,43 @@ money is outside cancellation and requires a separate refund policy.
116
111
  ```ts
117
112
  const canceled = await timbro.payments.cancel({
118
113
  paymentId: payment.id,
119
- idempotencyKey: "cancel-order-123",
120
114
  });
121
115
  ```
122
116
 
123
117
  `merchantCheckoutPolicy.retrieve()` reads tenant- and mode-scoped defaults and
124
- constraints. Administrators update them through the authenticated administrative
125
- `PUT /v1/merchant_checkout_policy` operation with the expected revision; ordinary
126
- merchant secret keys cannot update policy. Accepted configuration is retained with the Payment;
127
- later policy edits do not reroute existing Payments. Account readiness can still
128
- withdraw permission to start a provider effect.
118
+ constraints. Administrators replace them through a revision-checked `PUT`;
119
+ ordinary merchant secret keys cannot update policy. The optional `defaults.tax`
120
+ selects an explicit inclusive tax treatment for amount-only requests:
121
+
122
+ ```ts
123
+ const admin = createTimbroPayments({ apiKey: process.env.TIMBRO_ADMIN_KEY });
124
+ const policy = await admin.merchantCheckoutPolicy.retrieve();
125
+ await admin.merchantCheckoutPolicy.update({
126
+ expectedRevision: policy.revision,
127
+ defaults: {
128
+ ...policy.defaults,
129
+ tax: { kind: "itbis_18", included: true },
130
+ },
131
+ constraints: policy.constraints,
132
+ });
133
+ ```
134
+
135
+ Accepted configuration is retained with the Payment; later policy edits do not
136
+ reroute existing Payments. Account readiness can still withdraw permission to
137
+ start a provider effect.
129
138
 
130
139
  Use `mode: "required"` when Checkout must remain open until issuance. Required and deferred invoicing require the merchant's real invoice and order references. `externally_coordinated` records the payer recipient choice and lets the authenticated ERP supply those identifiers later.
131
140
 
132
141
  ```ts
133
142
  await timbro.payments.create({
134
- idempotencyKey: "create-required-order-124",
143
+ paymentReference: "order-124-payment-1",
135
144
  source: { id: "odoo:pos.order:124", version: "9" },
136
- sale: { kind: "itemized", reference: "order-124", currency: "DOP", items: [{
145
+ currency: "DOP",
146
+ items: [{
137
147
  id: "meal", description: "Meal", quantity: "1", unit: "unit", unitPrice: "1250.00", kind: "good",
138
148
  tax: { kind: "itbis_18", included: true },
139
- }], totals: { net: "1059.32", tax: "190.68", legalTip: "0.00", total: "1250.00" } },
149
+ }],
150
+ expectedTotals: { net: "1059.32", tax: "190.68", legalTip: "0.00", total: "1250.00" },
140
151
  invoicing: { mode: "required", type: "consumer", merchantInvoiceNumber: "INV-124", merchantOrderNumber: "124" },
141
152
  });
142
153
  ```
@@ -149,10 +160,9 @@ Refunds use one resource for the provider money movement and the separate fiscal
149
160
  const refund = await timbro.refunds.create({
150
161
  paymentId: payment.id,
151
162
  source: { id: "odoo:pos.order:124:return:1", version: "1" },
152
- reference: "RETURN-124-1",
153
- amount: { currency: "DOP", minorUnits: 50_000 },
163
+ refundReference: "RETURN-124-1",
164
+ amount: { currency: "DOP", value: "500.00" },
154
165
  allocationIds: [payment.capturedPayment!.allocations[0]!.id],
155
- idempotencyKey: "refund-order-124-return-1",
156
166
  });
157
167
 
158
168
  if (refund.providerOutcome.status === "succeeded") {
@@ -166,7 +176,13 @@ if (refund.providerOutcome.status === "succeeded") {
166
176
  }
167
177
  ```
168
178
 
169
- For a full, unsplit Payment, `timbro.payments.refund({ paymentId, idempotencyKey })` is a bodyless convenience command that returns the same Refund resource. `processing` means provider submission can still begin, `verifying` means an ambiguous submission is being checked without resubmission, and `operator_required` means staff must complete or reconcile the money movement. Provider outcome and fiscal E34 acceptance stay independent.
179
+ `timbro.refunds.create()` also accepts an omitted `amount`, which reserves the
180
+ remaining refundable balance once. Repeating the same `refundReference` returns that
181
+ same reservation. `processing` means provider submission can still begin,
182
+ `verifying` means an ambiguous submission is being checked without
183
+ resubmission, and `operator_required` means staff must complete or reconcile
184
+ the money movement. Provider outcome and fiscal E34 acceptance stay
185
+ independent.
170
186
 
171
187
  CardNet Ztrans full refunds are implemented for test mode with deterministic recovery tests. Current laboratory evidence does not prove CardNet's refund-inquiry semantics or production readiness. Partial, split, live-mode, Azul, and sandbox refund paths reserve the requested captured balance and return `operator_required` before remote provider I/O.
172
188
 
@@ -242,18 +258,18 @@ if (error !== undefined) {
242
258
  type Requirement = components["schemas"]["MerchantBusinessRequirement"];
243
259
  ```
244
260
 
245
- The facade covers every published merchant operation except `rotateApiKey`,
246
- `createPreCreationJourneyRequest`, and `chooseFiscalDocument`, which the client reaches directly.
261
+ The facade covers every published merchant operation except `rotateApiKey` and
262
+ `chooseFiscalDocument`, which the client reaches directly.
247
263
 
248
264
  ## From a terminal
249
265
 
250
- The published document is served at `https://api.timbro.dev/openapi.json`, so a
266
+ The published document is served at `https://api.timbro.do/openapi.json`, so a
251
267
  generic OpenAPI client needs nothing from Timbro. With [Restish](https://rest.sh), register the
252
268
  API once and pass a test administrator key on each call, from an environment variable rather than
253
269
  your shell history:
254
270
 
255
271
  ```sh
256
- restish api configure timbro https://api.timbro.dev
272
+ restish api configure timbro https://api.timbro.do
257
273
  restish timbro retrieve-merchant-business -H "Authorization: Bearer $TIMBRO_ADMIN_KEY"
258
274
  restish timbro update-merchant-business -H "Authorization: Bearer $TIMBRO_ADMIN_KEY" \
259
275
  'capabilities.electronicInvoicing.requested: true'