@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 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(new Config({
50
- token: 'your-api-token',
51
- baseUrl: 'https://app.dimepayments.com',
52
- timeout: 30, // seconds
53
- maxRetries: 2, // retries 429 / 5xx / network errors with backoff
54
- retryBaseDelay: 0.5,
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 | Endpoints |
69
- | ---------------------------- | ---------------------------------------------------------------- |
70
- | `dime.transactions` | chargeCard, chargeAch, tokenizeCard, refund, void, show, list |
71
- | `dime.customers` | list, show, create, update, delete |
72
- | `dime.paymentMethods` | list, show, create, update, delete |
73
- | `dime.merchants` | list, show, create, update, getFormLink |
74
- | `dime.addresses` | list, show, create, update, delete |
75
- | `dime.deposits` | list, listWithTransactions, show |
76
- | `dime.recurringPayments` | list, show, create, edit, pause, cancel, activate, delete |
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() // { 'data.amount': ['must be greater than 0'] }
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() // HTTP status
216
- e.getResponseBody() // decoded API body
345
+ e.getStatusCode() // HTTP status
346
+ e.getResponseBody() // decoded API body
217
347
  }
218
348
  }
219
349
  ```
220
350
 
221
- | Exception | When |
222
- | ---------------------------- | ------------------------------------------------------------ |
223
- | `ValidationException` | HTTP 400/422 with field errors |
224
- | `AuthenticationException` | HTTP 401 (missing/invalid token) |
225
- | `PermissionDeniedException` | HTTP 403 (belongs-to-company guard) |
226
- | `NotFoundException` | HTTP 404 |
227
- | `RateLimitException` | HTTP 429 (carries `Retry-After`) |
228
- | `ServerException` | HTTP 5xx |
229
- | `ConnectionException` | No HTTP response (DNS, timeout, network error) |
230
- | `ApiException` | Any other non-2xx |
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