@dime-technology/dime-js-sdk 1.0.0 → 1.3.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 +160 -30
- package/dist/index.cjs +791 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +344 -54
- package/dist/index.d.ts +344 -54
- package/dist/index.js +782 -50
- package/dist/index.js.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -46,13 +46,15 @@ import { Client, Config } from '@dime-technology/dime-js-sdk'
|
|
|
46
46
|
const dime = new Client('your-api-token', 'https://staging.dimepayments.com')
|
|
47
47
|
|
|
48
48
|
// Full control
|
|
49
|
-
const dime = new Client(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
const dime = new Client(
|
|
50
|
+
new Config({
|
|
51
|
+
token: 'your-api-token',
|
|
52
|
+
baseUrl: 'https://app.dimepayments.com',
|
|
53
|
+
timeout: 30, // seconds
|
|
54
|
+
maxRetries: 2, // retries 429 / 5xx / network errors with backoff
|
|
55
|
+
retryBaseDelay: 0.5,
|
|
56
|
+
}),
|
|
57
|
+
)
|
|
56
58
|
```
|
|
57
59
|
|
|
58
60
|
The SDK sends `Authorization: Bearer <token>` and JSON headers on every request. Transient
|
|
@@ -65,15 +67,17 @@ Every resource hangs off the client as a property. The merchant `sid` is always
|
|
|
65
67
|
explicitly; remaining fields go in an attributes object (and lookups, where the API expects
|
|
66
68
|
them, in a `filters` object). All amounts are returned as strings to avoid float rounding.
|
|
67
69
|
|
|
68
|
-
| Property
|
|
69
|
-
|
|
|
70
|
-
| `dime.transactions`
|
|
71
|
-
| `dime.customers`
|
|
72
|
-
| `dime.paymentMethods`
|
|
73
|
-
| `dime.merchants`
|
|
74
|
-
| `dime.addresses`
|
|
75
|
-
| `dime.deposits`
|
|
76
|
-
| `dime.recurringPayments`
|
|
70
|
+
| Property | Endpoints |
|
|
71
|
+
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `dime.transactions` | chargeCard, chargeAch, tokenizeCard, refund, void, show, list |
|
|
73
|
+
| `dime.customers` | list, show, create, update, delete |
|
|
74
|
+
| `dime.paymentMethods` | list, show, create, update, delete |
|
|
75
|
+
| `dime.merchants` | list, show, create, update, getFormLink |
|
|
76
|
+
| `dime.addresses` | list, show, create, update, delete |
|
|
77
|
+
| `dime.deposits` | list, listWithTransactions, show |
|
|
78
|
+
| `dime.recurringPayments` | list, show, create, edit, pause, cancel, activate, delete |
|
|
79
|
+
| `dime.invoices` | list, show, create, update, delete, send, markSent, void, duplicate, pay, getLink, addLineItem, updateLineItem, deleteLineItem, listItems, createItem |
|
|
80
|
+
| `dime.recurringInvoices` | list, show, create, cancel |
|
|
77
81
|
|
|
78
82
|
### Transactions
|
|
79
83
|
|
|
@@ -164,6 +168,132 @@ await dime.recurringPayments.activate('000010', rp.id!)
|
|
|
164
168
|
await dime.recurringPayments.cancel('000010', rp.id!)
|
|
165
169
|
```
|
|
166
170
|
|
|
171
|
+
### Invoices
|
|
172
|
+
|
|
173
|
+
Invoices are scoped to a merchant `sid` and built from line items that each reference a merchant
|
|
174
|
+
item (a fund/designation). Draft invoices can be edited; once sent they are locked. Amounts are
|
|
175
|
+
returned as strings.
|
|
176
|
+
|
|
177
|
+
Identify the customer with `customer_uuid` — the same uuid every other resource uses, and the only
|
|
178
|
+
identifier the customer endpoints return. `customer_id` is still accepted for older integrations.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
// Look up (or create) the items a line can reference
|
|
182
|
+
const items = await dime.invoices.listItems('000010')
|
|
183
|
+
const item = await dime.invoices.createItem('000010', {
|
|
184
|
+
name: 'Consulting',
|
|
185
|
+
price: 125,
|
|
186
|
+
tax_deductible: false,
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
// Create a draft invoice with one or more line items
|
|
190
|
+
const invoice = await dime.invoices.create('000010', {
|
|
191
|
+
customer_uuid: customer.uuid,
|
|
192
|
+
customer_name: 'Jane Doe',
|
|
193
|
+
customer_email: 'jane@example.com',
|
|
194
|
+
payment_terms: 'net_15', // due_on_receipt | net_15 | net_30 | net_60
|
|
195
|
+
lines: [
|
|
196
|
+
{ item_id: item.id, name: 'Consulting', description: '2 hours', quantity: 2, unit_price: 125 },
|
|
197
|
+
],
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// Tweak the draft's line items (each returns the refreshed invoice)
|
|
201
|
+
await dime.invoices.addLineItem('000010', invoice.id!, {
|
|
202
|
+
item_id: item.id!,
|
|
203
|
+
name: 'Setup',
|
|
204
|
+
quantity: 1,
|
|
205
|
+
unit_price: 50,
|
|
206
|
+
})
|
|
207
|
+
await dime.invoices.updateLineItem('000010', invoice.id!, invoice.items[0]!.id!, { quantity: 3 })
|
|
208
|
+
await dime.invoices.deleteLineItem('000010', invoice.id!, invoice.items[0]!.id!)
|
|
209
|
+
|
|
210
|
+
// Email it to the customer, or activate the pay link without emailing
|
|
211
|
+
await dime.invoices.send('000010', invoice.id!)
|
|
212
|
+
await dime.invoices.markSent('000010', invoice.id!)
|
|
213
|
+
|
|
214
|
+
// Share the public pay link
|
|
215
|
+
const { publicUrl } = await dime.invoices.getLink('000010', invoice.id!)
|
|
216
|
+
|
|
217
|
+
// Take a merchant-initiated (MOTO) payment against an open invoice
|
|
218
|
+
await dime.invoices.pay('000010', invoice.id!, {
|
|
219
|
+
payment_type: 'cc', // cc | ach
|
|
220
|
+
token: 'tok_abc123',
|
|
221
|
+
amount: 100, // optional partial amount when the invoice allows it
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
// Duplicate, void, delete
|
|
225
|
+
const copy = await dime.invoices.duplicate('000010', invoice.id!)
|
|
226
|
+
await dime.invoices.void('000010', invoice.id!)
|
|
227
|
+
await dime.invoices.delete('000010', copy.id!) // drafts only
|
|
228
|
+
|
|
229
|
+
// List, optionally filtered by status
|
|
230
|
+
const page = await dime.invoices.list('000010', { status: 'sent' })
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### Making the customer cover processing fees
|
|
234
|
+
|
|
235
|
+
Set `cover_fee_required` and the customer must pay the processing fee — it is not an optional
|
|
236
|
+
checkbox at checkout. The fee is **not** a line item and is **not** part of `total`: the merchant is
|
|
237
|
+
still owed `total`, and the fee is added on top of whatever the customer pays.
|
|
238
|
+
|
|
239
|
+
Card and ACH rates differ, so the charge depends on how the customer pays. `coverFeeQuote` gives you
|
|
240
|
+
both, quoted against the outstanding balance:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
const invoice = await dime.invoices.create('000010', {
|
|
244
|
+
customer_uuid: customer.uuid,
|
|
245
|
+
customer_name: 'Jane Doe',
|
|
246
|
+
customer_email: 'jane@example.com',
|
|
247
|
+
payment_terms: 'net_15',
|
|
248
|
+
cover_fee_required: true, // omit to inherit the merchant's invoice setting
|
|
249
|
+
lines: [{ item_id: 5, name: 'Consulting', quantity: 1, unit_price: 100 }],
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
invoice.total // '100.00' — what the merchant is owed
|
|
253
|
+
invoice.coverFeeQuote?.ccTotal // '104.32' — charged if they pay by card
|
|
254
|
+
invoice.coverFeeQuote?.achTotal // '101.26' — charged if they pay by bank
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The card figure is the higher of the two and is what the invoice and its emails lead with. A partial
|
|
258
|
+
payment re-quotes the fee against the partial amount, so treat the quote as "settling in full today"
|
|
259
|
+
rather than a fixed charge. `coverFeeQuote` is `undefined` when no fee is required.
|
|
260
|
+
|
|
261
|
+
To reconcile a payment, `amount` was credited to the invoice and `coverFee` was charged on top:
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
const payment = invoice.payments[0]!
|
|
265
|
+
payment.amount // '100.00' — applied to the balance
|
|
266
|
+
payment.coverFee // '4.32' — the fee the customer also paid
|
|
267
|
+
// The customer was charged amount + coverFee.
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
`pay()` behaves the same way: the fee for the `payment_type` you pass is added to `amount`, so the
|
|
271
|
+
card or bank account is debited more than the invoice is credited.
|
|
272
|
+
|
|
273
|
+
### Recurring invoices
|
|
274
|
+
|
|
275
|
+
Recurring-invoice templates generate and send invoices on a schedule. `cover_fee_required` is copied
|
|
276
|
+
onto every invoice a template generates.
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
const template = await dime.recurringInvoices.create('000010', {
|
|
280
|
+
customer_uuid: customer.uuid,
|
|
281
|
+
payment_terms: 'net_15',
|
|
282
|
+
recurring_frequency: 'Monthly', // Weekly | Biweekly | FirstFifteenth | Monthly | Yearly
|
|
283
|
+
recurring_start_date: '2026-08-01',
|
|
284
|
+
recurring_end_date: '2027-08-01', // optional
|
|
285
|
+
cover_fee_required: true, // optional
|
|
286
|
+
lines: [{ item_id: 5, name: 'Monthly retainer', quantity: 1, unit_price: 500 }],
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
const detail = await dime.recurringInvoices.show('000010', template.id!)
|
|
290
|
+
detail.upcomingRunDates // ['2026-08-01', '2026-09-01', ...]
|
|
291
|
+
|
|
292
|
+
await dime.recurringInvoices.cancel('000010', template.id!)
|
|
293
|
+
|
|
294
|
+
const page = await dime.recurringInvoices.list('000010', { status: 'Active' })
|
|
295
|
+
```
|
|
296
|
+
|
|
167
297
|
## Pagination
|
|
168
298
|
|
|
169
299
|
List endpoints return a `CursorPage`. Iterate one page, walk pages manually, or stream every
|
|
@@ -206,28 +336,28 @@ try {
|
|
|
206
336
|
await dime.transactions.chargeCard('000010', { amount: '0' })
|
|
207
337
|
} catch (e) {
|
|
208
338
|
if (e instanceof ValidationException) {
|
|
209
|
-
e.getErrors()
|
|
339
|
+
e.getErrors() // { 'data.amount': ['must be greater than 0'] }
|
|
210
340
|
e.firstError()
|
|
211
341
|
} else if (e instanceof RateLimitException) {
|
|
212
342
|
const wait = e.getRetryAfter() ?? 1
|
|
213
|
-
await new Promise(r => setTimeout(r, wait * 1000))
|
|
343
|
+
await new Promise((r) => setTimeout(r, wait * 1000))
|
|
214
344
|
} else if (e instanceof DimeException) {
|
|
215
|
-
e.getStatusCode()
|
|
216
|
-
e.getResponseBody()
|
|
345
|
+
e.getStatusCode() // HTTP status
|
|
346
|
+
e.getResponseBody() // decoded API body
|
|
217
347
|
}
|
|
218
348
|
}
|
|
219
349
|
```
|
|
220
350
|
|
|
221
|
-
| Exception
|
|
222
|
-
|
|
|
223
|
-
| `ValidationException`
|
|
224
|
-
| `AuthenticationException`
|
|
225
|
-
| `PermissionDeniedException`
|
|
226
|
-
| `NotFoundException`
|
|
227
|
-
| `RateLimitException`
|
|
228
|
-
| `ServerException`
|
|
229
|
-
| `ConnectionException`
|
|
230
|
-
| `ApiException`
|
|
351
|
+
| Exception | When |
|
|
352
|
+
| --------------------------- | ---------------------------------------------- |
|
|
353
|
+
| `ValidationException` | HTTP 400/422 with field errors |
|
|
354
|
+
| `AuthenticationException` | HTTP 401 (missing/invalid token) |
|
|
355
|
+
| `PermissionDeniedException` | HTTP 403 (belongs-to-company guard) |
|
|
356
|
+
| `NotFoundException` | HTTP 404 |
|
|
357
|
+
| `RateLimitException` | HTTP 429 (carries `Retry-After`) |
|
|
358
|
+
| `ServerException` | HTTP 5xx |
|
|
359
|
+
| `ConnectionException` | No HTTP response (DNS, timeout, network error) |
|
|
360
|
+
| `ApiException` | Any other non-2xx |
|
|
231
361
|
|
|
232
362
|
## Notes
|
|
233
363
|
|