From c67aefa44c7a9eee4f35c4960fe9162d00fa785a Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Wed, 16 Sep 2026 11:59:03 +0300 Subject: [PATCH 1/6] chore: pin SDK to sdks#12 head 00e9b05 Pin @polymorfa/sdk to github:polymorfa/sdks#00e9b05ec886db4cde77456af7b58d70eed88357, which aligns QuickLink settings and Customer types with API 1600403. --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1d550192..0bd15887 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@napi-rs/keyring": "1.3.0", "@oclif/core": "^4.13.5", - "@polymorfa/sdk": "github:polymorfa/sdks#08452992a32a392de5fc3d0fa3954ba6addd7f32" + "@polymorfa/sdk": "github:polymorfa/sdks#00e9b05ec886db4cde77456af7b58d70eed88357" }, "bin": { "polymorfa": "bin/run.js" @@ -972,8 +972,8 @@ }, "node_modules/@polymorfa/sdk": { "version": "0.1.0-dev.0", - "resolved": "git+ssh://git@github.com/polymorfa/sdks.git#08452992a32a392de5fc3d0fa3954ba6addd7f32", - "integrity": "sha512-e2+6BRTFp5OMi7aJXnL1/LBhTfL82bOp+9+Jn8FgFKn7rtoVg15AYMBdSbM9od8mm9t1vyrcRh85D9H+MrYx9g==", + "resolved": "git+ssh://git@github.com/polymorfa/sdks.git#00e9b05ec886db4cde77456af7b58d70eed88357", + "integrity": "sha512-uzKh0siPjQ3wJ6Fw1of4YC8y6CwC0o15ZaU3NRcYrMp5M+uze5LrPPgB31anRDeKPdPN5GsADGGUTEJKhkH0IA==", "workspaces": [ "packages/calls", "packages/browser", diff --git a/package.json b/package.json index 13d74106..b71787e1 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dependencies": { "@napi-rs/keyring": "1.3.0", "@oclif/core": "^4.13.5", - "@polymorfa/sdk": "github:polymorfa/sdks#08452992a32a392de5fc3d0fa3954ba6addd7f32" + "@polymorfa/sdk": "github:polymorfa/sdks#00e9b05ec886db4cde77456af7b58d70eed88357" }, "devDependencies": { "@eslint/js": "^9.39.5", From b42514dcab12f1c6d034acb60e41c95e86eb24c2 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Wed, 16 Sep 2026 11:59:03 +0300 Subject: [PATCH 2/6] fix: remove Customer phone and retired settings fields from commands Drop customer create --phone and customer update --phone/--clear-phone, and the pairing-link --locale/--theme flags, which the Customer contract no longer accepts. Keep --expected-phone. Show the external ID instead of a masked phone in Customer lists and remove the phone row from Customer output. Replace the redirect-URI row in widget settings output with the success and failure callback URLs and the phone-change policy. Tests reject the retired flags before any request. --- src/commands/customer/create.ts | 4 -- src/commands/customer/pairing-link/create.ts | 14 ------ src/commands/customer/update.ts | 10 ----- src/services/customers.ts | 9 +--- src/services/platform-management.ts | 4 +- test/commands/customers.test.ts | 47 +++++++++++++++----- test/commands/platform-management.test.ts | 45 +++++++++++++++---- 7 files changed, 76 insertions(+), 57 deletions(-) diff --git a/src/commands/customer/create.ts b/src/commands/customer/create.ts index 0117eb6d..348e8f14 100644 --- a/src/commands/customer/create.ts +++ b/src/commands/customer/create.ts @@ -17,9 +17,6 @@ export default class CustomerCreate extends BaseCommand { required: true, }), name: Flags.string({description: 'Customer name.'}), - phone: Flags.string({ - description: 'Customer phone number in E.164 format.', - }), } async run(): Promise { @@ -29,7 +26,6 @@ export default class CustomerCreate extends BaseCommand { { projectId: requireCustomerProject(flags.project), ...(flags.name === undefined ? {} : {name: flags.name}), - ...(flags.phone === undefined ? {} : {phone: flags.phone}), ...(flags['external-id'] === undefined ? {} : {externalCustomerId: flags['external-id']}), diff --git a/src/commands/customer/pairing-link/create.ts b/src/commands/customer/pairing-link/create.ts index ad5402e4..a48a8f94 100644 --- a/src/commands/customer/pairing-link/create.ts +++ b/src/commands/customer/pairing-link/create.ts @@ -27,19 +27,11 @@ export default class CustomerPairingLinkCreate extends BaseCommand { description: 'Identify this pairing-link attempt for safe retries.', required: true, }), - locale: Flags.string({ - description: 'Pairing page locale.', - options: ['en', 'pt-BR'], - }), method: Flags.string({ description: 'Allowed pairing method.', multiple: true, options: ['qr', 'phone'], }), - theme: Flags.string({ - description: 'Pairing page theme.', - options: ['light', 'dark', 'system'], - }), } async run(): Promise { @@ -55,15 +47,9 @@ export default class CustomerPairingLinkCreate extends BaseCommand { ...(flags['expires-in'] === undefined ? {} : {expiresInSeconds: flags['expires-in']}), - ...(flags.locale === undefined - ? {} - : {locale: flags.locale as 'en' | 'pt-BR'}), ...(flags.method === undefined ? {} : {methods: flags.method as Array<'qr' | 'phone'>}), - ...(flags.theme === undefined - ? {} - : {theme: flags.theme as 'light' | 'dark' | 'system'}), }, {idempotencyKey: flags['idempotency-key']}, ) diff --git a/src/commands/customer/update.ts b/src/commands/customer/update.ts index 2db3f0c7..016b2696 100644 --- a/src/commands/customer/update.ts +++ b/src/commands/customer/update.ts @@ -23,17 +23,10 @@ export default class CustomerUpdate extends BaseCommand { description: 'Clear the Customer name.', exclusive: ['name'], }), - 'clear-phone': Flags.boolean({ - description: 'Clear the Customer phone number.', - exclusive: ['phone'], - }), 'external-id': Flags.string({ description: 'New caller-defined Customer ID.', }), name: Flags.string({description: 'New Customer name.'}), - phone: Flags.string({ - description: 'New Customer phone number in E.164 format.', - }), } async run(): Promise { @@ -46,9 +39,6 @@ export default class CustomerUpdate extends BaseCommand { ...(flags.name === undefined && flags['clear-name'] !== true ? {} : {name: flags.name ?? null}), - ...(flags.phone === undefined && flags['clear-phone'] !== true - ? {} - : {phone: flags.phone ?? null}), ...(flags['external-id'] === undefined && flags['clear-external-id'] !== true ? {} diff --git a/src/services/customers.ts b/src/services/customers.ts index 55504f2c..4fcfe475 100644 --- a/src/services/customers.ts +++ b/src/services/customers.ts @@ -89,11 +89,7 @@ export async function updateCustomer( customerId: string, body: UpdateCustomerRequest, ): Promise> { - if ( - body.name === undefined && - body.phone === undefined && - body.externalCustomerId === undefined - ) { + if (body.name === undefined && body.externalCustomerId === undefined) { throw new PolymorfaValidationError( 'Provide at least one Customer profile field to update.', {code: 'missing_customer_update'}, @@ -204,7 +200,7 @@ export function renderCustomers(customers: CustomerListEnvelope): string { [ customer.id, customer.name ?? '', - customer.phoneMasked ?? '', + customer.externalCustomerId ?? '', customer.status, `${customer.connectedNumberCount}/${customer.numberCount} connected`, customer.needsAttention ? 'needs attention' : '', @@ -217,7 +213,6 @@ export function renderCustomer(customer: Customer): string { return [ `ID\t${customer.id}`, `Name\t${customer.name ?? ''}`, - `Phone\t${customer.phone ?? ''}`, `External ID\t${customer.externalCustomerId ?? ''}`, `Status\t${customer.status}`, `Default\t${customer.isDefault}`, diff --git a/src/services/platform-management.ts b/src/services/platform-management.ts index 162419c6..79bdeced 100644 --- a/src/services/platform-management.ts +++ b/src/services/platform-management.ts @@ -248,7 +248,9 @@ export function renderWidgetSettings( `Methods\t${settings.methods?.join(', ') ?? 'default'}`, `Theme\t${settings.theme}`, `Business name\t${settings.businessName ?? ''}`, - `Redirect URIs\t${settings.allowedRedirectUris.join(', ')}`, + `Success callback URL\t${settings.successCallbackUrl ?? ''}`, + `Failure callback URL\t${settings.failureCallbackUrl ?? ''}`, + `Allow phone change\t${settings.allowPhoneChange}`, `Hide watermark\t${settings.hideWatermark}`, `Shape\t${settings.shape ?? 'default'}`, `Radius\t${settings.radiusPx ?? 'default'}`, diff --git a/test/commands/customers.test.ts b/test/commands/customers.test.ts index 3284742d..e1cb5688 100644 --- a/test/commands/customers.test.ts +++ b/test/commands/customers.test.ts @@ -94,7 +94,7 @@ describe('Customer commands', () => { const created = await environment(() => runCommand( - 'customer create --project project/1 --name Ada --phone +15551234567 --external-id crm/1 --idempotency-key create_1 --json', + 'customer create --project project/1 --name Ada --external-id crm/1 --idempotency-key create_1 --json', ), ) const viewed = await environment(() => @@ -102,7 +102,7 @@ describe('Customer commands', () => { ) const updated = await environment(() => runCommand( - 'customer update customer/1 --project project/1 --clear-name --phone +15557654321 --json', + 'customer update customer/1 --project project/1 --clear-name --external-id crm/2 --json', ), ) @@ -117,12 +117,11 @@ describe('Customer commands', () => { expect(JSON.parse(server.requests[0]?.body ?? '')).toEqual({ externalCustomerId: 'crm/1', name: 'Ada', - phone: '+15551234567', projectId: 'project/1', }) expect(JSON.parse(server.requests[2]?.body ?? '')).toEqual({ + externalCustomerId: 'crm/2', name: null, - phone: '+15557654321', projectId: 'project/1', }) }) @@ -195,7 +194,7 @@ describe('Customer commands', () => { const created = await environment(() => runCommand( - 'customer pairing-link create customer/1 --project project/1 --expected-phone +15551234567 --method qr --method phone --expires-in 3600 --locale en --theme system --idempotency-key link_1 --json', + 'customer pairing-link create customer/1 --project project/1 --expected-phone +15551234567 --method qr --method phone --expires-in 3600 --idempotency-key link_1 --json', ), ) const revoked = await environment(() => @@ -220,10 +219,8 @@ describe('Customer commands', () => { expect(JSON.parse(server.requests[0]?.body ?? '')).toEqual({ expectedPhone: '+15551234567', expiresInSeconds: 3600, - locale: 'en', methods: ['qr', 'phone'], projectId: 'project/1', - theme: 'system', }) expect(JSON.parse(server.requests[2]?.body ?? '')).toEqual({ confirm: true, @@ -233,6 +230,36 @@ describe('Customer commands', () => { expect(server.requests[2]?.headers['idempotency-key']).toBe('transfer_1') }) + test('renders Customer profiles without a phone field', async () => { + server = await startHttpServer({body: {data: customer()}}) + + const viewed = await environment(() => + runCommand('customer view customer/1 --project project/1'), + ) + + expect(viewed.error).toBeUndefined() + expect(viewed.stdout).toContain('External ID\tcrm/1') + expect(viewed.stdout).not.toMatch(/phone/i) + }) + + test('rejects retired Customer phone and invitation presentation flags before transport', async () => { + server = await startHttpServer({body: {data: customer()}}) + + const commands = [ + 'customer create --project project/1 --phone +15551234567 --idempotency-key create_2 --json', + 'customer update customer/1 --project project/1 --phone +15551234567 --json', + 'customer update customer/1 --project project/1 --clear-phone --json', + 'customer pairing-link create customer/1 --project project/1 --locale en --idempotency-key link_2 --json', + 'customer pairing-link create customer/1 --project project/1 --theme dark --idempotency-key link_3 --json', + ] + for (const command of commands) { + const result = await environment(() => runCommand(command)) + expect(exitCode(result.error), command).toBe(2) + expect(result.stderr, command).toMatch(/Nonexistent flag/) + } + expect(server.requests).toHaveLength(0) + }) + test('rejects missing project context and empty updates before transport', async () => { server = await startHttpServer({body: {data: customer()}}) @@ -275,7 +302,6 @@ function customer() { isDefault: false, name: 'Ada', orgId: 'org_1', - phone: '+15551234567', projectId: 'project/1', status: 'active', updatedAt: 1_725_000_000_000, @@ -283,16 +309,13 @@ function customer() { } function customerSummary() { - const {phone: _phone, ...value} = customer() - void _phone return { - ...value, + ...customer(), activePairingLinkState: 'active', connectedNumberCount: 1, lastActivityAt: 1_725_000_000_000, needsAttention: false, numberCount: 1, - phoneMasked: '+1•••4567', } } diff --git a/test/commands/platform-management.test.ts b/test/commands/platform-management.test.ts index c752a452..9db8031c 100644 --- a/test/commands/platform-management.test.ts +++ b/test/commands/platform-management.test.ts @@ -379,12 +379,30 @@ describe('Platform management commands', () => { ) }) + test('renders saved QuickLink callbacks and phone-change policy', async () => { + server = await startHttpServer({body: {data: widgetSettings()}}) + + const result = await platformEnvironment(() => + runCommand('widget view --project project_1'), + ) + + expect(result.error).toBeUndefined() + expect(result.stdout).toContain( + 'Success callback URL\thttps://app.example.com/connected', + ) + expect(result.stdout).toContain('Failure callback URL\t\n') + expect(result.stdout).toContain('Allow phone change\tfalse') + expect(result.stdout).not.toContain('Redirect') + }) + test('updates a widget patch with separate project scope and idempotency', async () => { const input = await jsonInput('widget.json', { - allowedRedirectUris: ['https://app.example.com/connected'], + allowPhoneChange: true, businessName: 'Example', enabled: true, + failureCallbackUrl: null, methods: ['qr'], + successCallbackUrl: 'https://app.example.com/connected', theme: 'dark', }) server = await startHttpServer({body: {data: widgetSettings()}}) @@ -397,11 +415,13 @@ describe('Platform management commands', () => { expect(result.error).toBeUndefined() expect(JSON.parse(server.requests[0]?.body ?? '')).toEqual({ - allowedRedirectUris: ['https://app.example.com/connected'], + allowPhoneChange: true, businessName: 'Example', enabled: true, + failureCallbackUrl: null, methods: ['qr'], projectId: 'project_1', + successCallbackUrl: 'https://app.example.com/connected', theme: 'dark', }) expect(server.requests[0]).toMatchObject({ @@ -531,23 +551,30 @@ describe('Platform management commands', () => { function widgetSettings() { return { accent: null, - allowedOrigins: ['https://app.example.com'], - allowedRedirectUris: [], + allowPhoneChange: false, businessName: 'Example', - colors: null, createdAt: 1_723_000_000_000, + defaultMethod: null, + description: null, enabled: true, + failureCallbackUrl: null, + headline: null, hideWatermark: false, historySync: 'ask', id: 'widget_1', + logoMode: 'none', + logoSourceStorageId: null, + logoStorageId: null, + logoUrl: null, methods: ['qr'], - modesAllowed: ['embedded'], + privacyUrl: null, projectId: 'project_1', - qrLogoMode: 'none', - qrLogoSourceStorageId: null, - qrLogoStorageId: null, radiusPx: null, shape: null, + successCallbackUrl: 'https://app.example.com/connected', + successMessage: null, + supportUrl: null, + termsUrl: null, theme: 'dark', updatedAt: 1_723_000_000_000, } From 2f061ff459d073294d06fe83dd2f6026c3debc83 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Wed, 16 Sep 2026 11:59:03 +0300 Subject: [PATCH 3/6] docs: describe Customer invitations and QuickLink settings fields Remove Customer phone from examples, document --expected-phone, the saved callback URLs and allowPhoneChange, and correct the settings scope to quicklink:manage. --- README.md | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 18ff1cb3..1917dc86 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,6 @@ polymorfa customer enable \ polymorfa customer create \ --project project_123 \ --name Ada \ - --phone +15551234567 \ --external-id crm_456 \ --idempotency-key create-customer-crm-456 @@ -81,9 +80,16 @@ polymorfa customer pairing-link create customer_123 \ --project project_123 \ --method qr \ --method phone \ + --expected-phone +15551234567 \ --idempotency-key pair-customer-123 ``` +Customer profiles hold a name and an external ID; they have no phone field. To +reserve an invitation for one number, pass `--expected-phone` to +`customer pairing-link create`. Pairing links accept `--method`, +`--expected-phone`, and `--expires-in`; page language and theme are not +per-link options. + The `customer` commands cover project enablement, list filters and cursors, profile creation and updates, archive and restore, assigned Numbers, recent events, pairing-link creation/listing/revocation, and confirmed Number @@ -535,12 +541,28 @@ API-key creation, token mint/revoke, incident detail, or cross-project token aggregate in this typed slice. The raw API command is not a credential-boundary bypass. -Widget view returns `null` in JSON when no settings row has been saved. Update +`widget view` and `widget update` manage saved QuickLink settings. View +returns `null` in JSON when no settings row has been saved. Update accepts one bounded JSON object from `--input`; the target project is selected separately with `--project` and cannot be hidden in that input. Omitting the project targets organization defaults. Widget logo fields are existing storage -identifiers, not file, URL, base64, upload, or download operations. Widget -access requires the source `widget:create` scope. +identifiers, not file, URL, base64, upload, or download operations. Both +commands require the `quicklink:manage` scope. + +Settings accept `successCallbackUrl` and `failureCallbackUrl`: project-only +HTTPS destinations that the API copies into each link when it is issued. Set +`allowPhoneChange` to `true` to let recipients replace a prefilled number; the +default is `false`. `hideWatermark: true` requires Premium team access. Settings +have no redirect-URI allowlist. Human output shows both callback URLs and the +phone-change policy. + +```json +{ + "successCallbackUrl": "https://app.example.com/whatsapp/connected", + "failureCallbackUrl": "https://app.example.com/whatsapp/cancelled", + "allowPhoneChange": false +} +``` Session stop and delete accept 1 through 100 unique UUIDs or stable slugs. The CLI trims IDs and rejects duplicates or oversized batches before transport. From a1814dcb272094f20a32187fd9a76d40a4dcb631 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Wed, 16 Sep 2026 16:00:40 +0300 Subject: [PATCH 4/6] chore(deps): pin SDK cloud-launch head rebased on dev --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0bd15887..9bde2120 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@napi-rs/keyring": "1.3.0", "@oclif/core": "^4.13.5", - "@polymorfa/sdk": "github:polymorfa/sdks#00e9b05ec886db4cde77456af7b58d70eed88357" + "@polymorfa/sdk": "github:polymorfa/sdks#d9b08f9d0e2ae571df8a4f766e921993a44ce3df" }, "bin": { "polymorfa": "bin/run.js" @@ -972,8 +972,8 @@ }, "node_modules/@polymorfa/sdk": { "version": "0.1.0-dev.0", - "resolved": "git+ssh://git@github.com/polymorfa/sdks.git#00e9b05ec886db4cde77456af7b58d70eed88357", - "integrity": "sha512-uzKh0siPjQ3wJ6Fw1of4YC8y6CwC0o15ZaU3NRcYrMp5M+uze5LrPPgB31anRDeKPdPN5GsADGGUTEJKhkH0IA==", + "resolved": "git+ssh://git@github.com/polymorfa/sdks.git#d9b08f9d0e2ae571df8a4f766e921993a44ce3df", + "integrity": "sha512-3g7qQ8P/GsHJGNT2/KcjUnff4js96Ym5nuG0e9YKFF0C2IxFH5dlLrieen5Z1wuAKCCCIWibdIAE0N3llX1X2g==", "workspaces": [ "packages/calls", "packages/browser", diff --git a/package.json b/package.json index b71787e1..ec08babe 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dependencies": { "@napi-rs/keyring": "1.3.0", "@oclif/core": "^4.13.5", - "@polymorfa/sdk": "github:polymorfa/sdks#00e9b05ec886db4cde77456af7b58d70eed88357" + "@polymorfa/sdk": "github:polymorfa/sdks#d9b08f9d0e2ae571df8a4f766e921993a44ce3df" }, "devDependencies": { "@eslint/js": "^9.39.5", From 581fe39f6ce4fa8e4f941d6942c21925597a8787 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Wed, 16 Sep 2026 18:56:12 +0300 Subject: [PATCH 5/6] chore(deps): pin SDK dev at the merged BanSafe and cloud-launch changes --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9bde2120..57478d3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@napi-rs/keyring": "1.3.0", "@oclif/core": "^4.13.5", - "@polymorfa/sdk": "github:polymorfa/sdks#d9b08f9d0e2ae571df8a4f766e921993a44ce3df" + "@polymorfa/sdk": "github:polymorfa/sdks#8803f0554314214519971cb3306e0c0efe21cb76" }, "bin": { "polymorfa": "bin/run.js" @@ -972,8 +972,8 @@ }, "node_modules/@polymorfa/sdk": { "version": "0.1.0-dev.0", - "resolved": "git+ssh://git@github.com/polymorfa/sdks.git#d9b08f9d0e2ae571df8a4f766e921993a44ce3df", - "integrity": "sha512-3g7qQ8P/GsHJGNT2/KcjUnff4js96Ym5nuG0e9YKFF0C2IxFH5dlLrieen5Z1wuAKCCCIWibdIAE0N3llX1X2g==", + "resolved": "git+ssh://git@github.com/polymorfa/sdks.git#8803f0554314214519971cb3306e0c0efe21cb76", + "integrity": "sha512-rLG5Gg7X3U3iBxHU93PVZGrIIUnNlnX7I4TT1k8EaYQrkjPm6TkA83akOEPQzJbzTMQa13+hUqT/P4deYSyh5Q==", "workspaces": [ "packages/calls", "packages/browser", diff --git a/package.json b/package.json index ec08babe..367a0905 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dependencies": { "@napi-rs/keyring": "1.3.0", "@oclif/core": "^4.13.5", - "@polymorfa/sdk": "github:polymorfa/sdks#d9b08f9d0e2ae571df8a4f766e921993a44ce3df" + "@polymorfa/sdk": "github:polymorfa/sdks#8803f0554314214519971cb3306e0c0efe21cb76" }, "devDependencies": { "@eslint/js": "^9.39.5", From 479ef9baf095a8855b52ad6fd84a6676f32e56bf Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Thu, 17 Sep 2026 00:02:23 +0300 Subject: [PATCH 6/6] test(customers): assert the complete list JSON response --- test/commands/customers.test.ts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/test/commands/customers.test.ts b/test/commands/customers.test.ts index e1cb5688..682a6272 100644 --- a/test/commands/customers.test.ts +++ b/test/commands/customers.test.ts @@ -77,11 +77,30 @@ describe('Customer commands', () => { expect(server.requests[0]?.url).toBe( '/platform/customers?projectId=project%2F1&cursor=cursor%2F1&limit=20&search=Ada&status=active&isDefault=false&hasNumbers=true&needsAttention=false', ) - expect(JSON.parse(result.stdout)).toMatchObject({ + expect(JSON.parse(result.stdout)).toEqual({ data: { - data: [customerSummary()], + data: [ + { + activePairingLinkState: 'active', + archivedAt: null, + connectedNumberCount: 1, + createdAt: 1_725_000_000_000, + externalCustomerId: 'crm/1', + id: 'customer/1', + isDefault: false, + lastActivityAt: 1_725_000_000_000, + name: 'Ada', + needsAttention: false, + numberCount: 1, + orgId: 'org_1', + projectId: 'project/1', + status: 'active', + updatedAt: 1_725_000_000_000, + }, + ], page: {hasMore: true, nextCursor: 'cursor_2'}, }, + metadata: {attempts: 1, status: 200}, }) })