@getpeppr/cli 0.8.3 → 0.9.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/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ All notable changes to `@getpeppr/cli` are documented here.
4
4
 
5
5
  The CLI bundles `@getpeppr/sdk` into its published artifact (tsup `noExternal`), so `validate`, `convert` and `init` run the SDK's validators, country rules and UBL builder locally — an SDK release only reaches CLI users once the CLI is rebundled. Rebundle-only releases are listed with the SDK version they ship.
6
6
 
7
+ ## [0.9.0] — 2026-08-23
8
+
9
+ Before every sandbox send, the CLI now reads the exact sender profile from
10
+ `GET /v1/identity`. Its own generated fixture is adapted to O/0 for a
11
+ routing-only sender or AE/0 for a sender carrying a Tax Identifier. A
12
+ user-authored file is never rewritten silently: an incompatible tax mode is
13
+ refused locally before the invoice API is called.
14
+
15
+ This replaces the incomplete static O/0 assumption in 0.8.4. It also bundles
16
+ SDK 4.8.0 and fails closed when the provider inventory or scheme role cannot be
17
+ verified (GPR-1149).
18
+
19
+ ## [0.8.4] — 2026-08-22
20
+
21
+ `getpeppr init` scaffolded the SPF Economie test receiver plus out-of-scope
22
+ `O/0` lines. That fixed routing-only senders but incorrectly assumed every
23
+ sandbox sender lacked a Tax Identifier; 0.9.0 supersedes the static choice with
24
+ the exact sender profile.
25
+
26
+ Every generated `O` line includes the builder-only exemption reason required by
27
+ the SDK's local validator. The quick `getpeppr send --to …` payload remains on
28
+ the same contract. This release bundles SDK 4.7.0.
29
+
7
30
  ## [0.8.3] — 2026-08-21
8
31
 
9
32
  Rebundles `@getpeppr/sdk` **4.6.0** (was 4.5.0), so `getpeppr validate` and
package/README.md CHANGED
@@ -237,11 +237,11 @@ The CLI runs three validation engines from the [@getpeppr/sdk](https://www.npmjs
237
237
  2. **Business Rules** — Peppol BIS 3.0 / EN 16931 compliance (BR-xx, BR-CO-xx, PEPPOL-xx rules)
238
238
  3. **Country Rules** — Belgium (BE), France (FR), Italy (IT), Netherlands (NL), Germany (DE)
239
239
 
240
- Scaffolding (`init`), validation, and conversion run fully offline — no API key or network connection required. Only `lookup`, `send`, and `whoami` need a network connection.
240
+ Scaffolding (`init`), validation, and conversion run fully offline — no API key or network connection required. Only `lookup`, `send`, and `whoami` need a network connection. Before a sandbox `send`, the CLI reads `GET /v1/identity`: its own generated fixture is adapted to the returned O/0 or AE/0 profile, while a user-edited file is never rewritten silently and is refused locally if its tax mode conflicts with the sender.
241
241
 
242
242
  ## Invoice format
243
243
 
244
- The input file must be a JSON object matching the getpeppr `InvoiceInput` type. `number`, `to`, and `lines` are required for API sends. The `from` party is included in the scaffold because offline validation and UBL conversion need seller metadata; API sends use the legal entity linked to your key.
244
+ The input file must be a JSON object matching the getpeppr `InvoiceInput` type. `number`, `to`, and `lines` are required for API sends. The `from` party is included in the scaffold because offline validation and UBL conversion need seller metadata; API sends use the legal entity linked to your key. The generated file starts as an O/0 integration fixture. At send time the CLI verifies it against the actual sender profile and never forwards an incompatible tax mode.
245
245
 
246
246
  ```json
247
247
  {
@@ -271,14 +271,17 @@ The input file must be a JSON object matching the getpeppr `InvoiceInput` type.
271
271
  "description": "Conseil en transformation numérique",
272
272
  "quantity": 10,
273
273
  "unitPrice": 950,
274
- "vatRate": 21
274
+ "vatRate": 0,
275
+ "vatCategory": "O",
276
+ "taxExemptReason": "Integration test"
275
277
  },
276
278
  {
277
279
  "description": "Software license — annual subscription",
278
280
  "quantity": 1,
279
281
  "unitPrice": 2400,
280
282
  "vatRate": 0,
281
- "vatCategory": "AE"
283
+ "vatCategory": "O",
284
+ "taxExemptReason": "Integration test"
282
285
  }
283
286
  ],
284
287
  "paymentTerms": "Net 30 days",
package/dist/index.js CHANGED
@@ -717,6 +717,28 @@ function formatVatRate(vatRate, field) {
717
717
  }
718
718
  return String(vatRate);
719
719
  }
720
+ function formatBaseQuantity(baseQuantity, field) {
721
+ if (typeof baseQuantity !== "number" || !Number.isFinite(baseQuantity) || baseQuantity <= 0) {
722
+ throw new UblBuilderInputError("baseQuantity must be a finite number greater than zero.", field, "PEPPOL-EN16931-R121");
723
+ }
724
+ const numeric = String(baseQuantity);
725
+ const exponentMarker = numeric.search(/[eE]/);
726
+ if (exponentMarker === -1)
727
+ return numeric;
728
+ const coefficient = numeric.slice(0, exponentMarker);
729
+ const exponent = Number(numeric.slice(exponentMarker + 1));
730
+ const decimalPoint = coefficient.indexOf(".");
731
+ const digits = coefficient.replace(".", "");
732
+ const integerDigits = decimalPoint === -1 ? coefficient.length : decimalPoint;
733
+ const outputPoint = integerDigits + exponent;
734
+ if (outputPoint <= 0) {
735
+ return `0.${"0".repeat(-outputPoint)}${digits}`;
736
+ }
737
+ if (outputPoint >= digits.length) {
738
+ return `${digits}${"0".repeat(outputPoint - digits.length)}`;
739
+ }
740
+ return `${digits.slice(0, outputPoint)}.${digits.slice(outputPoint)}`;
741
+ }
720
742
  function round2(n) {
721
743
  return Math.round(n * 100) / 100;
722
744
  }
@@ -974,7 +996,7 @@ function buildDocumentLineXml(line, index, currency, lineTag, qtyTag) {
974
996
  </cac:Item>
975
997
  <cac:Price>
976
998
  <cbc:PriceAmount currencyID="${escapeXml(currency)}">${formatAmount(line.unitPrice)}</cbc:PriceAmount>
977
- ${line.baseQuantity != null ? `<cbc:BaseQuantity unitCode="${escapeXml(resolveUnitCode(line.baseQuantityUnit ?? line.unit ?? DEFAULT_UNIT))}">${line.baseQuantity}</cbc:BaseQuantity>` : ""}
999
+ ${line.baseQuantity !== void 0 ? `<cbc:BaseQuantity unitCode="${escapeXml(resolveUnitCode(line.baseQuantityUnit ?? line.unit ?? DEFAULT_UNIT))}">${formatBaseQuantity(line.baseQuantity, `lines[${index}].baseQuantity`)}</cbc:BaseQuantity>` : ""}
978
1000
  </cac:Price>
979
1001
  </cac:${lineTag}>`;
980
1002
  }
@@ -1605,6 +1627,11 @@ function validateLine(line, index, isCreditNote = false) {
1605
1627
  } else if (line.unitPrice < 0) {
1606
1628
  errors.push(error(`${path}.unitPrice`, `Unit price cannot be negative, got ${line.unitPrice}`, void 0, "For discounts, use a negative quantity or a separate discount line"));
1607
1629
  }
1630
+ if (line.baseQuantity !== void 0) {
1631
+ if (typeof line.baseQuantity !== "number" || !Number.isFinite(line.baseQuantity) || line.baseQuantity <= 0) {
1632
+ errors.push(error(`${path}.baseQuantity`, "Base quantity must be a finite number greater than zero", "PEPPOL-EN16931-R121", "Use a positive number for the item price base quantity"));
1633
+ }
1634
+ }
1608
1635
  if (line.vatRate === void 0 || line.vatRate === null) {
1609
1636
  errors.push(error(`${path}.vatRate`, "VAT rate is required", "BR-CO-17"));
1610
1637
  } else if (line.vatRate < 0 || line.vatRate > 100) {
@@ -2304,7 +2331,7 @@ function statusFamily(status) {
2304
2331
  var TERMINAL_FAILURE_STATUSES = STATUS_PRECEDENCE.filter((e) => e.family === "terminal-failure").map((e) => e.status);
2305
2332
 
2306
2333
  // ../sdk/dist/version.js
2307
- var SDK_VERSION = "4.6.0";
2334
+ var SDK_VERSION = "4.8.0";
2308
2335
 
2309
2336
  // ../sdk/dist/core/client.js
2310
2337
  function findHeaderCaseInsensitive(headers, name) {
@@ -2537,9 +2564,8 @@ var GetpepprAdapter = class {
2537
2564
  clearTimeout(timeoutId);
2538
2565
  }
2539
2566
  }
2540
- // NOTE: sendInvoice and createInvoice hit the same SDK endpoint (POST /invoices).
2541
- // The gateway (Tasks 9-10) differentiates them: sendInvoice wraps with
2542
- // { invoice: {...}, send_after_import: true }, createInvoice omits the flag.
2567
+ // sendInvoice and createInvoice hit the same endpoint. The latter adds the
2568
+ // legacy `_draft` marker, which the current gateway rejects explicitly.
2543
2569
  async sendInvoice(input, options) {
2544
2570
  const headers = {};
2545
2571
  if (options?.idempotencyKey) {
@@ -2578,6 +2604,8 @@ var GetpepprAdapter = class {
2578
2604
  params.set("limit", String(options.limit));
2579
2605
  if (options?.offset != null)
2580
2606
  params.set("offset", String(options.offset));
2607
+ if (options?.number != null)
2608
+ params.set("number", options.number);
2581
2609
  if (options?.includeLines)
2582
2610
  params.set("include", "lines");
2583
2611
  const query = params.toString() ? `?${params.toString()}` : "";
@@ -2711,7 +2739,9 @@ var GetpepprAdapter = class {
2711
2739
  params.set("limit", String(options.limit));
2712
2740
  if (options?.offset != null)
2713
2741
  params.set("offset", String(options.offset));
2714
- if (options?.invoiceId)
2742
+ if (options?.documentId != null)
2743
+ params.set("documentId", options.documentId);
2744
+ if (options?.invoiceId != null)
2715
2745
  params.set("invoiceId", options.invoiceId);
2716
2746
  if (options?.dateFrom)
2717
2747
  params.set("dateFrom", options.dateFrom);
@@ -3218,9 +3248,49 @@ function parseAccountIdentity(raw) {
3218
3248
  return {
3219
3249
  environment,
3220
3250
  legalEntity: parseAccountIdentityLegalEntity(readOwn(result, "legalEntity"), result),
3221
- identifiers
3251
+ identifiers,
3252
+ sandboxFirstSend: parseSandboxFirstSendProfile(readOwn(result, "sandboxFirstSend"), result)
3222
3253
  };
3223
3254
  }
3255
+ function parseSandboxFirstSendProfile(raw, body) {
3256
+ if (raw === null)
3257
+ return null;
3258
+ if (!isRecord(raw)) {
3259
+ throw new PeppolProtocolError("The getpeppr API answered the identity request without a valid sandboxFirstSend field. Please report this response to support@getpeppr.dev.", "sandboxFirstSend", boundedBody(body));
3260
+ }
3261
+ const status = readOwn(raw, "status");
3262
+ if (status === "blocked") {
3263
+ const code = readOwn(raw, "code");
3264
+ const message = readOwn(raw, "message");
3265
+ if (typeof code === "string" && code.trim() !== "" && typeof message === "string" && message.trim() !== "") {
3266
+ return { status, code, message };
3267
+ }
3268
+ }
3269
+ if (status === "ready") {
3270
+ const taxMode = readOwn(raw, "taxMode");
3271
+ const line = readOwn(raw, "line");
3272
+ if ((taxMode === "outside_scope" || taxMode === "reverse_charge") && isRecord(line)) {
3273
+ const vatRate = readOwn(line, "vatRate");
3274
+ const vatCategory = readOwn(line, "vatCategory");
3275
+ const taxExemptReason = readOwn(line, "taxExemptReason");
3276
+ if (vatRate === 0 && typeof taxExemptReason === "string" && taxExemptReason.trim() !== "" && taxMode === "outside_scope" && vatCategory === "O") {
3277
+ return {
3278
+ status,
3279
+ taxMode,
3280
+ line: { vatRate, vatCategory, taxExemptReason }
3281
+ };
3282
+ }
3283
+ if (vatRate === 0 && typeof taxExemptReason === "string" && taxExemptReason.trim() !== "" && taxMode === "reverse_charge" && vatCategory === "AE") {
3284
+ return {
3285
+ status,
3286
+ taxMode,
3287
+ line: { vatRate, vatCategory, taxExemptReason }
3288
+ };
3289
+ }
3290
+ }
3291
+ }
3292
+ throw new PeppolProtocolError("The getpeppr API answered the identity request with a malformed sandboxFirstSend profile. Please report this response to support@getpeppr.dev.", "sandboxFirstSend", boundedBody(body));
3293
+ }
3224
3294
  function parseAccountIdentityLegalEntity(raw, body) {
3225
3295
  if (raw === null)
3226
3296
  return null;
@@ -3521,16 +3591,12 @@ var InvoiceOperations = class {
3521
3591
  this.adapter = adapter;
3522
3592
  }
3523
3593
  /**
3524
- * Create a draft invoice without sending it.
3525
- * Validates input client-side, then creates the invoice via the gateway.
3526
- * Use `sendById()` to send the draft when ready.
3594
+ * Request draft creation from the gateway.
3527
3595
  *
3528
- * @example
3529
- * ```ts
3530
- * const draft = await peppol.invoices.create({ number: "INV-001", to, lines });
3531
- * // Later, when ready:
3532
- * await peppol.invoices.sendById(draft.id);
3533
- * ```
3596
+ * @deprecated The current Storecove-backed gateway does not support drafts
3597
+ * and returns 422 `drafts_not_supported`. Submit the final document with
3598
+ * `invoices.send()` instead.
3599
+ * @throws {PeppolApiError} 422 with code `drafts_not_supported`
3534
3600
  */
3535
3601
  async create(input, options) {
3536
3602
  const validation = validateInvoice(input);
@@ -3545,14 +3611,11 @@ ${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (
3545
3611
  return result;
3546
3612
  }
3547
3613
  /**
3548
- * Send an existing draft invoice by ID.
3549
- * The invoice must have been previously created with `create()`.
3614
+ * Request sending of an existing draft invoice by ID.
3550
3615
  *
3551
- * @example
3552
- * ```ts
3553
- * await peppol.invoices.sendById("inv-1");
3554
- * ```
3555
- * @throws {PeppolApiError} 501 if the gateway provider does not support draft sending
3616
+ * @deprecated The current Storecove-backed gateway has no draft lifecycle and
3617
+ * always returns 501. Submit the final document with `invoices.send()`.
3618
+ * @throws {PeppolApiError} 501 with the current gateway provider
3556
3619
  */
3557
3620
  async sendById(id) {
3558
3621
  return this.adapter.sendInvoiceById(id);
@@ -3723,52 +3786,39 @@ ${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (
3723
3786
  return this.adapter.importInvoice(options);
3724
3787
  }
3725
3788
  /**
3726
- * Acknowledge a received invoice.
3789
+ * Request acknowledgement of a received invoice.
3727
3790
  *
3728
- * @example
3729
- * ```ts
3730
- * const result = await peppol.invoices.acknowledge("inv-123");
3731
- * console.log(result.status); // "accepted"
3732
- * ```
3733
- * @throws {PeppolApiError} 501 if the gateway provider does not support acknowledgement
3791
+ * @deprecated The current Storecove-backed gateway does not support
3792
+ * acknowledgement and always returns 501.
3793
+ * @throws {PeppolApiError} 501 with the current gateway provider
3734
3794
  */
3735
3795
  async acknowledge(id) {
3736
3796
  return this.adapter.acknowledgeInvoice(id);
3737
3797
  }
3738
3798
  /**
3739
- * Update an existing invoice (draft only).
3740
- * Only include the fields you want to change — partial updates are supported.
3799
+ * Request an update to an existing invoice.
3741
3800
  *
3742
- * @example
3743
- * ```ts
3744
- * const updated = await peppol.invoices.update("inv-123", {
3745
- * dueDate: "2026-04-01",
3746
- * lines: [
3747
- * { id: "line-1", quantity: 5 },
3748
- * { id: "line-2", _destroy: true },
3749
- * ],
3750
- * });
3751
- * ```
3752
- * @throws {PeppolApiError} 501 if the gateway provider does not support invoice updates
3801
+ * @deprecated Storecove documents are immutable after submission. The
3802
+ * current gateway always returns 501; issue a credit note instead.
3803
+ * @throws {PeppolApiError} 501 with the current gateway provider
3753
3804
  */
3754
3805
  async update(id, input) {
3755
3806
  return this.adapter.updateInvoice(id, input);
3756
3807
  }
3757
3808
  /**
3758
- * Delete an invoice.
3809
+ * Request deletion of an invoice.
3759
3810
  *
3760
- * @example
3761
- * ```ts
3762
- * const deleted = await peppol.invoices.delete("inv-123");
3763
- * ```
3764
- * @throws {PeppolApiError} 501 if the gateway provider does not support invoice deletion
3811
+ * @deprecated The current Storecove-backed gateway does not support invoice
3812
+ * deletion and always returns 501.
3813
+ * @throws {PeppolApiError} 501 with the current gateway provider
3765
3814
  */
3766
3815
  async delete(id) {
3767
3816
  return this.adapter.deleteInvoice(id);
3768
3817
  }
3769
3818
  /**
3770
- * Transition an invoice to a new state.
3771
- * The gateway validates the state machine invalid transitions return an error.
3819
+ * Report a French CTC invoice as paid.
3820
+ * Other state transitions are retained for API compatibility but the current
3821
+ * Storecove-backed gateway returns 501 for them.
3772
3822
  *
3773
3823
  * `"paid"` on a French CTC invoice reports the payment collection
3774
3824
  * (« signalement d'encaissement ») to the tax authority via the gateway —
@@ -3970,8 +4020,8 @@ var EventOperations = class {
3970
4020
  * const result = await peppol.events.list({ limit: 10 });
3971
4021
  * console.log(result.data, result.meta);
3972
4022
  *
3973
- * // Filter by invoice
3974
- * const invoiceEvents = await peppol.events.list({ invoiceId: "inv-123" });
4023
+ * // Filter by provider document ID or getpeppr submission ID
4024
+ * const invoiceEvents = await peppol.events.list({ documentId: "inv-123" });
3975
4025
  * ```
3976
4026
  */
3977
4027
  async list(options) {
@@ -3982,7 +4032,7 @@ var EventOperations = class {
3982
4032
  *
3983
4033
  * @example
3984
4034
  * ```ts
3985
- * for await (const event of peppol.events.listAll({ invoiceId: "inv-123" })) {
4035
+ * for await (const event of peppol.events.listAll({ documentId: "inv-123" })) {
3986
4036
  * console.log(event.name, event.createdAt);
3987
4037
  * }
3988
4038
  * ```
@@ -4448,14 +4498,17 @@ var INVOICE_TEMPLATE = {
4448
4498
  description: "Conseil en transformation num\xE9rique",
4449
4499
  quantity: 10,
4450
4500
  unitPrice: 950,
4451
- vatRate: 21
4501
+ vatRate: 0,
4502
+ vatCategory: "O",
4503
+ taxExemptReason: "Integration test"
4452
4504
  },
4453
4505
  {
4454
4506
  description: "Software license \u2014 annual subscription",
4455
4507
  quantity: 1,
4456
4508
  unitPrice: 2400,
4457
4509
  vatRate: 0,
4458
- vatCategory: "AE"
4510
+ vatCategory: "O",
4511
+ taxExemptReason: "Integration test"
4459
4512
  }
4460
4513
  ],
4461
4514
  paymentTerms: "Net 30 days",
@@ -4491,7 +4544,9 @@ var CREDIT_NOTE_TEMPLATE = {
4491
4544
  description: "Avoir partiel \u2014 Conseil en transformation num\xE9rique",
4492
4545
  quantity: 2,
4493
4546
  unitPrice: 950,
4494
- vatRate: 21
4547
+ vatRate: 0,
4548
+ vatCategory: "O",
4549
+ taxExemptReason: "Integration test"
4495
4550
  }
4496
4551
  ],
4497
4552
  note: "Avoir pour prestations non r\xE9alis\xE9es \u2014 r\xE9f. INV-2026-001"
@@ -4525,9 +4580,9 @@ function registerInitCommand(program2) {
4525
4580
  3. Convert to XML: getpeppr convert ${filename}
4526
4581
  4. Send: getpeppr send ${filename}
4527
4582
 
4528
- ${pc2.dim("Sandbox note:")} this template includes VAT. To send it on a sandbox
4529
- account, first register your VAT on the Peppol identity page, or set each
4530
- line's "vatCategory" to "O" (outside the scope of VAT) for a no-VAT test send.
4583
+ ${pc2.dim("Sandbox note:")} this offline template starts with O/0 tax lines.
4584
+ On send, the CLI checks GET /v1/identity and refuses a conflicting sender
4585
+ profile before anything reaches the provider.
4531
4586
  `);
4532
4587
  process.exit(0);
4533
4588
  }
@@ -5090,11 +5145,11 @@ function buildDefaultSendPayload(overrides = {}) {
5090
5145
  quantity: 1,
5091
5146
  unitPrice: amount,
5092
5147
  vatRate: 0,
5093
- // vatCategory "O" = "Services outside scope of tax" (UBL 2.1 / EN 16931).
5094
- // Public entities (SPF Economie) are VAT-exempt. The SDK pre-validator
5095
- // requires the builder-only reason; the send transport strips it so
5096
- // Storecove can still derive its own provider-specific text.
5097
- // If sandbox returns 422 on this combination, fallback is vatRate: 21 + vatCategory: "S".
5148
+ // vatCategory "O" = outside the scope of VAT (UBL 2.1 / EN 16931).
5149
+ // This offline fixture starts at O/0. Before sending, the CLI reads
5150
+ // GET /identity and replaces these tax fields with the sender-specific
5151
+ // O/0 or AE/0 first-send profile. The SDK transport strips the
5152
+ // builder-only reason so Storecove can derive its own provider text.
5098
5153
  vatCategory: "O",
5099
5154
  taxExemptReason: "Not subject to VAT"
5100
5155
  }
@@ -5270,6 +5325,42 @@ function registerSendCommand(program2) {
5270
5325
  }
5271
5326
  throw e;
5272
5327
  }
5328
+ const baseUrl = flags.local ? LOCAL_BASE : API_BASE;
5329
+ const client = new Peppol({ apiKey: auth.apiKey, baseUrl });
5330
+ if (auth.environment === "sandbox") {
5331
+ let profile;
5332
+ try {
5333
+ profile = (await client.identity.get()).sandboxFirstSend;
5334
+ } catch (e) {
5335
+ const msg = e instanceof Error ? e.message : String(e);
5336
+ process.stderr.write(`${pc6.red("\u2722")} Could not verify the sandbox sender profile: ${msg}
5337
+ `);
5338
+ process.exit(1);
5339
+ return;
5340
+ }
5341
+ if (!profile || profile.status !== "ready") {
5342
+ const message = profile?.status === "blocked" ? profile.message : "The sandbox first-send profile is unavailable.";
5343
+ process.stderr.write(`${pc6.red("\u2722")} ${message}
5344
+ `);
5345
+ process.exit(1);
5346
+ return;
5347
+ }
5348
+ const taxEntries = [payload.lines, payload.allowances, payload.charges].filter(Array.isArray).flat();
5349
+ const payloadOutsideScope = taxEntries.length > 0 && taxEntries.every((entry) => entry.vatCategory === "O");
5350
+ const profileOutsideScope = profile.taxMode === "outside_scope";
5351
+ if (file) {
5352
+ if (payloadOutsideScope !== profileOutsideScope) {
5353
+ process.stderr.write(
5354
+ `${pc6.red("\u2722")} This file's tax mode does not match the sandbox sender. GET /v1/identity recommends ${profile.line.vatCategory}/0. Nothing was sent.
5355
+ `
5356
+ );
5357
+ process.exit(1);
5358
+ return;
5359
+ }
5360
+ } else {
5361
+ payload.lines = payload.lines.map((line) => ({ ...line, ...profile.line }));
5362
+ }
5363
+ }
5273
5364
  if (flags.validate !== false) {
5274
5365
  const result2 = runValidation(payload);
5275
5366
  if (!result2.valid) {
@@ -5290,8 +5381,6 @@ function registerSendCommand(program2) {
5290
5381
  process.exit(0);
5291
5382
  }
5292
5383
  }
5293
- const baseUrl = flags.local ? LOCAL_BASE : API_BASE;
5294
- const client = new Peppol({ apiKey: auth.apiKey, baseUrl });
5295
5384
  let result;
5296
5385
  try {
5297
5386
  result = await client.invoices.send(payload);