@timbro/payments 0.1.0-next.4 → 0.2.0-next.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 +47 -238
- package/dist/generated/openapi.d.ts +15237 -13018
- package/dist/generated/openapi.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/payments-client.d.ts +49 -177
- package/dist/payments-client.d.ts.map +1 -1
- package/dist/payments-client.js +142 -187
- package/dist/payments-client.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,283 +1,92 @@
|
|
|
1
1
|
# `@timbro/payments`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
business that onboards them.
|
|
3
|
+
Create a payment on your server and send the customer to Checkout. Read the Payment state from your server; signed webhooks notify you when it changes. Use `@timbro/invoices` to issue, retrieve, and deliver invoices independently. This SDK coordinates invoices with Payments and Refunds through their canonical `invoiceId`.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
Payments; an administrator key, which the owner creates and names in the Workspace business
|
|
8
|
-
settings, also administers the business and its Merchant Accounts. Keys are additive: creating another one,
|
|
9
|
-
of either kind, never retires the keys you already use.
|
|
5
|
+
Requires Node.js 24.19 or later and ESM. Install the stable `0.1.0` release:
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Checkout URL, stable capture allocations with sanitized payment method
|
|
15
|
-
summaries, and the fiscal recipient projection needed by an ERP.
|
|
7
|
+
```sh
|
|
8
|
+
npm install @timbro/payments
|
|
9
|
+
```
|
|
16
10
|
|
|
17
|
-
|
|
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:
|
|
11
|
+
Keep the API key on your server. Its granted capabilities determine which Payment, Invoice coordination, and Business setup tasks it can perform. This example assumes the merchant has an explicit amount-only tax default configured. Timbro does not infer a tax rate. For an amount-only override, pass `tax: { includedAmount: "190.68" }`; see [taxes and sale items](https://timbro.do/en/docs/cobros/impuestos-y-articulos/) for setup and itemized sales.
|
|
22
12
|
|
|
23
13
|
```ts
|
|
24
14
|
import { createTimbroPayments } from "@timbro/payments";
|
|
25
15
|
|
|
26
|
-
const timbro = createTimbroPayments({
|
|
27
|
-
|
|
28
|
-
paymentReference: "order-123-payment-1",
|
|
29
|
-
amount: { currency: "DOP", value: "1250.00" },
|
|
30
|
-
description: "Consumo en el comercio",
|
|
31
|
-
tax: { includedAmount: "190.68" },
|
|
32
|
-
});
|
|
33
|
-
return Response.redirect(payment.checkout.url);
|
|
34
|
-
```
|
|
35
|
-
|
|
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:
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
await timbro.payments.create({
|
|
42
|
-
paymentReference: "order-126-payment-1",
|
|
43
|
-
source: { id: "odoo:pos.order:126", version: "3" },
|
|
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" },
|
|
16
|
+
const timbro = createTimbroPayments({
|
|
17
|
+
apiKey: process.env.TIMBRO_PAYMENTS_SECRET_KEY,
|
|
48
18
|
});
|
|
49
|
-
```
|
|
50
19
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
and list operations. Provider outcome and fiscal note coordination are separate.
|
|
59
|
-
The Gateway reserves captured allocation balances before provider work begins:
|
|
20
|
+
export async function POST(): Promise<Response> {
|
|
21
|
+
const payment = await timbro.payments.create({
|
|
22
|
+
paymentReference: "order-123-payment-1",
|
|
23
|
+
amount: { currency: "DOP", value: "1250.00" },
|
|
24
|
+
description: "Service",
|
|
25
|
+
returnUrl: "https://shop.example.com/orders/123",
|
|
26
|
+
});
|
|
60
27
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
paymentId: payment.id,
|
|
64
|
-
refundReference: "order-124-return-1",
|
|
65
|
-
amount: { currency: "DOP", value: "125.00" },
|
|
66
|
-
// Optional for split Payments; omit to reserve across every captured allocation.
|
|
67
|
-
allocationIds: payment.capturedPayment?.allocations.map(({ id }) => id),
|
|
68
|
-
});
|
|
28
|
+
return Response.redirect(payment.checkout.url);
|
|
29
|
+
}
|
|
69
30
|
```
|
|
70
31
|
|
|
71
|
-
|
|
72
|
-
ERP can reconcile one or more split-payer allocations without exceeding any
|
|
73
|
-
captured balance. The Refund row owns the durable provider binding,
|
|
74
|
-
submission fence, and recovery schedule. Test-mode CardNet full refunds use the
|
|
75
|
-
Ztrans submission and same-key inquiry path. Partial, split, live-mode, Azul,
|
|
76
|
-
and sandbox paths remain `operator_required` before remote money movement.
|
|
77
|
-
|
|
78
|
-
An authenticated ERP can attach Timbro's accepted E34 fiscal credit note after
|
|
79
|
-
the refund request is recorded. This advances only `fiscalCoordination`; it does
|
|
80
|
-
not claim that provider money movement succeeded:
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
await timbro.refunds.attachFiscalCoordination({
|
|
84
|
-
refundId: refund.id,
|
|
85
|
-
timbroFiscalDocumentId: "timbro-operation-01h123456789abcdefgh",
|
|
86
|
-
eNcf: "E3400000001",
|
|
87
|
-
acceptedAt: "2026-09-11T00:00:00.000Z",
|
|
88
|
-
idempotencyKey: "refund-fiscal-note-124-1",
|
|
89
|
-
});
|
|
90
|
-
```
|
|
32
|
+
Replace `order-123-payment-1` with a stable reference for your order and persist it before collecting payment. Reuse the same reference and request after a timeout to recover that Payment; changing the request under that reference conflicts. `returnUrl` returns the customer from Checkout and does not confirm payment. See [retries and idempotency](https://timbro.do/en/docs/cobros/reintentos-e-idempotencia/) and [signed webhooks](https://timbro.do/en/docs/cobros/webhooks/).
|
|
91
33
|
|
|
92
|
-
|
|
93
|
-
`merchantAccounts.retrieveCheckoutCapabilities(id)` discovers its supported
|
|
94
|
-
Checkout features. Preferences can restrict available methods, but cannot grant
|
|
95
|
-
capabilities or bypass merchant policy. Empty `wallets` explicitly disables both
|
|
96
|
-
wallets; omitted preferences retain the merchant's applicable defaults.
|
|
97
|
-
`testOptions.threeDs` selects authentication for a test Payment only and cannot
|
|
98
|
-
disable production authentication. CardNet requires its supported 3DS flow.
|
|
34
|
+
## Read, cancel, or refund
|
|
99
35
|
|
|
100
|
-
|
|
101
|
-
The operation invalidates prepared Checkout submissions immediately. Split
|
|
102
|
-
authorizations enter provider release and the returned Payment remains
|
|
103
|
-
`releasing` until every void is confirmed; retrieve the Payment to observe the
|
|
104
|
-
authoritative terminal `canceled` state. The gateway emits one ordered
|
|
105
|
-
`payment.canceled` webhook only after that terminal state is committed. A same-key `202` cancellation replay is
|
|
106
|
-
intentionally stale while release is pending; polling the Payment is the
|
|
107
|
-
correctness authority. A submitted or ambiguous unsplit attempt returns a
|
|
108
|
-
conflict and stays under correlation reconciliation. Captured
|
|
109
|
-
money is outside cancellation and requires a separate refund policy.
|
|
36
|
+
Retrieve a Payment from your server to read its current state:
|
|
110
37
|
|
|
111
38
|
```ts
|
|
112
|
-
const
|
|
113
|
-
paymentId: payment.id,
|
|
114
|
-
});
|
|
39
|
+
const payment = await timbro.payments.retrieve("payment_123");
|
|
115
40
|
```
|
|
116
41
|
|
|
117
|
-
|
|
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:
|
|
42
|
+
Cancel only a Payment that is still unpaid and eligible for cancellation:
|
|
121
43
|
|
|
122
44
|
```ts
|
|
123
|
-
|
|
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
|
-
});
|
|
45
|
+
await timbro.payments.cancel({ paymentId: "payment_123" });
|
|
133
46
|
```
|
|
134
47
|
|
|
135
|
-
|
|
136
|
-
reroute existing Payments. Account readiness can still withdraw permission to
|
|
137
|
-
start a provider effect.
|
|
138
|
-
|
|
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.
|
|
140
|
-
|
|
141
|
-
```ts
|
|
142
|
-
await timbro.payments.create({
|
|
143
|
-
paymentReference: "order-124-payment-1",
|
|
144
|
-
source: { id: "odoo:pos.order:124", version: "9" },
|
|
145
|
-
currency: "DOP",
|
|
146
|
-
items: [{
|
|
147
|
-
id: "meal", description: "Meal", quantity: "1", unit: "unit", unitPrice: "1250.00", kind: "good",
|
|
148
|
-
tax: { kind: "itbis_18", included: true },
|
|
149
|
-
}],
|
|
150
|
-
expectedTotals: { net: "1059.32", tax: "190.68", legalTip: "0.00", total: "1250.00" },
|
|
151
|
-
invoicing: { mode: "required", type: "consumer", merchantInvoiceNumber: "INV-124", merchantOrderNumber: "124" },
|
|
152
|
-
});
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Use `mode: "deferred"` when Checkout owns issuance and retries, but the paid receipt may be shown before issuance finishes. The same complete immutable sale and invoicing intent is captured before provider I/O.
|
|
156
|
-
|
|
157
|
-
Refunds use one resource for the provider money movement and the separate fiscal-note coordination state. An ERP or POS supplies its immutable source coordinate and exact captured allocation attribution:
|
|
48
|
+
Refund only after capture. Omitting `amount` reserves the remaining refundable balance once:
|
|
158
49
|
|
|
159
50
|
```ts
|
|
160
51
|
const refund = await timbro.refunds.create({
|
|
161
|
-
paymentId:
|
|
162
|
-
|
|
163
|
-
refundReference: "RETURN-124-1",
|
|
164
|
-
amount: { currency: "DOP", value: "500.00" },
|
|
165
|
-
allocationIds: [payment.capturedPayment!.allocations[0]!.id],
|
|
52
|
+
paymentId: "payment_123",
|
|
53
|
+
refundReference: "order-123-refund-1",
|
|
166
54
|
});
|
|
167
|
-
|
|
168
|
-
if (refund.providerOutcome.status === "succeeded") {
|
|
169
|
-
await timbro.refunds.attachFiscalCoordination({
|
|
170
|
-
refundId: refund.id,
|
|
171
|
-
timbroFiscalDocumentId: "fiscal_document_123",
|
|
172
|
-
eNcf: "E340000000001",
|
|
173
|
-
acceptedAt: new Date().toISOString(),
|
|
174
|
-
idempotencyKey: "refund-order-124-return-1-e34",
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
55
|
```
|
|
178
56
|
|
|
179
|
-
|
|
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.
|
|
186
|
-
|
|
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.
|
|
188
|
-
|
|
189
|
-
Before collecting the rest of a merchant's onboarding details, verify its RNC
|
|
190
|
-
against the current DGII directory snapshot. The operation is read-only and
|
|
191
|
-
returns the canonical taxpayer name for the form to use. Either merchant key
|
|
192
|
-
calls it:
|
|
57
|
+
Before the customer submits a payment, choose its Invoice type and buyer:
|
|
193
58
|
|
|
194
59
|
```ts
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
The business belongs to the key's tenant, so no call names it. Claiming the business and handing
|
|
202
|
-
over the certificate file stay with the person who holds them; everything else is one resource.
|
|
203
|
-
Read it, act on the first requirement your integration owns, and read it again:
|
|
204
|
-
|
|
205
|
-
```ts
|
|
206
|
-
const admin = createTimbroPayments({ apiKey: process.env.TIMBRO_ADMIN_KEY });
|
|
207
|
-
|
|
208
|
-
let business = await admin.merchantBusiness.retrieve();
|
|
209
|
-
business = await admin.merchantBusiness.update({
|
|
210
|
-
capabilities: { electronicInvoicing: { requested: true } },
|
|
211
|
-
fiscalDetails: {
|
|
212
|
-
commercialName: "Café Duarte",
|
|
213
|
-
address: "Calle El Conde 101",
|
|
214
|
-
location: { municipalityCode: "320100" },
|
|
215
|
-
phone: "+18095550142",
|
|
216
|
-
defaultIncomeType: "01",
|
|
217
|
-
},
|
|
218
|
-
});
|
|
219
|
-
business = await admin.merchantBusiness.importSigningCertificate({
|
|
220
|
-
certificateP12Base64: p12.toString("base64"),
|
|
221
|
-
password: certificatePassword,
|
|
60
|
+
await timbro.payments.updateInvoiceChoice({
|
|
61
|
+
paymentId: payment.id,
|
|
62
|
+
idempotencyKey: "buyer-1",
|
|
63
|
+
type: "E31",
|
|
64
|
+
buyer: { kind: "domestic", taxId: "130123456" },
|
|
222
65
|
});
|
|
223
|
-
// Timbro sends the TesteCF document itself; poll until DGII answers.
|
|
224
|
-
business = await admin.merchantBusiness.retrieve();
|
|
225
|
-
if (business.capabilities.electronicInvoicing.status === "active") {
|
|
226
|
-
const { credential, fiscalOrigin } = await admin.merchantBusiness.issueSandboxCredential({
|
|
227
|
-
idempotencyKey: "sandbox-credential-1",
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
66
|
```
|
|
231
67
|
|
|
232
|
-
|
|
233
|
-
and `field` points into the representation when a field answers it. `dgii` and `timbro` entries
|
|
234
|
-
wait, `provider` entries wait on the acquirer, and `operator` entries need Timbro support. `update` replaces each member it carries, and
|
|
235
|
-
an `expectedRevision` refuses a stale write with `merchant_business_revision_conflict`.
|
|
236
|
-
Electronic invoicing onboards against DGII's TesteCF environment only. The certificate import is
|
|
237
|
-
the one call that carries the PKCS#12 archive; send it only from a machine that already holds the
|
|
238
|
-
file, and do not resend it once `fiscalSetup.signingCertificate.sha256` matches.
|
|
239
|
-
`retryTestFiscalDocument()` sends a new TesteCF document only when none is processing or
|
|
240
|
-
accepted. `issueSandboxCredential` returns the ERP credential once and retires the one issued
|
|
241
|
-
before it; the same `idempotencyKey` replays it.
|
|
242
|
-
|
|
243
|
-
## Every published operation
|
|
68
|
+
Use `buyer: { kind: "anonymous" }` to clear an earlier recipient. The operation preserves locked choices and refuses changes after submission or split creation.
|
|
244
69
|
|
|
245
|
-
`
|
|
246
|
-
with the same key and transport. Requests, responses, and Problem bodies are typed from the
|
|
247
|
-
generated `paths`, `components`, and `operations`, which the package also exports:
|
|
70
|
+
For a partial refund, pass exact `amount` and, when returning a voluntary tip, `voluntaryTipAmount`, each as `{ currency, value }`. Omitting the tip portion declares zero; refunding the entire remaining balance includes its remaining tip. `Refund.voluntaryTipAmount` records the reserved portion. Issue the credit note through the Invoices API for the commercial portion, then associate it separately:
|
|
248
71
|
|
|
249
72
|
```ts
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
73
|
+
await timbro.refunds.attachInvoice({
|
|
74
|
+
refundId: refund.id,
|
|
75
|
+
invoiceId: creditNote.id,
|
|
76
|
+
idempotencyKey: "order-123-credit-note",
|
|
77
|
+
receipt: { id: receipt.id, accessToken: receipt.accessToken },
|
|
254
78
|
});
|
|
255
|
-
if (error !== undefined) {
|
|
256
|
-
console.error(response.status, error.code);
|
|
257
|
-
}
|
|
258
|
-
type Requirement = components["schemas"]["MerchantBusinessRequirement"];
|
|
259
79
|
```
|
|
260
80
|
|
|
261
|
-
The
|
|
262
|
-
`chooseFiscalDocument`, which the client reaches directly.
|
|
81
|
+
Use the restricted receipt when the ERP owns the Invoice through an independent Source. The Gateway verifies the original Invoice, issuer, environment, currency, acceptance, and amount before setting `Refund.invoiceId`; it never changes the provider outcome.
|
|
263
82
|
|
|
264
|
-
|
|
83
|
+
Reuse a `refundReference` for retries. Automatic refunds currently cover full, unsplit DOP card payments in TEST with Azul. CardNet refund qualification remains open in [issue #587](https://github.com/indexa-labs/checkout/issues/587); partial, split, LIVE, wallet, and sandbox refunds require an operator and return `operator_required`. See [refunds](https://timbro.do/en/docs/cobros/reembolsos/).
|
|
265
84
|
|
|
266
|
-
|
|
267
|
-
generic OpenAPI client needs nothing from Timbro. With [Restish](https://rest.sh), register the
|
|
268
|
-
API once and pass a test administrator key on each call, from an environment variable rather than
|
|
269
|
-
your shell history:
|
|
270
|
-
|
|
271
|
-
```sh
|
|
272
|
-
restish api configure timbro https://api.timbro.do
|
|
273
|
-
restish timbro retrieve-merchant-business -H "Authorization: Bearer $TIMBRO_ADMIN_KEY"
|
|
274
|
-
restish timbro update-merchant-business -H "Authorization: Bearer $TIMBRO_ADMIN_KEY" \
|
|
275
|
-
'capabilities.electronicInvoicing.requested: true'
|
|
276
|
-
jq -n --arg p12 "$(base64 -w0 certificate.p12)" --arg password "$CERTIFICATE_PASSWORD" \
|
|
277
|
-
'{certificateP12Base64: $p12, password: $password}' |
|
|
278
|
-
restish timbro import-merchant-business-signing-certificate -H "Authorization: Bearer $TIMBRO_ADMIN_KEY"
|
|
279
|
-
```
|
|
85
|
+
## Guides and API reference
|
|
280
86
|
|
|
281
|
-
|
|
87
|
+
- [Retrieve payments](https://timbro.do/en/docs/cobros/consultar-pagos/) and [payment states](https://timbro.do/en/docs/cobros/estados-del-pago/)
|
|
88
|
+
- [Taxes and sale items](https://timbro.do/en/docs/cobros/impuestos-y-articulos/) and [request an e-CF](https://timbro.do/en/docs/comprobantes/emitir-ecf/)
|
|
89
|
+
- [Webhooks](https://timbro.do/en/docs/cobros/webhooks/) and [refunds](https://timbro.do/en/docs/cobros/reembolsos/)
|
|
90
|
+
- [Payments API reference](https://timbro.do/en/docs/reference/payments/) and [error handling](https://timbro.do/en/docs/produccion/errores/)
|
|
282
91
|
|
|
283
|
-
|
|
92
|
+
Use `PaymentsError.code` to classify API failures. The [Payments API reference](https://timbro.do/en/docs/reference/payments/) documents the complete surface; see [error handling](https://timbro.do/en/docs/produccion/errores/) for recovery guidance.
|