diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 00000000..1bab34c3
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,75 @@
+{
+ "root": true,
+ "env": {
+ "es6": true,
+ "es2021": true,
+ "node": true,
+ "jest/globals": true
+ },
+ "extends": [
+ "eslint:recommended",
+ "google",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:jest/recommended",
+ "plugin:jest-formatting/recommended",
+ "prettier"
+ ],
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "ecmaVersion": "latest",
+ "sourceType": "module"
+ },
+ "plugins": [
+ "@typescript-eslint",
+ "deprecation",
+ "jest",
+ "jest-extended",
+ "jest-formatting",
+ "prettier"
+ ],
+ "rules": {
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-var-requires": "off",
+ "semi": "warn",
+ "comma-dangle": "warn",
+ "jest-extended/prefer-to-be-true": "warn",
+ "jest-extended/prefer-to-be-false": "error",
+ "jest-formatting/padding-around-describe-blocks": 2,
+ "jest-formatting/padding-around-test-blocks": 2,
+ "jest/expect-expect": "error",
+ "curly": [
+ "error",
+ "all"
+ ],
+ "indent": [
+ "error",
+ 2
+ ],
+ "object-curly-spacing": [
+ "error",
+ "always",
+ {
+ "objectsInObjects": true,
+ "arraysInObjects": true
+ }
+ ],
+ "require-jsdoc": [
+ "off"
+ ],
+ "operator-linebreak": [
+ "error",
+ "before"
+ ],
+ "max-len": [
+ "error",
+ {
+ "code": 120,
+ "ignoreUrls": true,
+ "ignoreComments": true,
+ "ignoreTemplateLiterals": true,
+ "ignoreRegExpLiterals": true,
+ "ignorePattern": "^import.+|test"
+ }
+ ]
+ }
+}
diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml
new file mode 100644
index 00000000..f6f5249d
--- /dev/null
+++ b/.github/workflows/run_tests.yaml
@@ -0,0 +1,26 @@
+name: Test Sinch Node.js SDK
+
+on:
+ push:
+ branches:
+ - 'main'
+ pull_request:
+ branches: [main]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version: [16.x, 18.x, 20.x]
+ steps:
+ - uses: actions/checkout@v3
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v3
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: yarn install
+ - run: npx eslint "packages/**/src/**/*.ts"
+ - run: npx eslint "packages/**/tests/**/*.ts"
+ - run: yarn run build
+ - run: yarn run test
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..f7ac1425
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+.DS_Store
+.idea
+node_modules
+tsconfig.tsbuildinfo
+packages/**/dist
+.env
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 00000000..6ac3d910
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,17 @@
+{
+ "trailingComma": "all",
+ "endOfLine": "lf",
+ "tabWidth": 2,
+ "semi": true,
+ "singleQuote": true,
+ "bracketSpacing": true,
+ "overrides": [
+ {
+ "files": "*.json",
+ "options": {
+ "parser": "json",
+ "proseWrap": "always"
+ }
+ }
+ ]
+}
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..6792d3ae
--- /dev/null
+++ b/README.md
@@ -0,0 +1,110 @@
+
+
+ [![Sinch Logo](https://developers.sinch.com/static/logo-07afe977d6d9dcd21b066d1612978e5c.svg)](https://www.sinch.com)
+
+ Node.js SDK
+
+ ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/sinch/sinch-sdk-node/run_tests.yaml?branch=main)
+ [![Node.js LTS](https://img.shields.io/badge/Node.js-LTS%20supported-brightgreen)](https://nodejs.org/en/download/)
+ ![Latest Release](https://img.shields.io/npm/v/@sinch/sdk-core?label=%40sinch%2Fsdk-core&labelColor=FFC658)
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sinch/sinch-sdk-python/blob/main/LICENSE)
+
+
+
+## Welcome to Sinch's Node.js SDK.
+
+Here you'll find documentation to start developing Node.js code using Sinch services.
+
+To use this SDK you'll need a Sinch account. Please [sign up](https://dashboard.sinch.com/signup) or [log in](https://dashboard.sinch.com/login) if you already have one.
+
+Once logged-in you'll find different sets of credentials to access to the various Sinch APIs:
+ - On the [Account dashboard](https://dashboard.sinch.com/account/access-keys), you will find your `projectId` and access keys composed of pairs of `keyId` / `keySecret`. Unless mentionned otherwise, these are the credentials you will need to access most of the Sinch APIs
+ - For the **Verification** and **Voice** APIs, you will find pairs of `App key` / `App secret` in the [Verification dashboard](https://dashboard.sinch.com/verification/apps) and the [Voice dashboard](https://dashboard.sinch.com/voice/apps) respectively. Note that the apps are the same, wherever you access them.
+ - For the **SMS** API, the standard credentials (`projectId`, `keyId`, `keySecret`) are available only in the US and EU regions. If your business involves any of the other regions (BR, CA, AU), you will need to use your `servicePlanId` that you can find on the [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services). Note that the `servicePlanId` supports all the regions (US, EU, BR, CA, AU).
+
+For more in depth information about the Sinch APIs, please refer to the official developer portal - [developers.sinch.com](https://developers.sinch.com/)
+
+Warning:
+**This SDK is currently available for preview purposes only. It should not be used in production environments.**
+
+## Installation
+
+### With NPM
+
+```bash
+npm install @sinch/sdk-core
+```
+
+### With Yarn
+
+```bash
+yarn add @sinch/sdk-core
+```
+
+## Constructor
+
+```typescript
+import {
+ SinchClient,
+} from '@sinch/sdk-core';
+
+const sinchClient = new SinchClient(sinchClientParameters);
+```
+where `sinchClientParameters` is an object containing the properties required to access the API you want to use:
+ - for **Verification** and **Voice** APIs:
+ - `applicationKey`
+ - `applicationSecret`
+ - for **SMS** API when using the AU, BR or CA region (works also for US and EU)
+ - `servicePlanId`
+ - `apiToken`
+ - for all the other APIs (including SMS is using the US and EU regions only)
+ - `projectId`
+ - `keyId`
+ - `keySecret`
+
+## Promises
+All the methods that interact with the Sinch APIs use Promises.
+```typescript
+const response: SendSMSResponse = await sinchClient.sms.batches.send({
+ SendSMSRequest: {
+ to: [
+ '+12223334444',
+ '+12223335555'
+ ],
+ from: '+12228889999',
+ parameters: {
+ name: {
+ '+12223334444': 'John',
+ default: 'there',
+ }
+ },
+ body: 'Hi ${name}',
+ type: 'mt_text',
+ },
+});
+console.log(`The SMS has been sent successfully. Here is the batch id: ${response.id}`)
+```
+
+## Examples
+You can find an example of each request in the [examples/simple-examples](./examples/simple-examples/) folder.
+
+## Contact
+Developer Experience team: [devexp@sinch.com](mailto:devexp@sinch.com)
+
+## Supported APIs
+
+Here is the list of the Sinch API and there level of support by the Node.js SDK:
+
+| API Category | API Name | Status |
+|------------------------|-------------------------------------|:------:|
+| Messaging | SMS API | ✅ |
+| | Conversation API | ❌ |
+| | RCS API | ❌ |
+| | MMS API | ❌ |
+| | Provisioning API | ❌ |
+| Voice and Video | Voice API | ❌ |
+| | Elastic SIP Trunking | ❌ |
+| Numbers & Connectivity | Numbers API | ✅ |
+| | Brand and Campaign Registration API | ❌ |
+| | Number Lookup API | ❌ |
+| Verification | Verification API | ✅ |
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 00000000..c2eb0c6a
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,7 @@
+module.exports = {
+ presets: [
+ ['@babel/preset-env', { targets: { node: 'current' } }],
+ '@babel/preset-typescript',
+ ],
+
+};
diff --git a/examples/integrated-flows-examples/.env.template b/examples/integrated-flows-examples/.env.template
new file mode 100644
index 00000000..8debcfca
--- /dev/null
+++ b/examples/integrated-flows-examples/.env.template
@@ -0,0 +1,5 @@
+# Credentials for APIs using OAuth2 authentication
+PROJECT_ID=project-id found at https://dashboard.sinch.com/account/access-keys
+KEY_ID=access-key-id found at https://dashboard.sinch.com/account/access-keys
+KEY_SECRET=access-key-secret found at access-key creation time
+
diff --git a/examples/integrated-flows-examples/.gitignore b/examples/integrated-flows-examples/.gitignore
new file mode 100644
index 00000000..2ff5437a
--- /dev/null
+++ b/examples/integrated-flows-examples/.gitignore
@@ -0,0 +1,8 @@
+# compiled output
+/dist
+/node_modules
+
+# OS
+.DS_Store
+
+.env
diff --git a/examples/integrated-flows-examples/README.md b/examples/integrated-flows-examples/README.md
new file mode 100644
index 00000000..2b72ecde
--- /dev/null
+++ b/examples/integrated-flows-examples/README.md
@@ -0,0 +1,68 @@
+# Integrated flows with the Sinch Node.js SDK
+
+This directory contains some code samples to illustrate how to chain services supported in the Sinch Node.js SDK.
+
+## Prerequisites
+
+Before trying to run a sample, make sure you have Node.js installed: please download and install the LTS version from [nodejs.org](https://nodejs.org).
+
+Once installed, check you can run node with the following command:
+
+```bash
+node --version
+```
+
+You should see a result such as `v20.10.0`, matching the LTS you have downloaded or the version you had previously installed.
+
+To use the Sinch Node.js SDK packages, you will need a package manager such as `NPM` (already installed with Node.js) or `yarn`.
+
+To install `yarn` (optional), run the following command:
+
+```bash
+npm install --global yarn
+```
+
+## Configuration
+
+To be able to send requests to the Sinch APIs, you need to have a Sinch account. Please [sign up](https://dashboard.sinch.com/signup) or [log in](https://dashboard.sinch.com/login) if you already have one.
+
+With the credentials found on the Sinch dashboards, you will have to fill the file `.env.template` and **rename it to `.env`**. This file needs to be located at the same place where you will be executing the sample applications.
+
+```properties
+# Credentials for APIs using OAuth2 authentication
+PROJECT_ID=project-id found at https://dashboard.sinch.com/account/access-keys
+KEY_ID=access-key-id found at https://dashboard.sinch.com/account/access-keys
+KEY_SECRET=access-key-secret found at access-key creation time
+```
+
+**Note**: If you prefer using environment variables, the sample app is also supporting them: they take precedence over the value from the `.env` file.
+
+## Execution
+You will find all the scripts in the `package.json` file to run the samples.
+
+### With NPM
+
+```bash
+npm run numbers:app
+```
+
+### With Yarn
+
+```bash
+yarn run numbers:app
+```
+
+## Available flows
+
+### Numbers
+
+This app will try to rent a number or type `LOCAL` and manage it. the following requests will be chained:
+ - the first request will return all the regions where we can rent a number of type `LOCAL`. We will store one of the values from the response.
+ - Now that we have a region, we list all the numbers of type `LOCAL` available for rental in this region.
+ - From the list of available numbers in the response, we select one, and we send another request to rent it
+ - *Alternative*: renting a number can be done in only one step with the `rentAny` method. The application will rent a second number with this method.
+ - Once a number is rented, it becomes an "active" number.
+ - A possibility to check is a number belongs to us, is to request it in the "active" domain
+ - Another possibility is to list our active numbers and check if the numbers we have rented are part of the list. This example illustrates the pagination.
+ - The next request will update some properties of our numbers
+ - Finally, we will release our numbers to not be charged for more than 1 month.
diff --git a/examples/integrated-flows-examples/package.json b/examples/integrated-flows-examples/package.json
new file mode 100644
index 00000000..44130765
--- /dev/null
+++ b/examples/integrated-flows-examples/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "@sinch/integrated-flows-examples",
+ "version": "0.0.0",
+ "author": "Sinch",
+ "private": true,
+ "main": "dist/app.js",
+ "scripts": {
+ "build": "yarn run clean && yarn run compile",
+ "clean": "rimraf dist tsconfig.tsbuildinfo",
+ "compile": "tsc --build --verbose",
+ "numbers:app": "ts-node src/numbers/app.ts"
+ },
+ "dependencies": {
+ "@sinch/sdk-core": "^0.0.0",
+ "@types/node": "^20.8.7",
+ "dotenv": "^16.3.1",
+ "typescript": "^5.2.2"
+ },
+ "devDependencies": {
+ "ts-node": "^10.9.1"
+ }
+}
diff --git a/examples/integrated-flows-examples/src/numbers/app.ts b/examples/integrated-flows-examples/src/numbers/app.ts
new file mode 100644
index 00000000..f7d8234c
--- /dev/null
+++ b/examples/integrated-flows-examples/src/numbers/app.ts
@@ -0,0 +1,258 @@
+import {
+ SinchClient,
+ ActiveNumber,
+ GetActiveNumberRequestData, ListActiveNumbersRequestData,
+ ListAvailableNumbersRequestData,
+ ListAvailableRegionsRequestData,
+ NumberTypeEnum,
+ RegionNumberTypeEnum, ReleaseNumberRequestData, RentAnyNumberRequestData,
+ RentNumberRequestData, UpdateActiveNumberRequestData,
+} from '@sinch/sdk-core';
+require('dotenv').config();
+
+(async() => {
+
+ // Scenario: We need a 'LOCAL' number.
+ // We'll first search for the regions where such option is available
+ // We'll then search for one available number and rent it. We will also rent another number base on pattern search.
+ // We'll then verify they are part of our active numbers, update their configuration and finally release them.
+ // The final step will be to verify the numbers are not listed as active anymore
+
+ const keyId = process.env.KEY_ID || '';
+ const keySecret = process.env.KEY_SECRET || '';
+ const projectId = process.env.PROJECT_ID || '';
+ const sinchClient = new SinchClient({ projectId, keyId, keySecret });
+
+ const regionType: RegionNumberTypeEnum = 'LOCAL';
+ const type: NumberTypeEnum = 'LOCAL';
+
+ console.log('+------------------------------------------------------------------------------+');
+ console.log('| Step 1: List the available regions and store the first one from the response |');
+ console.log('+------------------------------------------------------------------------------+');
+
+ // Build the request data
+ const availableRegionsRequestData: ListAvailableRegionsRequestData = {
+ types: regionType,
+ };
+
+ // Declare the variable holding the response
+ let availableRegionsResponse;
+ try {
+ // Send the HTTP request with the SDK method
+ availableRegionsResponse
+ = await sinchClient.numbers.availableRegions.list(availableRegionsRequestData);
+ } catch (error) {
+ // Catch error if any, log it and stop the program
+ console.error(`ERROR: An error occurred when trying to list the available regions for the type ${regionType}`);
+ throw error;
+ }
+
+ // Check the response contains some data
+ if (!availableRegionsResponse.availableRegions
+ || availableRegionsResponse.availableRegions.length === 0) {
+ console.log(`ERROR: No available regions for the type ${regionType}`);
+ return;
+ }
+ // Store the region code to reuse it in subsequent requests
+ const regionCode: string
+ = availableRegionsResponse.availableRegions[availableRegionsResponse.availableRegions.length-1].regionCode!;
+ console.log(`Region code = ${regionCode}\n`);
+
+ console.log('+-----------------------------------------------+');
+ console.log('| Step 2: List available numbers in this region |');
+ console.log('+-----------------------------------------------+');
+
+ // Build the request data
+ const listAvailableNumbersRequestData: ListAvailableNumbersRequestData = {
+ regionCode,
+ type,
+ };
+
+ // Declare the variable holding the response
+ let availableNumbersResponse;
+ try {
+ // Send the HTTP request with the SDK method
+ availableNumbersResponse
+ = await sinchClient.numbers.availableNumber.list(listAvailableNumbersRequestData);
+ } catch (error) {
+ // Catch error if any, log it and stop the program
+ console.error(`ERROR: An error occurred when trying to list the available numbers for the type ${type}`);
+ throw error;
+ }
+
+ // Check the response contains some data
+ if (!availableNumbersResponse.availableNumbers
+ || availableNumbersResponse.availableNumbers.length === 0) {
+ console.log(`ERROR: No available numbers for the type ${type}`);
+ return;
+ }
+
+ // Store the phone number to reuse it in subsequent requests
+ const phoneNumber1 = availableNumbersResponse.availableNumbers[0].phoneNumber!;
+ console.log(`The number ${phoneNumber1} is available.\n`);
+
+ console.log('+-------------------------------+');
+ console.log('| Step 3: Rent the phone number |');
+ console.log('+-------------------------------+');
+
+ // Build the request data
+ const rentNumberRequestData: RentNumberRequestData = {
+ phoneNumber: phoneNumber1,
+ rentNumberRequestBody: {},
+ };
+
+ // Declare the variable holding the response
+ let rentNumberResponse;
+ try {
+ // Send the HTTP request with the SDK method
+ rentNumberResponse = await sinchClient.numbers.availableNumber.rent(rentNumberRequestData);
+ } catch (error) {
+ // Catch error if any, log it and stop the program
+ console.error(`ERROR: Impossible to rent the number ${phoneNumber1}`);
+ throw error;
+ }
+ console.log(`Number ${phoneNumber1} has been rented. The next charge date is ${rentNumberResponse.nextChargeDate}\n`);
+
+ console.log('+------------------------------------------------------------+');
+ console.log('| Step 2+3 bis: Rent a number directly from a search pattern |');
+ console.log('+------------------------------------------------------------+');
+
+ // Build the request data
+ const rentAnyNumberRequestData: RentAnyNumberRequestData = {
+ rentAnyNumberRequestBody: {
+ regionCode,
+ type,
+ capabilities: ['SMS'],
+ numberPattern: {
+ searchPattern: 'START',
+ pattern: '+1781',
+ },
+ },
+ };
+
+ // Declare the variable holding the response
+ let rentAnyNumberResponse;
+ try {
+ // Send the HTTP request with the SDK method
+ rentAnyNumberResponse = await sinchClient.numbers.availableNumber.rentAny(rentAnyNumberRequestData);
+ } catch (error) {
+ // Catch error if any, log it and stop the program
+ console.error(`ERROR: Impossible to rent a number in the region ${regionCode} of type ${type}`);
+ throw error;
+ }
+ // Store the phone number to reuse it in subsequent requests
+ const phoneNumber2 = rentAnyNumberResponse.phoneNumber!;
+ console.log(`Number ${phoneNumber2} has been rented. The next charge date is ${rentAnyNumberResponse.nextChargeDate}\n`);
+
+ console.log('+-----------------------------------------------------------------------------------------------+');
+ console.log('| Step 4: Check the numbers are part of our active numbers - method 1: give the number in input |');
+ console.log('+-----------------------------------------------------------------------------------------------+');
+
+ // Build the request data
+ const getActiveNumberRequestData: GetActiveNumberRequestData = {
+ phoneNumber: phoneNumber1,
+ };
+
+ // Declare the variable holding the response
+ let getActiveNumberResponse;
+ try {
+ // Send the HTTP request with the SDK method
+ getActiveNumberResponse = await sinchClient.numbers.activeNumber.get(getActiveNumberRequestData);
+ } catch (error) {
+ // Catch error if any, log it and stop the program
+ console.error(`ERROR: Impossible to get details for the number ${phoneNumber1}`);
+ throw error;
+ }
+ console.log(`SUCCESS: The number ${phoneNumber1} is found as an active number. Cost is ${getActiveNumberResponse.money?.amount} ${getActiveNumberResponse.money?.currencyCode}\n`);
+
+ console.log('+----------------------------------------------------------------------------------------------+');
+ console.log('| Step 4: Check the numbers are part of our active numbers - method 2: List all active numbers |');
+ console.log('+----------------------------------------------------------------------------------------------+');
+
+ // Build the request data
+ const listActiveNumbersRequestData: ListActiveNumbersRequestData = {
+ regionCode,
+ type,
+ };
+
+ // The ActiveNumbersResponse is paginated. Let's fetch all the pages using the iterator functionality
+ const activeNumbersList: ActiveNumber[] = [];
+ for await (const activeNumber of sinchClient.numbers.activeNumber.list(listActiveNumbersRequestData)) {
+ activeNumbersList.push(activeNumber);
+ }
+
+ // Check our numbers are part of the response
+ const number1IsListedInActiveNumbers
+ = activeNumbersList.some((activeNumber) => activeNumber.phoneNumber === phoneNumber1);
+ const number2IsListedInActiveNumbers
+ = activeNumbersList.some((activeNumber) => activeNumber.phoneNumber === phoneNumber2);
+ console.log(`The number ${phoneNumber1} is ${number1IsListedInActiveNumbers? '' : 'NOT '}listed in the active numbers`);
+ console.log(`The number ${phoneNumber2} is ${number2IsListedInActiveNumbers? '' : 'NOT '}listed in the active numbers\n`);
+
+ console.log('+---------------------------------+');
+ console.log('| Step 5: Update an active number |');
+ console.log('+---------------------------------+');
+
+ // Build the request data
+ const updateActiveNumberRequestData: UpdateActiveNumberRequestData = {
+ phoneNumber: phoneNumber1,
+ activeNumberRequestBody: {
+ displayName: 'Sample number 1',
+ },
+ };
+
+ // Declare the variable holding the response
+ let updateActiveNumberResponse;
+ try {
+ // Send the HTTP request with the SDK method
+ updateActiveNumberResponse
+ = await sinchClient.numbers.activeNumber.update(updateActiveNumberRequestData);
+ } catch (error) {
+ // Catch error if any, log it and stop the program
+ console.log(`ERROR: Impossible to update the number ${phoneNumber1}`);
+ throw error;
+ }
+
+ console.log(`SUCCESS: The number ${phoneNumber1} has been updated; the display name is '${updateActiveNumberResponse.displayName}'\n`);
+
+ console.log('+---------------------------------------+');
+ console.log('| Step 6: Release the numbers - number1 |');
+ console.log('+---------------------------------------+');
+
+ // Build the request data
+ let releaseActiveNumberRequestData: ReleaseNumberRequestData = {
+ phoneNumber: phoneNumber1,
+ };
+
+ let releaseActiveNumberResponse;
+ try {
+ // Send the HTTP request with the SDK method
+ releaseActiveNumberResponse = await sinchClient.numbers.activeNumber.release(releaseActiveNumberRequestData);
+ } catch (error) {
+ // Catch error if any, log it and stop the program
+ console.error(`ERROR: Impossible to release the number ${phoneNumber1}`);
+ throw error;
+ }
+
+ console.log(`SUCCESS: The number ${phoneNumber1} has been released; it will expire at ${releaseActiveNumberResponse.expireAt}\n`);
+
+ console.log('+-------------------------------------------+');
+ console.log('| Step 6 bis: Release the numbers - number2 |');
+ console.log('+-------------------------------------------+');
+
+ releaseActiveNumberRequestData = {
+ phoneNumber: phoneNumber2,
+ };
+
+ try {
+ // Send the HTTP request with the SDK method
+ releaseActiveNumberResponse = await sinchClient.numbers.activeNumber.release(releaseActiveNumberRequestData);
+ } catch (error) {
+ // Catch error if any, log it and stop the program
+ console.error(`ERROR: Impossible to release the number ${phoneNumber2}`);
+ throw error;
+ }
+
+ console.log(`SUCCESS: The number ${phoneNumber2} has been released; it will expire at ${releaseActiveNumberResponse.expireAt}`);
+
+})();
diff --git a/examples/integrated-flows-examples/tsconfig.json b/examples/integrated-flows-examples/tsconfig.json
new file mode 100644
index 00000000..52f99567
--- /dev/null
+++ b/examples/integrated-flows-examples/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "CommonJS",
+ "moduleResolution": "node",
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "baseUrl": "./",
+ "strict": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "incremental": true,
+ "composite": true,
+ "paths": {
+ "@sinch/sdk-core": ["../../packages/sdk-core"]
+ }
+ }
+}
diff --git a/examples/simple-examples/.env.template b/examples/simple-examples/.env.template
new file mode 100644
index 00000000..8cc5760f
--- /dev/null
+++ b/examples/simple-examples/.env.template
@@ -0,0 +1,19 @@
+# Credentials for APIs using OAuth2 authentication
+SINCH_PROJECT_ID=project-id found at https://dashboard.sinch.com/account/access-keys
+SINCH_KEY_ID=access-key-id found at https://dashboard.sinch.com/account/access-keys
+SINCH_KEY_SECRET=access-key-secret found at access-key creation time
+# Credentials for legacy SMS API usage
+SINCH_SERVICE_PLAN_ID=service-plan-id found at https://dashboard.sinch.com/sms/api/services
+SINCH_API_TOKEN=api-token found at https://dashboard.sinch.com/sms/api/services
+# Application credentials for Verification and Voice APIs
+SINCH_APPLICATION_KEY=application-key found at https://dashboard.sinch.com/verification/apps
+SINCH_APPLICATION_SECRET=application-secret found at https://dashboard.sinch.com/verification/apps
+# Properties to fill according to some API responses
+PHONE_NUMBER=phone-number to fill with one of your numbers rented with the Numbers API
+RECIPIENT_PHONE_NUMBER=phone-number to fill with the number to which you want to send a batch with the SMS API
+BATCH_ID=batch-id to fill with one the batches created with the SMS API
+GROUP_ID=group-id to fill with one of the groups created with the SMS API
+INBOUND_ID=inbound-id to fill with one of the ids found when listing inbound messages with the SMS API
+VERIFICATION_ID=verification-id to fill with the verification started with the Verification API
+VERIFICATION_IDENTITY=verification-identity to fill with the identity of the user
+VERIFICATION_REFERENCE=verification-reference to add when starting a verification or getting its status
diff --git a/examples/simple-examples/.gitignore b/examples/simple-examples/.gitignore
new file mode 100644
index 00000000..2ff5437a
--- /dev/null
+++ b/examples/simple-examples/.gitignore
@@ -0,0 +1,8 @@
+# compiled output
+/dist
+/node_modules
+
+# OS
+.DS_Store
+
+.env
diff --git a/examples/simple-examples/README.md b/examples/simple-examples/README.md
new file mode 100644
index 00000000..fcab61b0
--- /dev/null
+++ b/examples/simple-examples/README.md
@@ -0,0 +1,114 @@
+# Simple examples with the Sinch Node.js SDK
+
+This directory contains some code samples to illustrate how to use the services supported in the Sinch Node.js SDK.
+
+## Prerequisites
+
+Before trying to run a sample, make sure you have Node.js installed: please download and install the LTS version from [nodejs.org](https://nodejs.org).
+
+Once installed, check you can run node with the following command:
+
+```bash
+node --version
+```
+
+You should see a result such as `v20.10.0`, matching the LTS you have downloaded or the version you had previously installed.
+
+To use the Sinch Node.js SDK packages, you will need a package manager such as `NPM` (already installed with Node.js) or `yarn`.
+
+To install `yarn` (optional), run the following command:
+
+```bash
+npm install --global yarn
+```
+
+## Configuration
+
+To be able to send requests to the Sinch APIs, you need to have a Sinch account. Please [sign up](https://dashboard.sinch.com/signup) or [log in](https://dashboard.sinch.com/login) if you already have one.
+
+With the credentials found on the Sinch dashboards, you will have to fill the file `.env.template` and **rename it to `.env`**. This file needs to be located at the same place where you will be executing the sample files.
+
+```properties
+# Credentials for APIs using OAuth2 authentication
+SINCH_PROJECT_ID=project-id found at https://dashboard.sinch.com/account/access-keys
+SINCH_KEY_ID=access-key-id found at https://dashboard.sinch.com/account/access-keys
+SINCH_KEY_SECRET=access-key-secret found at access-key creation time
+# Credentials for legacy SMS API usage
+SINCH_SERVICE_PLAN_ID=service-plan-id found at https://dashboard.sinch.com/sms/api/services
+SINCH_API_TOKEN=api-token found at https://dashboard.sinch.com/sms/api/services
+# Application credentials for Verification and Voice APIs
+SINCH_APPLICATION_KEY=application-key found at https://dashboard.sinch.com/verification/apps
+SINCH_APPLICATION_SECRET=application-secret found at https://dashboard.sinch.com/verification/apps
+# Properties to fill according to some API responses
+PHONE_NUMBER=phone-number to fill with one of your numbers rented with the Numbers API
+RECIPIENT_PHONE_NUMBER=phone-number to fill with the number to which you want to send a batch with the SMS API
+BATCH_ID=batch-id to fill with one the batches created with the SMS API
+GROUP_ID=group-id to fill with one of the groups created with the SMS API
+INBOUND_ID=inbound-id to fill with one of the ids found when listing inbound messages with the SMS API
+VERIFICATION_ID=verification-id to fill with the verification started with the Verification API
+VERIFICATION_IDENTITY=verification-identity to fill with the identity of the user
+VERIFICATION_REFERENCE=verification-reference to add when starting a verification or getting its status
+VERIFICATION_CODE=verification-code received for a verification via SMS or callout
+VERIFICATION_CLI=verification-cli received for a verification via flashCall
+```
+
+**Note**: If you prefer using environment variables, the sample app is also supporting them: they take precedence over the value from the `.env` file.
+
+## Execution
+You will find all the scripts in the `package.json` file to run the samples.
+
+### With NPM
+
+```bash
+npm run numbers:regions:list
+```
+
+### With Yarn
+
+```bash
+yarn run numbers:regions:list
+```
+
+**Note**: You can add the option `pretty` at the end of the command to display a processed output from the raw JSON response (e.g. `yarn run numbers:regions:list pretty`)
+
+## Available sample applications
+
+| Domain | Service | Sample application name and location | Required parameters |
+|--------------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
+| Numbers | Regions | [./src/numbers/regions/list.ts](./src/numbers/regions/list.ts) | |
+| | Available | [./src/numbers/available/list.ts](./src/numbers/available/list.ts) | |
+| | | [./src/numbers/available/checkAvailability.ts](./src/numbers/available/checkAvailability.ts) | `PHONE_NUMBER` |
+| | | [./src/numbers/available/rent.ts](./src/numbers/available/rent.ts) | `PHONE_NUMBER` |
+| | | [./src/numbers/available/rentAny.ts](./src/numbers/available/rentAny.ts) | |
+| | Active | [./src/numbers/active/list.ts](./src/numbers/active/list.ts) | |
+| | | [./src/numbers/active/get.ts](./src/numbers/active/get.ts) | `PHONE_NUMBER` |
+| | | [./src/numbers/active/update.ts](./src/numbers/active/update.ts) | `PHONE_NUMBER` |
+| | | [./src/numbers/active/release.ts](./src/numbers/active/release.ts) | `PHONE_NUMBER` |
+| | Callback | [./src/numbers/callback/get.ts](./src/numbers/callback/get.ts) | |
+| | | [./src/numbers/callback/update.ts](./src/numbers/callback/update.ts) | |
+| SMS | Groups | [./src/sms/groups/list/list.ts](./src/sms/groups/list/list.ts) | |
+| | | [./src/sms/groups/create/create.ts](./src/sms/groups/create/create.ts) | |
+| | | [./src/sms/groups/get/get.ts](./src/sms/groups/get/get.ts) | `GROUP_ID` |
+| | | [./src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts](./src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts) | `GROUP_ID` |
+| | | [./src/sms/groups/replace/replace.ts](./src/sms/groups/replace/replace.ts) | `GROUP_ID` |
+| | | [./src/sms/groups/update/update.ts](./src/sms/groups/update/update.ts) | `GROUP_ID` |
+| | | [./src/sms/groups/delete/delete.ts](./src/sms/groups/delete/delete.ts) | `GROUP_ID` |
+| | Batches | [./src/sms/batches/send.ts](./src/sms/batches/send.ts) | `RECIPIENT_PHONE_NUMBER` |
+| | | [./src/sms/batches/list.ts](./src/sms/batches/list.ts) | |
+| | | [./src/sms/batches/dry-run.ts](./src/sms/batches/dry-run.ts) | `RECIPIENT_PHONE_NUMBER` |
+| | | [./src/sms/batches/get.ts](./src/sms/batches/get.ts) | `BATCH_ID` |
+| | | [./src/sms/batches/update.ts](./src/sms/batches/update.ts) | `BATCH_ID` |
+| | | [./src/sms/batches/replace.ts](./src/sms/batches/replace.ts) | `BATCH_ID` |
+| | | [./src/sms/batches/cancel.ts](./src/sms/batches/cancel.ts) | `BATCH_ID` |
+| | | [./src/sms/batches/delivery-feedback.ts](./src/sms/batches/delivery-feedback.ts) | `BATCH_ID` |
+| | DeliveryReports | [./src/sms/delivery-reports/list.ts](./src/sms/delivery-reports/list.ts) | |
+| | | [./src/sms/delivery-reports/getByBatchId.ts](./src/sms/delivery-reports/getByBatchId.ts) | `BATCH_ID` |
+| | | [./src/sms/delivery-reports/getByPhoneNumber.ts](./src/sms/delivery-reports/getByPhoneNumber.ts) | `BATCH_ID`, `RECIPIENT_PHONE_NUMBER` |
+| | Inbounds | [./src/sms/inbounds/list.ts](./src/sms/inbounds/list.ts) | |
+| | | [./src/sms/inbounds/get.ts](./src/sms/inbounds/get.ts) | `INBOUND_ID` |
+| Verification | Verifications | [./src/verification/verifications/start.ts](./src/verification/verifications/start.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_REFERENCE` |
+| | | [./src/verification/verifications/report-with-id_.ts](./src/verification/verifications/report-with-id.ts) | `VERIFICATION_ID` + `VERIFICATION_CODE` or `VERIFICATION_CLI` (flashCall) |
+| | | [./src/verification/verifications/report-with-identity.ts](./src/verification/verifications/report-with-identity.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_CODE` or `VERIFICATION_CLI` (flashCall) |
+| | Verification-status | [./src/verification/verification-status/verification-by-id.ts](./src/verification/verification-status/verification-by-id.ts) | `VERIFICATION_ID` |
+| | | [./src/verification/verification-status/verification-by-identity.ts](./src/verification/verification-status/verification-by-identity.ts) | `VERIFICATION_IDENTITY` |
+| | | [./src/verification/verification-status/verification-by-reference.ts](./src/verification/verification-status/verification-by-reference.ts) | `VERIFICATION_REFERENCE` |
diff --git a/examples/simple-examples/package.json b/examples/simple-examples/package.json
new file mode 100644
index 00000000..d3946f81
--- /dev/null
+++ b/examples/simple-examples/package.json
@@ -0,0 +1,61 @@
+{
+ "name": "@sinch/simple-examples",
+ "version": "0.0.0",
+ "author": "Sinch",
+ "private": true,
+ "main": "dist/app.js",
+ "scripts": {
+ "build": "yarn run clean && yarn run compile",
+ "clean": "rimraf dist tsconfig.tsbuildinfo",
+ "compile": "tsc --build --verbose",
+ "numbers:regions:list": "ts-node src/numbers/regions/list.ts",
+ "numbers:available:list": "ts-node src/numbers/available/list.ts",
+ "numbers:available:checkAvailability": "ts-node src/numbers/available/checkAvailability.ts",
+ "numbers:available:rent": "ts-node src/numbers/available/rent.ts",
+ "numbers:available:rentAny": "ts-node src/numbers/available/rentAny.ts",
+ "numbers:active:list": "ts-node src/numbers/active/list.ts",
+ "numbers:active:get": "ts-node src/numbers/active/get.ts",
+ "numbers:active:update": "ts-node src/numbers/active/update.ts",
+ "numbers:active:release": "ts-node src/numbers/active/release.ts",
+ "numbers:callback:get": "ts-node src/numbers/callback/get.ts",
+ "numbers:callback:update": "ts-node src/numbers/callback/update.ts",
+ "sms:groups:list": "ts-node src/sms/groups/list/list.sinch-client.ts",
+ "sms:groups:create": "ts-node src/sms/groups/create/create.sinch-client.ts",
+ "sms:groups:get": "ts-node src/sms/groups/get/get.sinch-client.ts",
+ "sms:groups:getPhoneNumbers": "ts-node src/sms/groups/getPhoneNumbers/getPhoneNumbers.sinch-client.ts",
+ "sms:groups:replace": "ts-node src/sms/groups/replace/replace.sinch-client.ts",
+ "sms:groups:update": "ts-node src/sms/groups/update/update.sinch-client.ts",
+ "sms:groups:delete": "ts-node src/sms/groups/delete/delete.sinch-client.ts",
+ "sms:batches:send": "ts-node src/sms/batches/send.ts",
+ "sms:batches:list": "ts-node src/sms/batches/list.ts",
+ "sms:batches:dry-run": "ts-node src/sms/batches/dry-run.ts",
+ "sms:batches:get": "ts-node src/sms/batches/get.ts",
+ "sms:batches:update": "ts-node src/sms/batches/update.ts",
+ "sms:batches:replace": "ts-node src/sms/batches/replace.ts",
+ "sms:batches:cancel": "ts-node src/sms/batches/cancel.ts",
+ "sms:batches:delivery-feedback": "ts-node src/sms/batches/delivery-feedback.ts",
+ "sms:delivery-reports:list": "ts-node src/sms/delivery-reports/list.ts",
+ "sms:delivery-reports:getByBatchId": "ts-node src/sms/delivery-reports/getByBatchId.ts",
+ "sms:delivery-reports:getByPhoneNumber": "ts-node src/sms/delivery-reports/getByPhoneNumber.ts",
+ "sms:inbounds:list": "ts-node src/sms/inbounds/list.ts",
+ "sms:inbounds:get": "ts-node src/sms/inbounds/get.ts",
+ "verification:verifications:start-sms": "ts-node src/verification/verifications/start-sms.ts",
+ "verification:verifications:start-callout": "ts-node src/verification/verifications/start-callout.ts",
+ "verification:verifications:start-flashcall": "ts-node src/verification/verifications/start-flashcall.ts",
+ "verification:verifications:start-seamless": "ts-node src/verification/verifications/start-seamless.ts",
+ "verification:verifications:report-with-id": "ts-node src/verification/verifications/report-with-id.ts",
+ "verification:verifications:report-with-identity": "ts-node src/verification/verifications/report-with-identity.ts",
+ "verification:verification-status:verification-by-id": "ts-node src/verification/verification-status/verification-by-id.ts",
+ "verification:verification-status:verification-by-identity": "ts-node src/verification/verification-status/verification-by-identity.ts",
+ "verification:verification-status:verification-by-reference": "ts-node src/verification/verification-status/verification-by-reference.ts"
+ },
+ "dependencies": {
+ "@sinch/sdk-core": "^0.0.0",
+ "@types/node": "^20.8.7",
+ "dotenv": "^16.3.1",
+ "typescript": "^5.2.2"
+ },
+ "devDependencies": {
+ "ts-node": "^10.9.1"
+ }
+}
diff --git a/examples/simple-examples/src/config.ts b/examples/simple-examples/src/config.ts
new file mode 100644
index 00000000..8734f53f
--- /dev/null
+++ b/examples/simple-examples/src/config.ts
@@ -0,0 +1,86 @@
+import { getRegion, SinchClient, Region } from '@sinch/sdk-core';
+require('dotenv').config();
+
+export const initClient = () => {
+ const keyId = process.env.SINCH_KEY_ID || '';
+ const keySecret = process.env.SINCH_KEY_SECRET || '';
+ const projectId = process.env.SINCH_PROJECT_ID || '';
+ return new SinchClient({ projectId, keyId, keySecret });
+};
+
+export const initSmsClient = () => {
+ const servicePlanId = process.env.SINCH_SERVICE_PLAN_ID || '';
+ const apiToken = process.env.SINCH_API_TOKEN || '';
+ const region = getRegion(process.env.SINCH_PROJECT_ID) || Region.UNITED_STATES;
+ return new SinchClient({ servicePlanId, apiToken, region });
+};
+
+export const initVerificationClient = () => {
+ const applicationKey = process.env.SINCH_APPLICATION_KEY || '';
+ const applicationSecret = process.env.SINCH_APPLICATION_SECRET || '';
+ return new SinchClient({ applicationKey, applicationSecret });
+};
+
+export const getPrintFormat = (args: string[]): 'pretty' | 'full' => {
+ const params = args.slice(2);
+ if (params.length > 0 && params[0] === 'pretty') {
+ return 'pretty';
+ }
+ return 'full';
+};
+
+export const getPhoneNumberFromConfig = (): string | undefined => {
+ return process.env.PHONE_NUMBER;
+};
+
+export const getServicePlanIdFromConfig = (): string | undefined => {
+ return process.env.SERVICE_PLAN_ID;
+};
+
+export const getApplicationKeyFromConfig = (): string | undefined => {
+ return process.env.APPLICATION_KEY;
+};
+
+export const getGroupIdFromConfig = (): string | undefined => {
+ return process.env.GROUP_ID;
+};
+
+export const getRecipientPhoneNumberFromConfig = (): string | undefined => {
+ return process.env.RECIPIENT_PHONE_NUMBER;
+};
+
+export const getBatchIdFromConfig = (): string | undefined => {
+ return process.env.BATCH_ID;
+};
+
+export const getInboundIdFromConfig = (): string | undefined => {
+ return process.env.INBOUND_ID;
+};
+
+export const getHmacSecretFromConfig = (): string | undefined => {
+ return process.env.HMAC_SECRET;
+};
+
+export const getVerificationIdFromConfig = (): string | undefined => {
+ return process.env.VERIFICATION_ID;
+};
+
+export const getVerificationIdentityFromConfig = (): string | undefined => {
+ return process.env.VERIFICATION_IDENTITY;
+};
+
+export const getVerificationReferenceFromConfig = (): string | undefined => {
+ return process.env.VERIFICATION_REFERENCE;
+};
+
+export const getVerificationCodeFromConfig = (): string | undefined => {
+ return process.env.VERIFICATION_CODE;
+};
+
+export const getVerificationCliFromConfig = (): string | undefined => {
+ return process.env.VERIFICATION_CLI;
+};
+
+export const printFullResponse = (response: any) => {
+ console.log(JSON.stringify(response, null, 2));
+};
diff --git a/examples/simple-examples/src/numbers/active/get.ts b/examples/simple-examples/src/numbers/active/get.ts
new file mode 100644
index 00000000..471a6002
--- /dev/null
+++ b/examples/simple-examples/src/numbers/active/get.ts
@@ -0,0 +1,35 @@
+import { getPhoneNumberFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config';
+import { GetActiveNumberRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('*********************************');
+ console.log('* NumberService_GetActiveNumber *');
+ console.log('*********************************');
+
+ const phoneNumber = getPhoneNumberFromConfig();
+ if (!phoneNumber) {
+ throw new Error('No phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/numbers/active/get.ts file');
+ }
+
+ const requestData: GetActiveNumberRequestData= {
+ phoneNumber,
+ };
+
+ const sinchClient = initClient();
+ let response;
+ try {
+ response = await sinchClient.numbers.activeNumber.get(requestData);
+ } catch (error) {
+ console.error(`ERROR: The phone number ${requestData.phoneNumber} is not active`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The phone number ${response.phoneNumber} is part of your active numbers.\n Display name = ${response.displayName}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/active/list.ts b/examples/simple-examples/src/numbers/active/list.ts
new file mode 100644
index 00000000..aed4151b
--- /dev/null
+++ b/examples/simple-examples/src/numbers/active/list.ts
@@ -0,0 +1,70 @@
+import { getPrintFormat, initClient, printFullResponse } from '../../config';
+import { ActiveNumber, ListActiveNumbersRequestData, PageResult } from '@sinch/sdk-core';
+
+const populateActiveNumbersList = (
+ activeNumbersPage: PageResult,
+ activeNumbersList: ActiveNumber[],
+ phoneNumbersList: (string | undefined)[],
+) => {
+ activeNumbersPage.data?.map((activeNumber: ActiveNumber) => {
+ activeNumbersList.push(activeNumber);
+ phoneNumbersList.push(activeNumber.phoneNumber);
+ });
+};
+
+
+(async () => {
+ console.log('***********************************');
+ console.log('* NumberService_ListActiveNumbers *');
+ console.log('***********************************');
+
+ const requestData: ListActiveNumbersRequestData = {
+ regionCode: 'US',
+ type: 'LOCAL',
+ pageSize: 2,
+ };
+
+ const sinchClient = initClient();
+
+ // ----------------------------------------------
+ // Method 1: Fetch the data page by page manually
+ // ----------------------------------------------
+ let response = await sinchClient.numbers.activeNumber.list(requestData);
+
+ const activeNumbersList: ActiveNumber[] = [];
+ const phoneNumbersList: (string | undefined)[] = [];
+
+ // Loop on all the pages to get all the active numbers
+ let reachedEndOfPages = false;
+ while (!reachedEndOfPages) {
+ populateActiveNumbersList(response, activeNumbersList, phoneNumbersList);
+ if (response.hasNextPage) {
+ response = await response.nextPage();
+ } else {
+ reachedEndOfPages = true;
+ }
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(phoneNumbersList.length > 0
+ ? 'List of active numbers: ' + JSON.stringify(phoneNumbersList, null, 2)
+ : 'Sorry, no active numbers were found.');
+ } else {
+ printFullResponse(activeNumbersList);
+ }
+
+ // ---------------------------------------------------------------------
+ // Method 2: Use the iterator and fetch data on more pages automatically
+ // ---------------------------------------------------------------------
+ for await (const activeNumber of sinchClient.numbers.activeNumber.list(requestData)) {
+ if (printFormat === 'pretty') {
+ console.log(activeNumber.phoneNumber);
+ } else {
+ console.log(activeNumber);
+ }
+ }
+
+})();
+
diff --git a/examples/simple-examples/src/numbers/active/release.ts b/examples/simple-examples/src/numbers/active/release.ts
new file mode 100644
index 00000000..9ef23c8d
--- /dev/null
+++ b/examples/simple-examples/src/numbers/active/release.ts
@@ -0,0 +1,29 @@
+import { getPhoneNumberFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config';
+import { ReleaseNumberRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('*******************************');
+ console.log('* NumberService_ReleaseNumber *');
+ console.log('*******************************');
+
+ const phoneNumber = getPhoneNumberFromConfig();
+ if (!phoneNumber) {
+ throw new Error('No phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/numbers/active/release.ts file');
+ }
+
+ const requestData: ReleaseNumberRequestData= {
+ phoneNumber,
+ };
+
+ const sinchClient = initClient();
+ const response = await sinchClient.numbers.activeNumber.release(requestData);
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The phone number ${response.phoneNumber} will be released at ${response.expireAt}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/active/update.ts b/examples/simple-examples/src/numbers/active/update.ts
new file mode 100644
index 00000000..d22aa12e
--- /dev/null
+++ b/examples/simple-examples/src/numbers/active/update.ts
@@ -0,0 +1,47 @@
+import {
+ getPhoneNumberFromConfig,
+ getPrintFormat,
+ getServicePlanIdFromConfig,
+ initClient,
+ printFullResponse,
+} from '../../config';
+import { UpdateActiveNumberRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('************************************');
+ console.log('* NumberService_UpdateActiveNumber *');
+ console.log('************************************');
+
+ const phoneNumber = getPhoneNumberFromConfig();
+ if (!phoneNumber) {
+ throw new Error('No phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/numbers/active/update.ts file');
+ }
+
+ const servicePlanId = getServicePlanIdFromConfig();
+ if (!servicePlanId) {
+ throw new Error('No servicePlanId has been provided. '
+ + 'Please update your .env file or edit the ./src/numbers/active/update.ts file');
+ }
+
+ const requestData: UpdateActiveNumberRequestData= {
+ phoneNumber,
+ activeNumberRequestBody: {
+ displayName: 'New display name updated with the Sinch Node.js SDK',
+ smsConfiguration: {
+ servicePlanId,
+ },
+ },
+ };
+
+ const sinchClient = initClient();
+ const response = await sinchClient.numbers.activeNumber.update(requestData);
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The phone number ${response.phoneNumber} has been updated. The servicePlanId is ${response.smsConfiguration?.servicePlanId}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/available/checkAvailability.ts b/examples/simple-examples/src/numbers/available/checkAvailability.ts
new file mode 100644
index 00000000..4c2e1562
--- /dev/null
+++ b/examples/simple-examples/src/numbers/available/checkAvailability.ts
@@ -0,0 +1,36 @@
+import { getPhoneNumberFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config';
+import { GetAvailableNumberRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('************************************');
+ console.log('* NumberService_GetAvailableNumber *');
+ console.log('************************************');
+
+ // Use the phone number from the .env file
+ const phoneNumber = getPhoneNumberFromConfig();
+ if (!phoneNumber) {
+ throw new Error('No phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/numbers/available/checkAvailability.ts file');
+ }
+
+ const requestData: GetAvailableNumberRequestData= {
+ phoneNumber,
+ };
+
+ const sinchClient = initClient();
+ let response;
+ try {
+ response = await sinchClient.numbers.availableNumber.checkAvailability(requestData);
+ } catch (error) {
+ console.error(`ERROR: the phone number ${requestData.phoneNumber} is not available`);
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ const prettyResponse = response?.phoneNumber;
+ console.log(prettyResponse);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/available/list.ts b/examples/simple-examples/src/numbers/available/list.ts
new file mode 100644
index 00000000..2ca680a4
--- /dev/null
+++ b/examples/simple-examples/src/numbers/available/list.ts
@@ -0,0 +1,26 @@
+import { getPrintFormat, initClient, printFullResponse } from '../../config';
+import { ListAvailableNumbersRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('**************************************');
+ console.log('* NumberService_ListAvailableNumbers *');
+ console.log('**************************************');
+
+ const requestData: ListAvailableNumbersRequestData= {
+ regionCode: 'US',
+ type: 'LOCAL',
+ };
+
+ const sinchClient = initClient();
+ const response = await sinchClient.numbers.availableNumber.list(requestData);
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(response.availableNumbers
+ ? JSON.stringify(response.availableNumbers.map((availableNumber) => availableNumber.phoneNumber))
+ : 'Sorry, no numbers are available.');
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/available/rent.ts b/examples/simple-examples/src/numbers/available/rent.ts
new file mode 100644
index 00000000..5a2959a8
--- /dev/null
+++ b/examples/simple-examples/src/numbers/available/rent.ts
@@ -0,0 +1,56 @@
+import {
+ getApplicationKeyFromConfig,
+ getPhoneNumberFromConfig,
+ getPrintFormat,
+ getServicePlanIdFromConfig,
+ initClient,
+ printFullResponse,
+} from '../../config';
+import {
+ RentNumberRequestData,
+} from '@sinch/sdk-core';
+import { RentNumberRequest } from '@sinch/numbers/src';
+
+(async () => {
+ console.log('****************************');
+ console.log('* NumberService_RentNumber *');
+ console.log('****************************');
+
+ // Use the phone number from the .env file
+ const phoneNumber = getPhoneNumberFromConfig();
+ if (!phoneNumber) {
+ throw new Error('No phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/numbers/available/rent.ts file');
+ }
+
+ const servicePlanId = getServicePlanIdFromConfig()
+ const appId = getApplicationKeyFromConfig();
+
+ let rentNumberRequest: RentNumberRequest = {
+ smsConfiguration: servicePlanId ? { servicePlanId } : undefined,
+ voiceConfiguration: appId ? { appId } : undefined,
+ };
+
+ if (!rentNumberRequest.smsConfiguration && !rentNumberRequest.voiceConfiguration) {
+ rentNumberRequest = {};
+ console.error('Warning: no configuration has been provided for sms and voice configuration.'
+ + 'You may want to check the value of "SERVICE_PLAN_ID" and "APPLICATION_KEY" in the .env file');
+ }
+
+ const requestData: RentNumberRequestData = {
+ phoneNumber,
+ rentNumberRequestBody: rentNumberRequest,
+ };
+
+ const sinchClient = initClient();
+ const response = await sinchClient.numbers.availableNumber.rent(requestData);
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ const prettyResponse = response.phoneNumber;
+ console.log(JSON.stringify(prettyResponse, null, 2));
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/available/rentAny.ts b/examples/simple-examples/src/numbers/available/rentAny.ts
new file mode 100644
index 00000000..fe9517c4
--- /dev/null
+++ b/examples/simple-examples/src/numbers/available/rentAny.ts
@@ -0,0 +1,58 @@
+import {
+ getApplicationKeyFromConfig,
+ getPrintFormat,
+ getServicePlanIdFromConfig,
+ initClient,
+ printFullResponse,
+} from '../../config';
+import {
+ RentAnyNumberRequest,
+ RentAnyNumberRequestData,
+} from '@sinch/sdk-core';
+
+(async () => {
+ console.log('*******************************');
+ console.log('* NumberService_RentAnyNumber *');
+ console.log('*******************************');
+
+ const servicePlanId = getServicePlanIdFromConfig();
+ const appId = getApplicationKeyFromConfig();
+
+ if (!servicePlanId && !appId) {
+ console.error('Warning: no configuration has been provided for sms and voice configuration.'
+ + 'You may want to check the value of "SERVICE_PLAN_ID" and "APPLICATION_KEY" in the .env file');
+ }
+
+ const rentAnyNumberRequest: RentAnyNumberRequest = {
+ regionCode: 'US',
+ type: 'LOCAL',
+ numberPattern: {
+ searchPattern: 'START',
+ pattern: '+1781',
+ },
+ };
+
+ if (servicePlanId) {
+ rentAnyNumberRequest.smsConfiguration = { servicePlanId };
+ }
+
+ if (appId) {
+ rentAnyNumberRequest.voiceConfiguration = { appId };
+ }
+
+ const requestData: RentAnyNumberRequestData = {
+ rentAnyNumberRequestBody: rentAnyNumberRequest,
+ };
+
+ const sinchClient = initClient();
+ const response = await sinchClient.numbers.availableNumber.rentAny(requestData);
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ const prettyResponse = response.phoneNumber;
+ console.log(JSON.stringify(prettyResponse, null, 2));
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/callback/get.ts b/examples/simple-examples/src/numbers/callback/get.ts
new file mode 100644
index 00000000..381349b0
--- /dev/null
+++ b/examples/simple-examples/src/numbers/callback/get.ts
@@ -0,0 +1,22 @@
+import { GetCallbackConfigurationRequestData } from '@sinch/sdk-core';
+import { getPrintFormat, initClient, printFullResponse } from '../../config';
+
+(async () => {
+ console.log('****************************');
+ console.log('* GetCallbackConfiguration *');
+ console.log('****************************');
+
+ const requestData: GetCallbackConfigurationRequestData = {};
+
+ const sinchClient = initClient();
+ const response = await sinchClient.numbers.callbackConfiguration.get(requestData);
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ const prettyResponse = response.hmacSecret;
+ console.log(JSON.stringify(prettyResponse, null, 2));
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/callback/update.ts b/examples/simple-examples/src/numbers/callback/update.ts
new file mode 100644
index 00000000..3dc02f88
--- /dev/null
+++ b/examples/simple-examples/src/numbers/callback/update.ts
@@ -0,0 +1,33 @@
+import { UpdateCallbackConfigurationRequestData } from '@sinch/sdk-core';
+import { getHmacSecretFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config';
+import * as process from 'process';
+
+(async () => {
+ console.log('*******************************');
+ console.log('* UpdateCallbackConfiguration *');
+ console.log('*******************************');
+
+ const hmacSecret = getHmacSecretFromConfig();
+ if (!hmacSecret) {
+ console.log('No HMAC secret has been provided. '
+ + 'Please update your .env file or edit the ./src/numbers/callback/update.ts file');
+ }
+
+ const requestData: UpdateCallbackConfigurationRequestData = {
+ callbackConfigurationUpdateRequestBody: {
+ hmacSecret,
+ },
+ };
+
+ const sinchClient = initClient();
+ const response = await sinchClient.numbers.callbackConfiguration.update(requestData);
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ const prettyResponse = response.hmacSecret;
+ console.log(JSON.stringify(prettyResponse, null, 2));
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/numbers/regions/list.ts b/examples/simple-examples/src/numbers/regions/list.ts
new file mode 100644
index 00000000..a34d78d1
--- /dev/null
+++ b/examples/simple-examples/src/numbers/regions/list.ts
@@ -0,0 +1,26 @@
+import { ListAvailableRegionsRequestData } from '@sinch/sdk-core';
+import { getPrintFormat, initClient, printFullResponse } from '../../config';
+
+(async () => {
+ console.log('**************************************');
+ console.log('* NumberService_ListAvailableRegions *');
+ console.log('**************************************');
+
+ const requestData: ListAvailableRegionsRequestData = {
+ types: 'LOCAL',
+ };
+
+ const sinchClient = initClient();
+ const response = await sinchClient.numbers.availableRegions.list(requestData);
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(response.availableRegions
+ ? response.availableRegions.map((region) => region.regionCode)
+ : 'No regions were found');
+ } else {
+ printFullResponse(response);
+ }
+
+})();
diff --git a/examples/simple-examples/src/sms/batches/cancel.ts b/examples/simple-examples/src/sms/batches/cancel.ts
new file mode 100644
index 00000000..5c1d3ade
--- /dev/null
+++ b/examples/simple-examples/src/sms/batches/cancel.ts
@@ -0,0 +1,35 @@
+import { getBatchIdFromConfig, getPrintFormat, initSmsClient, printFullResponse } from '../../config';
+import { CancelBatchMessageRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('**********************');
+ console.log('* CancelBatchMessage *');
+ console.log('**********************');
+
+ const batchIdInTheFuture = getBatchIdFromConfig();
+ if (!batchIdInTheFuture) {
+ throw new Error('No batch id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/cancel.ts file');
+ }
+
+ const requestData: CancelBatchMessageRequestData= {
+ batch_id: batchIdInTheFuture,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.batches.cancel(requestData);
+ } catch (error) {
+ console.error(`ERROR: The batch could not be canceled`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The batch has been canceled successfully. Here is the boolean 'canceled': ${response.canceled}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/sms/batches/delivery-feedback.ts b/examples/simple-examples/src/sms/batches/delivery-feedback.ts
new file mode 100644
index 00000000..eb54a29a
--- /dev/null
+++ b/examples/simple-examples/src/sms/batches/delivery-feedback.ts
@@ -0,0 +1,41 @@
+import { getBatchIdFromConfig, getRecipientPhoneNumberFromConfig, initSmsClient } from '../../config';
+import { DeliveryFeedbackRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('********************');
+ console.log('* deliveryFeedback *');
+ console.log('********************');
+
+ const batchIdInTheFuture = getBatchIdFromConfig();
+ if (!batchIdInTheFuture) {
+ throw new Error('No batch id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/delivery-feedback.ts file');
+ }
+
+ const recipientPhoneNumber = getRecipientPhoneNumberFromConfig();
+ if (!recipientPhoneNumber) {
+ throw new Error('No recipient phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/delivery-feedback.ts file');
+ }
+
+ const requestData: DeliveryFeedbackRequestData= {
+ batch_id: batchIdInTheFuture,
+ deliveryFeedbackRequestBody: {
+ recipients: [
+ recipientPhoneNumber,
+ ],
+ },
+ };
+
+ const sinchClient = initSmsClient();
+
+ try {
+ await sinchClient.sms.batches.sendDeliveryFeedback(requestData);
+ } catch (error) {
+ console.error(`ERROR: The delivery feedback could not be sent.`);
+ throw error;
+ }
+
+ console.log(`Delivery feedback for batch ID ${requestData.batch_id} has been sent!`);
+
+})();
diff --git a/examples/simple-examples/src/sms/batches/dry-run.ts b/examples/simple-examples/src/sms/batches/dry-run.ts
new file mode 100644
index 00000000..00ea2fc7
--- /dev/null
+++ b/examples/simple-examples/src/sms/batches/dry-run.ts
@@ -0,0 +1,62 @@
+import {
+ getPhoneNumberFromConfig,
+ getPrintFormat,
+ getRecipientPhoneNumberFromConfig,
+ initSmsClient,
+ printFullResponse,
+} from '../../config';
+import { DryRunRequestData, TextRequest } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('***********');
+ console.log('* Dry_Run *');
+ console.log('***********');
+
+ const recipientPhoneNumber = getRecipientPhoneNumberFromConfig();
+ if (!recipientPhoneNumber) {
+ throw new Error('No recipient phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/dry-run.ts file');
+ }
+
+ const senderPhoneNumber = getPhoneNumberFromConfig();
+ if (!senderPhoneNumber) {
+ throw new Error('No sender phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/dry-run.ts file');
+ }
+
+ const requestData: DryRunRequestData= {
+ dryRunRequestBody: {
+ to: [
+ recipientPhoneNumber,
+ ],
+ from: senderPhoneNumber,
+ parameters: {
+ name: {
+ [recipientPhoneNumber]: 'John',
+ default: 'there',
+ },
+ },
+ body: 'Hi ${name}!',
+ delivery_report: 'none',
+ type: 'mt_text',
+ } as TextRequest,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.batches.dryRun(requestData);
+ } catch (error) {
+ console.error(`ERROR: The dry run couldn't be performed`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The dry run was successfully performed.
+ The batch wil send ${response.number_of_messages} messages to ${response.number_of_recipients} recipients`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/sms/batches/get.ts b/examples/simple-examples/src/sms/batches/get.ts
new file mode 100644
index 00000000..644f8efd
--- /dev/null
+++ b/examples/simple-examples/src/sms/batches/get.ts
@@ -0,0 +1,35 @@
+import { getPrintFormat, getBatchIdFromConfig, initSmsClient, printFullResponse } from '../../config';
+import { GetBatchMessageRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('*******************');
+ console.log('* GetBatchMessage *');
+ console.log('*******************');
+
+ const batchId = getBatchIdFromConfig();
+ if (!batchId) {
+ throw new Error('No batch id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/get.ts file');
+ }
+
+ const requestData: GetBatchMessageRequestData= {
+ batch_id: batchId,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.batches.get(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to retrieve the batch ${requestData.batch_id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Batch ID: ${response.id} - Type: ${response.type} - From: ${response.from}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/sms/batches/list.ts b/examples/simple-examples/src/sms/batches/list.ts
new file mode 100644
index 00000000..4b4ed1f5
--- /dev/null
+++ b/examples/simple-examples/src/sms/batches/list.ts
@@ -0,0 +1,70 @@
+import { getPrintFormat, initSmsClient, printFullResponse } from '../../config';
+import { ApiBatchListBatchesInner, ListBatchesRequestData, PageResult } from '@sinch/sdk-core';
+
+const populateBatchesList = (
+ batchListPage: PageResult,
+ fullBatchesList: ApiBatchListBatchesInner[],
+ batchesList: string[],
+) => {
+ fullBatchesList.push(...batchListPage.data);
+ batchListPage.data.map((batch) => {
+ batchesList.push(`Batch ID: ${batch.id} - Type: ${batch.type} - From: ${batch.from}`);
+ });
+};
+
+(async () => {
+ console.log('***************');
+ console.log('* ListBatches *');
+ console.log('***************');
+
+ const oneWeekAgo = new Date();
+ oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
+ oneWeekAgo.setHours(0, 0, 0, 0);
+
+ const requestData: ListBatchesRequestData= {
+ start_date: oneWeekAgo,
+ page_size: 2,
+ };
+
+ const sinchClient = initSmsClient();
+
+ // ----------------------------------------------
+ // Method 1: Fetch the data page by page manually
+ // ----------------------------------------------
+ let response = await sinchClient.sms.batches.list(requestData);
+
+ const fullBatchesList: ApiBatchListBatchesInner[] = [];
+ const batchesList: string[] = [];
+
+ // Loop on all the pages to get all the batches
+ let reachedEndOfPages = false;
+ while (!reachedEndOfPages) {
+ populateBatchesList(response, fullBatchesList, batchesList);
+ if (response.hasNextPage) {
+ response = await response.nextPage();
+ } else {
+ reachedEndOfPages = true;
+ }
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(batchesList.length > 0
+ ? 'List of batches: ' + JSON.stringify(batchesList, null, 2)
+ : 'Sorry, no batches were found.');
+ } else {
+ printFullResponse(fullBatchesList);
+ }
+
+ // ---------------------------------------------------------------------
+ // Method 2: Use the iterator and fetch data on more pages automatically
+ // ---------------------------------------------------------------------
+ for await (const batch of sinchClient.sms.batches.list(requestData)) {
+ if (printFormat === 'pretty') {
+ console.log(`Batch ID: ${batch.id} - Type: ${batch.type} - From: ${batch.from}`);
+ } else {
+ console.log(batch);
+ }
+ }
+})();
diff --git a/examples/simple-examples/src/sms/batches/replace.ts b/examples/simple-examples/src/sms/batches/replace.ts
new file mode 100644
index 00000000..b9372725
--- /dev/null
+++ b/examples/simple-examples/src/sms/batches/replace.ts
@@ -0,0 +1,64 @@
+import {
+ getBatchIdFromConfig, getPhoneNumberFromConfig,
+ getPrintFormat,
+ getRecipientPhoneNumberFromConfig,
+ initSmsClient,
+ printFullResponse,
+} from '../../config';
+import { BinaryRequest, ReplaceBatchMessageRequestData, textToHex } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('****************');
+ console.log('* ReplaceBatch *');
+ console.log('****************');
+
+ const batchIdInTheFuture = getBatchIdFromConfig();
+ if (!batchIdInTheFuture) {
+ throw new Error('No batch id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/replace.ts file');
+ }
+
+ const recipientPhoneNumber = getRecipientPhoneNumberFromConfig();
+ if (!recipientPhoneNumber) {
+ throw new Error('No recipient phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/replace.ts file');
+ }
+
+ const senderPhoneNumber = getPhoneNumberFromConfig();
+ if (!senderPhoneNumber) {
+ throw new Error('No sender phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/replace.ts file');
+ }
+
+ const requestData: ReplaceBatchMessageRequestData= {
+ batch_id: batchIdInTheFuture,
+ replaceBatchMessageRequestBody: {
+ from: senderPhoneNumber,
+ to: [
+ recipientPhoneNumber,
+ ],
+ udh: textToHex('UserDataHeader'),
+ body: btoa('This is an replaced message'),
+ delivery_report: 'none',
+ type: 'mt_binary',
+ client_reference: 'Sinch Node.js SDK',
+ } as BinaryRequest,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.batches.replace(requestData);
+ } catch (error) {
+ console.error(`ERROR: The batch could not be updated`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The batch has been updated successfully. Here is the batch id: ${response.id}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/sms/batches/send.ts b/examples/simple-examples/src/sms/batches/send.ts
new file mode 100644
index 00000000..8485884a
--- /dev/null
+++ b/examples/simple-examples/src/sms/batches/send.ts
@@ -0,0 +1,66 @@
+import {
+ getPhoneNumberFromConfig,
+ getPrintFormat,
+ getRecipientPhoneNumberFromConfig,
+ initSmsClient,
+ printFullResponse,
+} from '../../config';
+import { SendSMSRequestData, TextRequest } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('***********');
+ console.log('* SendSMS *');
+ console.log('***********');
+
+ const recipientPhoneNumber = getRecipientPhoneNumberFromConfig();
+ if (!recipientPhoneNumber) {
+ throw new Error('No recipient phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/send.ts file');
+ }
+
+ const senderPhoneNumber = getPhoneNumberFromConfig();
+ if (!senderPhoneNumber) {
+ throw new Error('No sender phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/send.ts file');
+ }
+
+ const oneDayLater = new Date();
+ oneDayLater.setDate(oneDayLater.getDate() +1);
+
+ const requestData: SendSMSRequestData= {
+ sendSMSRequestBody: {
+ to: [
+ recipientPhoneNumber,
+ ],
+ from: senderPhoneNumber,
+ parameters: {
+ name: {
+ [recipientPhoneNumber]: 'John',
+ default: 'there',
+ },
+ },
+ body: 'Hi ${name}!',
+ send_at: oneDayLater,
+ delivery_report: 'none',
+ type: 'mt_text',
+ } as TextRequest,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.batches.send(requestData);
+ } catch (error) {
+ console.error(`ERROR: The SMS could not be sent`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The SMS has been sent successfully. Here is the batch id: ${response.id}`);
+ } else {
+ printFullResponse(response);
+ }
+ console.log(`You may want to update your .env file with the following value: BATCH_ID=${response.id}`);
+})();
diff --git a/examples/simple-examples/src/sms/batches/update.ts b/examples/simple-examples/src/sms/batches/update.ts
new file mode 100644
index 00000000..839d7949
--- /dev/null
+++ b/examples/simple-examples/src/sms/batches/update.ts
@@ -0,0 +1,65 @@
+import {
+ getBatchIdFromConfig,
+ getPhoneNumberFromConfig,
+ getPrintFormat, getRecipientPhoneNumberFromConfig,
+ initSmsClient,
+ printFullResponse,
+} from '../../config';
+import { ApiUpdateTextMtMessage, UpdateBatchMessageRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('**********************');
+ console.log('* UpdateBatchMessage *');
+ console.log('**********************');
+
+ const batchId = getBatchIdFromConfig();
+ if (!batchId) {
+ throw new Error('No batch id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/update.ts file');
+ }
+
+ const recipientPhoneNumber = getRecipientPhoneNumberFromConfig();
+ if (!recipientPhoneNumber) {
+ throw new Error('No recipient phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/update.ts file');
+ }
+
+ const senderPhoneNumber = getPhoneNumberFromConfig();
+ if (!senderPhoneNumber) {
+ throw new Error('No sender phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/batches/update.ts file');
+ }
+
+ const requestData: UpdateBatchMessageRequestData= {
+ batch_id: batchId,
+ updateBatchMessageRequestBody: {
+ from: senderPhoneNumber,
+ parameters: {
+ name: {
+ [recipientPhoneNumber]: 'John',
+ default: 'there',
+ },
+ },
+ body: 'Hi ${name}! This is an updated message',
+ delivery_report: 'none',
+ type: 'mt_text',
+ } as ApiUpdateTextMtMessage,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.batches.update(requestData);
+ } catch (error) {
+ console.error(`ERROR: The batch could not be updated`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The batch has been updated successfully. Here is the batch id: ${response.id}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/sms/delivery-reports/getByBatchId.ts b/examples/simple-examples/src/sms/delivery-reports/getByBatchId.ts
new file mode 100644
index 00000000..5fd01ebd
--- /dev/null
+++ b/examples/simple-examples/src/sms/delivery-reports/getByBatchId.ts
@@ -0,0 +1,39 @@
+import { getBatchIdFromConfig, getPrintFormat, initSmsClient, printFullResponse } from '../../config';
+import { GetDeliveryReportByBatchIdRequestData, MessageDeliveryStatus } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('******************************');
+ console.log('* GetDeliveryReportByBatchId *');
+ console.log('******************************');
+
+ const batchId = getBatchIdFromConfig();
+ if (!batchId) {
+ throw new Error('No batch id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/delivery-reports/getByBatchId.ts file');
+ }
+
+ const requestData: GetDeliveryReportByBatchIdRequestData = {
+ batch_id: batchId,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.deliveryReports.get(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to retrieve the delivery report by batch ID ${requestData.batch_id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ const statuses: string[] = [];
+ response.statuses.map((status: MessageDeliveryStatus) => {
+ statuses.push(`${status.count} messages have the status ${status.code} - ${status.status}`);
+ });
+ console.log(`Delivery report from batch ID: ${response.batch_id} - Type: ${response.type} - Statuses: ${statuses}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/sms/delivery-reports/getByPhoneNumber.ts b/examples/simple-examples/src/sms/delivery-reports/getByPhoneNumber.ts
new file mode 100644
index 00000000..c9b61e72
--- /dev/null
+++ b/examples/simple-examples/src/sms/delivery-reports/getByPhoneNumber.ts
@@ -0,0 +1,48 @@
+import {
+ getBatchIdFromConfig,
+ getPrintFormat,
+ getRecipientPhoneNumberFromConfig,
+ initSmsClient,
+ printFullResponse,
+} from '../../config';
+import { GetDeliveryReportByPhoneNumberRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('**********************************');
+ console.log('* GetDeliveryReportByPhoneNumber *');
+ console.log('**********************************');
+
+ const batchId = getBatchIdFromConfig();
+ if (!batchId) {
+ throw new Error('No batch id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/delivery-reports/getByPhoneNumber.ts file');
+ }
+
+ const recipientPhoneNumber = getRecipientPhoneNumberFromConfig();
+ if (!recipientPhoneNumber) {
+ throw new Error('No recipient phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/delivery-reports/getByPhoneNumber.ts file');
+ }
+
+ const requestData: GetDeliveryReportByPhoneNumberRequestData = {
+ batch_id: batchId,
+ recipient_msisdn: recipientPhoneNumber,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.deliveryReports.getByPhoneNumber(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to retrieve the delivery report by batch ID ${requestData.batch_id} for the recipient ${requestData.recipient_msisdn}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Delivery report from batch ID ${response.batch_id} and recipient ${response.recipient} - Type: ${response.type} - Status: ${response.code} - ${response.status}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/sms/delivery-reports/list.ts b/examples/simple-examples/src/sms/delivery-reports/list.ts
new file mode 100644
index 00000000..2a681128
--- /dev/null
+++ b/examples/simple-examples/src/sms/delivery-reports/list.ts
@@ -0,0 +1,79 @@
+import { getPrintFormat, initSmsClient, printFullResponse } from '../../config';
+import {
+ GetDeliveryReportsRequestData, PageResult,
+ RecipientDeliveryReport,
+} from '@sinch/sdk-core';
+
+const populateDeliveryReportsList = (
+ deliveryReportsListPage: PageResult,
+ fullDeliveryReportsList: RecipientDeliveryReport[],
+ deliveryReportsList: string[],
+) => {
+ fullDeliveryReportsList.push(...deliveryReportsListPage.data);
+ deliveryReportsListPage.data?.map((deliveryReport) => {
+ deliveryReportsList.push(`Delivery support status: ${deliveryReport.status} - Type: ${deliveryReport.type} - Batch ID: ${deliveryReport.batch_id}`);
+ });
+};
+
+(async () => {
+ console.log('**********************');
+ console.log('* getDeliveryReports *');
+ console.log('**********************');
+
+ const oneWeekAgo = new Date();
+ oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
+ oneWeekAgo.setHours(0, 0, 0, 0);
+
+ const requestData: GetDeliveryReportsRequestData= {
+ start_date: oneWeekAgo,
+ };
+
+ const sinchClient = initSmsClient();
+
+ // ----------------------------------------------
+ // Method 1: Fetch the data page by page manually
+ // ----------------------------------------------
+ let response;
+ try {
+ response = await sinchClient.sms.deliveryReports.list(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to get the list of delivery reports starting at ${requestData.start_date}`);
+ throw error;
+ }
+
+ const fullDeliveryReportsList: RecipientDeliveryReport[] = [];
+ const deliveryReportsList: string[] = [];
+
+ // Loop on all the pages to get all the delivery reports
+ let reachedEndOfPages = false;
+ while (!reachedEndOfPages) {
+ populateDeliveryReportsList(response, fullDeliveryReportsList, deliveryReportsList);
+ if (response.hasNextPage) {
+ response = await response.nextPage();
+ } else {
+ reachedEndOfPages = true;
+ }
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(deliveryReportsList.length > 0
+ ? 'List of delivery reports: ' + JSON.stringify(deliveryReportsList, null, 2)
+ : 'Sorry, no delivery reports were found.');
+ } else {
+ printFullResponse(fullDeliveryReportsList);
+ }
+
+ // ---------------------------------------------------------------------
+ // Method 2: Use the iterator and fetch data on more pages automatically
+ // ---------------------------------------------------------------------
+ for await (const deliveryReport of sinchClient.sms.deliveryReports.list(requestData)) {
+ if (printFormat === 'pretty') {
+ console.log(`Delivery support status: ${deliveryReport.status} - Type: ${deliveryReport.type} - Batch ID: ${deliveryReport.batch_id}`);
+ } else {
+ console.log(deliveryReport);
+ }
+ }
+
+})();
diff --git a/examples/simple-examples/src/sms/groups/create/create.sinch-client.ts b/examples/simple-examples/src/sms/groups/create/create.sinch-client.ts
new file mode 100644
index 00000000..06acddd1
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/create/create.sinch-client.ts
@@ -0,0 +1,7 @@
+import { initClient } from '../../../config';
+import { create } from './create';
+
+(async () => {
+ const sinchClient = initClient();
+ await create(sinchClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/create/create.sinch-sms-client.ts b/examples/simple-examples/src/sms/groups/create/create.sinch-sms-client.ts
new file mode 100644
index 00000000..b2800840
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/create/create.sinch-sms-client.ts
@@ -0,0 +1,7 @@
+import { initSmsClient } from '../../../config';
+import { create } from './create';
+
+(async () => {
+ const sinchSmsClient = initSmsClient();
+ await create(sinchSmsClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/create/create.ts b/examples/simple-examples/src/sms/groups/create/create.ts
new file mode 100644
index 00000000..9c71cd6c
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/create/create.ts
@@ -0,0 +1,36 @@
+import { CreateGroupRequestData, SinchClient } from '@sinch/sdk-core';
+import { getPrintFormat, printFullResponse } from '../../../config';
+
+export const create = async(sinchClient: SinchClient) => {
+ console.log('***************');
+ console.log('* CreateGroup *');
+ console.log('***************');
+
+ const requestData: CreateGroupRequestData = {
+ createGroupRequestBody: {
+ name: `Group_${new Date().getTime()}`,
+ members: [
+ "+11111111100",
+ "+22222222200",
+ "+33333333300",
+ ],
+ },
+ };
+
+ let response;
+ try {
+ response = await sinchClient.sms.groups.create(requestData);
+ } catch (error) {
+ console.error('ERROR: Impossible to create a new group');
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`New group created! Group ID: ${response.id} - Group name: ${response.name}`);
+ } else {
+ printFullResponse(response);
+ }
+ console.log(`You may want to update your .env file with the following value: GROUP_ID=${response.id}`);
+};
diff --git a/examples/simple-examples/src/sms/groups/delete/delete.sinch-client.ts b/examples/simple-examples/src/sms/groups/delete/delete.sinch-client.ts
new file mode 100644
index 00000000..c1436850
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/delete/delete.sinch-client.ts
@@ -0,0 +1,7 @@
+import { initClient } from '../../../config';
+import { deleteGroup } from './delete';
+
+(async () => {
+ const sinchClient = initClient();
+ await deleteGroup(sinchClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/delete/delete.sinch-sms-client.ts b/examples/simple-examples/src/sms/groups/delete/delete.sinch-sms-client.ts
new file mode 100644
index 00000000..bce74da6
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/delete/delete.sinch-sms-client.ts
@@ -0,0 +1,7 @@
+import { initSmsClient } from '../../../config';
+import { deleteGroup } from './delete';
+
+(async () => {
+ const sinchSmsClient = initSmsClient();
+ await deleteGroup(sinchSmsClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/delete/delete.ts b/examples/simple-examples/src/sms/groups/delete/delete.ts
new file mode 100644
index 00000000..86830053
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/delete/delete.ts
@@ -0,0 +1,27 @@
+import { SinchClient, DeleteGroupRequestData } from '@sinch/sdk-core';
+import { getGroupIdFromConfig } from '../../../config';
+
+export const deleteGroup = async(sinchClient: SinchClient) => {
+ console.log('***************');
+ console.log('* deleteGroup *');
+ console.log('***************');
+
+ const groupId = getGroupIdFromConfig();
+ if (!groupId) {
+ throw new Error('No group id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/groups/delete.ts file');
+ }
+
+ const requestData: DeleteGroupRequestData = {
+ group_id: groupId,
+ };
+
+ try {
+ await sinchClient.sms.groups.delete(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to delete the group ${requestData.group_id}`);
+ throw error;
+ }
+
+ console.log(`Group ${requestData.group_id} has been deleted!`);
+};
diff --git a/examples/simple-examples/src/sms/groups/get/get.sinch-client.ts b/examples/simple-examples/src/sms/groups/get/get.sinch-client.ts
new file mode 100644
index 00000000..8d8afba3
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/get/get.sinch-client.ts
@@ -0,0 +1,7 @@
+import { initClient } from '../../../config';
+import { get } from './get';
+
+(async () => {
+ const sinchClient = initClient();
+ await get(sinchClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/get/get.sinch-sms-client.ts b/examples/simple-examples/src/sms/groups/get/get.sinch-sms-client.ts
new file mode 100644
index 00000000..07d24b73
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/get/get.sinch-sms-client.ts
@@ -0,0 +1,7 @@
+import { initSmsClient } from '../../../config';
+import { get } from './get';
+
+(async () => {
+ const sinchSmsClient = initSmsClient();
+ await get(sinchSmsClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/get/get.ts b/examples/simple-examples/src/sms/groups/get/get.ts
new file mode 100644
index 00000000..d075456e
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/get/get.ts
@@ -0,0 +1,34 @@
+import { SinchClient, GetGroupRequestData } from '@sinch/sdk-core';
+import { getGroupIdFromConfig, getPrintFormat, printFullResponse } from '../../../config';
+
+export const get = async(sinchClient: SinchClient) => {
+ console.log('*****************');
+ console.log('* RetrieveGroup *');
+ console.log('*****************');
+
+ const groupId = getGroupIdFromConfig();
+ if (!groupId) {
+ throw new Error('No group id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/groups/get.ts file');
+ }
+
+ const requestData: GetGroupRequestData = {
+ group_id: groupId,
+ };
+
+ let response;
+ try {
+ response = await sinchClient.sms.groups.get(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to get the group ${requestData.group_id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Group ID: ${response.id} - Group name: ${response.name}`);
+ } else {
+ printFullResponse(response);
+ }
+};
diff --git a/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.sinch-client.ts b/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.sinch-client.ts
new file mode 100644
index 00000000..8728e4d6
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.sinch-client.ts
@@ -0,0 +1,7 @@
+import { initClient } from '../../../config';
+import { getPhoneNumbers } from './getPhoneNumbers';
+
+(async () => {
+ const sinchClient = initClient();
+ await getPhoneNumbers(sinchClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.sinch-sms-client.ts b/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.sinch-sms-client.ts
new file mode 100644
index 00000000..ad85a497
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.sinch-sms-client.ts
@@ -0,0 +1,7 @@
+import { initSmsClient } from '../../../config';
+import { getPhoneNumbers } from './getPhoneNumbers';
+
+(async () => {
+ const sinchSmsClient = initSmsClient();
+ await getPhoneNumbers(sinchSmsClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts b/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts
new file mode 100644
index 00000000..5ca37819
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts
@@ -0,0 +1,36 @@
+import { ListMembersRequestData, SinchClient } from '@sinch/sdk-core';
+import { getGroupIdFromConfig, getPrintFormat, printFullResponse } from '../../../config';
+
+export const getPhoneNumbers = async(sinchClient: SinchClient) => {
+ console.log('**************');
+ console.log('* GetMembers *');
+ console.log('**************');
+
+ const groupId = getGroupIdFromConfig();
+ if (!groupId) {
+ throw new Error('No group id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/groups/getPhoneNumbers.ts file');
+ }
+
+ const requestData: ListMembersRequestData = {
+ group_id: groupId,
+ };
+
+ let response;
+ try {
+ response = await sinchClient.sms.groups.listMembers(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to get the numbers of the group ${requestData.group_id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(response.length > 0
+ ? 'List of phone numbers: ' + JSON.stringify(response, null, 2)
+ : `Sorry, no phone numbers in group ${requestData.group_id} were found.`);
+ } else {
+ printFullResponse(response);
+ }
+};
diff --git a/examples/simple-examples/src/sms/groups/list/list.sinch-client.ts b/examples/simple-examples/src/sms/groups/list/list.sinch-client.ts
new file mode 100644
index 00000000..44af8fcd
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/list/list.sinch-client.ts
@@ -0,0 +1,7 @@
+import { initClient } from '../../../config';
+import { list } from './list';
+
+(async () => {
+ const sinchClient = initClient();
+ await list(sinchClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/list/list.sinch-sms-client.ts b/examples/simple-examples/src/sms/groups/list/list.sinch-sms-client.ts
new file mode 100644
index 00000000..0454f295
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/list/list.sinch-sms-client.ts
@@ -0,0 +1,7 @@
+import { initSmsClient } from '../../../config';
+import { list } from './list';
+
+(async () => {
+ const sinchSmsClient = initSmsClient();
+ await list(sinchSmsClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/list/list.ts b/examples/simple-examples/src/sms/groups/list/list.ts
new file mode 100644
index 00000000..106e22fe
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/list/list.ts
@@ -0,0 +1,80 @@
+import {
+ SinchClient,
+ CreateGroupResponse,
+ ListGroupsRequestData, PageResult,
+} from '@sinch/sdk-core';
+import { getPrintFormat, printFullResponse } from '../../../config';
+
+const populateGroupsList = (
+ groupsPage: PageResult,
+ fullGroupsList: CreateGroupResponse[],
+ groupsList: string[],
+) => {
+ // Populate the data structure that holds the response content
+ fullGroupsList.push(...groupsPage.data);
+ // Populate the data structure that holds the response content for pretty print
+ groupsPage.data.map((group: CreateGroupResponse) => {
+ groupsList.push(`Group ID: ${group.id} - Group name: ${group.name}`);
+ });
+};
+
+export const list = async(sinchClient: SinchClient) => {
+ console.log('**************');
+ console.log('* ListGroups *');
+ console.log('**************');
+
+ const requestData: ListGroupsRequestData = {
+ page_size: 1,
+ };
+
+ // ----------------------------------------------
+ // Method 1: Fetch the data page by page manually
+ // ----------------------------------------------
+ let response;
+ try {
+ response = await sinchClient.sms.groups.list(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to list the groups associated to your service plan id`);
+ throw error;
+ }
+
+ // Init data structure to hold the response content
+ const fullGroupsList: CreateGroupResponse[] = [];
+ // Init data structure to hold the response content for pretty print
+ const groupsList: string[] = [];
+
+ // Loop on all the pages to get all the groups
+ let reachedEndOfPages = false;
+ while (!reachedEndOfPages) {
+ populateGroupsList(response, fullGroupsList, groupsList);
+ if (response.hasNextPage) {
+ response = await response.nextPage();
+ } else {
+ reachedEndOfPages = true;
+ }
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(groupsList.length > 0
+ ? 'List of members: ' + JSON.stringify(groupsList, null, 2)
+ : 'Sorry, no members in groups were found.');
+ } else {
+ printFullResponse(fullGroupsList);
+ }
+
+ // ---------------------------------------------------------------------
+ // Method 2: Use the iterator and fetch data on more pages automatically
+ // ---------------------------------------------------------------------
+ for await (const group of sinchClient.sms.groups.list(requestData)) {
+ if (printFormat === 'pretty') {
+ console.log(`Group ID: ${group.id} - Group name: ${group.name}`);
+ } else {
+ console.log(group);
+ }
+ }
+
+};
+
+
diff --git a/examples/simple-examples/src/sms/groups/replace/replace.sinch-client.ts b/examples/simple-examples/src/sms/groups/replace/replace.sinch-client.ts
new file mode 100644
index 00000000..a39215ba
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/replace/replace.sinch-client.ts
@@ -0,0 +1,7 @@
+import { initClient } from '../../../config';
+import { replace } from './replace';
+
+(async () => {
+ const sinchClient = initClient();
+ await replace(sinchClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/replace/replace.sinch-sms-client.ts b/examples/simple-examples/src/sms/groups/replace/replace.sinch-sms-client.ts
new file mode 100644
index 00000000..bcdffe06
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/replace/replace.sinch-sms-client.ts
@@ -0,0 +1,7 @@
+import { initSmsClient } from '../../../config';
+import { replace } from './replace';
+
+(async () => {
+ const sinchSmsClient = initSmsClient();
+ await replace(sinchSmsClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/replace/replace.ts b/examples/simple-examples/src/sms/groups/replace/replace.ts
new file mode 100644
index 00000000..ea5a0b58
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/replace/replace.ts
@@ -0,0 +1,41 @@
+import { ReplaceGroupRequestData, SinchClient } from '@sinch/sdk-core';
+import { getGroupIdFromConfig, getPrintFormat, printFullResponse } from '../../../config';
+
+export const replace = async(sinchClient: SinchClient) => {
+ console.log('****************');
+ console.log('* ReplaceGroup *');
+ console.log('****************');
+
+ const groupId = getGroupIdFromConfig();
+ if (!groupId) {
+ throw new Error('No group id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/groups/replace.ts file');
+ }
+
+ const requestData: ReplaceGroupRequestData = {
+ group_id: groupId,
+ replaceGroupRequestBody: {
+ members: [
+ '+111111111',
+ '+222222222',
+ ],
+ },
+ };
+
+ let response;
+ try {
+ response = await sinchClient.sms.groups.replace(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to replace the group ${requestData.group_id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The group ${response.id} has been replaced and contains now ${response.size} member(s)`);
+ } else {
+ printFullResponse(response);
+ }
+
+};
diff --git a/examples/simple-examples/src/sms/groups/update/update.sinch-client.ts b/examples/simple-examples/src/sms/groups/update/update.sinch-client.ts
new file mode 100644
index 00000000..d2e85eef
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/update/update.sinch-client.ts
@@ -0,0 +1,7 @@
+import { initClient } from '../../../config';
+import { update } from './update';
+
+(async () => {
+ const sinchClient = initClient();
+ await update(sinchClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/update/update.sinch-sms-client.ts b/examples/simple-examples/src/sms/groups/update/update.sinch-sms-client.ts
new file mode 100644
index 00000000..9b9bd30d
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/update/update.sinch-sms-client.ts
@@ -0,0 +1,7 @@
+import { initSmsClient } from '../../../config';
+import { update } from './update';
+
+(async () => {
+ const sinchSmsClient = initSmsClient();
+ await update(sinchSmsClient);
+})();
diff --git a/examples/simple-examples/src/sms/groups/update/update.ts b/examples/simple-examples/src/sms/groups/update/update.ts
new file mode 100644
index 00000000..3844251c
--- /dev/null
+++ b/examples/simple-examples/src/sms/groups/update/update.ts
@@ -0,0 +1,42 @@
+import { SinchClient, UpdateGroupRequestData } from '@sinch/sdk-core';
+import { getGroupIdFromConfig, getPrintFormat, printFullResponse } from '../../../config';
+
+export const update = async(sinchClient: SinchClient) => {
+ console.log('***************');
+ console.log('* UpdateGroup *');
+ console.log('***************');
+
+ const groupId = getGroupIdFromConfig();
+ if (!groupId) {
+ throw new Error('No group id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/groups/update.ts file');
+ }
+
+ const requestData: UpdateGroupRequestData = {
+ group_id: groupId,
+ updateGroupRequestBody: {
+ name: `update_${new Date().getTime()}`,
+ add: [
+ '+123456789',
+ '+987654321',
+ ],
+ },
+ };
+
+ let response;
+ try {
+ response = await sinchClient.sms.groups.update(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to update the group ${requestData.group_id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`The group ${response.id} has been updated and has now the name '${response.name}' and contains ${response.size} member(s)`);
+ } else {
+ printFullResponse(response);
+ }
+
+};
diff --git a/examples/simple-examples/src/sms/inbounds/get.ts b/examples/simple-examples/src/sms/inbounds/get.ts
new file mode 100644
index 00000000..8a8316ee
--- /dev/null
+++ b/examples/simple-examples/src/sms/inbounds/get.ts
@@ -0,0 +1,40 @@
+import {
+ getInboundIdFromConfig,
+ getPrintFormat,
+ initSmsClient,
+ printFullResponse,
+} from '../../config';
+import { GetInboundMessageRequestData } from '@sinch/sdk-core';
+
+(async () => {
+ console.log('**************************');
+ console.log('* RetrieveInboundMessage *');
+ console.log('**************************');
+
+ const inboundId = getInboundIdFromConfig();
+ if (!inboundId) {
+ throw new Error('No inbound id has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/inbounds/get.ts file');
+ }
+
+ const requestData: GetInboundMessageRequestData = {
+ inbound_id: inboundId,
+ };
+
+ const sinchClient = initSmsClient();
+ let response;
+ try {
+ response = await sinchClient.sms.inbounds.get(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to retrieve the inbound message ${requestData.inbound_id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Incoming message ID: ${response.id} - Type: ${response.type} - From: ${response.from}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/sms/inbounds/list.ts b/examples/simple-examples/src/sms/inbounds/list.ts
new file mode 100644
index 00000000..217ecfe0
--- /dev/null
+++ b/examples/simple-examples/src/sms/inbounds/list.ts
@@ -0,0 +1,91 @@
+import { getPrintFormat, getRecipientPhoneNumberFromConfig, initSmsClient, printFullResponse } from '../../config';
+import {
+ InboundMessageResponse,
+ ListInboundMessagesRequestData,
+ PageResult,
+} from '@sinch/sdk-core';
+
+const populateInboundMessagesList = (
+ inboundMessagesListPage: PageResult,
+ fullInboundMessagesList: InboundMessageResponse[],
+ inboundMessagesList: string[],
+) => {
+ fullInboundMessagesList.push(...inboundMessagesListPage.data);
+ inboundMessagesListPage.data.map((inboundMessage) => {
+ inboundMessagesList.push(`Inbound message ID: ${inboundMessage.id} - Type: ${inboundMessage.type} - From: ${inboundMessage.from}`);
+ });
+};
+
+(async () => {
+ console.log('***********************');
+ console.log('* ListInboundMessages *');
+ console.log('***********************');
+
+ const oneWeekAgo = new Date();
+ oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
+ oneWeekAgo.setHours(0, 0, 0, 0);
+
+ const recipientPhoneNumber = getRecipientPhoneNumberFromConfig();
+ if (!recipientPhoneNumber) {
+ throw new Error('No recipient phone number has been provided. '
+ + 'Please update your .env file or edit the ./src/sms/inbounds/list.ts file');
+ }
+
+ const requestData: ListInboundMessagesRequestData= {
+ start_date: oneWeekAgo,
+ to: recipientPhoneNumber,
+ };
+
+ const sinchClient = initSmsClient();
+
+ // ----------------------------------------------
+ // Method 1: Fetch the data page by page manually
+ // ----------------------------------------------
+ let response;
+ try {
+ response = await sinchClient.sms.inbounds.list(requestData);
+ } catch (error) {
+ console.error(`ERROR: Impossible to get the list the inbound messages for the numbers ${requestData.to}`);
+ throw error;
+ }
+
+ const fullInboundMessagesList: InboundMessageResponse[] = [];
+ const inboundMessagesList: string[] = [];
+
+ // Loop on all the pages to get all the batches
+ let reachedEndOfPages = false;
+ while (!reachedEndOfPages) {
+ populateInboundMessagesList(response, fullInboundMessagesList, inboundMessagesList);
+ if (response.hasNextPage) {
+ response = await response.nextPage();
+ } else {
+ reachedEndOfPages = true;
+ }
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(inboundMessagesList.length > 0
+ ? 'List of inbound messages: ' + JSON.stringify(inboundMessagesList, null, 2)
+ : 'Sorry, no inbound messages were found.');
+ } else {
+ printFullResponse(fullInboundMessagesList);
+ }
+
+ if (fullInboundMessagesList.length > 0) {
+ console.log(`You may want to update your .env file with the following value: INBOUND_ID=${fullInboundMessagesList[0].id}`);
+ }
+
+ // ---------------------------------------------------------------------
+ // Method 2: Use the iterator and fetch data on more pages automatically
+ // ---------------------------------------------------------------------
+ for await (const inboundMessage of sinchClient.sms.inbounds.list(requestData)) {
+ if (printFormat === 'pretty') {
+ console.log(`Inbound message ID: ${inboundMessage.id} - Type: ${inboundMessage.type} - From: ${inboundMessage.from}`);
+ } else {
+ console.log(inboundMessage);
+ }
+ }
+
+})();
diff --git a/examples/simple-examples/src/verification/verification-status/verification-by-id.ts b/examples/simple-examples/src/verification/verification-status/verification-by-id.ts
new file mode 100644
index 00000000..2669dc51
--- /dev/null
+++ b/examples/simple-examples/src/verification/verification-status/verification-by-id.ts
@@ -0,0 +1,40 @@
+import { VerificationStatusByIdRequestData } from '@sinch/sdk-core';
+import {
+ getPrintFormat,
+ getVerificationIdFromConfig,
+ initVerificationClient,
+ printFullResponse,
+} from '../../config';
+
+(async () => {
+ console.log('**************************');
+ console.log('* VerificationStatusById *');
+ console.log('**************************');
+
+ const verificationId = getVerificationIdFromConfig();
+ if (!verificationId) {
+ throw new Error('No verification id has been provided. '
+ + 'Please update your .env file or edit the ./src/verification/verification-status/verification-by-id.ts file');
+ }
+
+ const requestData: VerificationStatusByIdRequestData = {
+ id: verificationId,
+ };
+
+ const sinchClient = initVerificationClient();
+ let response;
+ try {
+ response = await sinchClient.verification.verificationStatus.getById(requestData);
+ } catch (error) {
+ console.log(`Impossible to get the verification status for the id ${requestData.id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Verification ID: ${response.id}\nStatus: ${response.status}${response.status === 'SUCCESSFUL' ? '':' (' + response.reason + ')'}\nPrice: ${response.price?.verificationPrice?.amount} ${response.price?.verificationPrice?.currencyId}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/verification/verification-status/verification-by-identity.ts b/examples/simple-examples/src/verification/verification-status/verification-by-identity.ts
new file mode 100644
index 00000000..9715dfed
--- /dev/null
+++ b/examples/simple-examples/src/verification/verification-status/verification-by-identity.ts
@@ -0,0 +1,37 @@
+import { VerificationStatusByIdentityRequestData } from '@sinch/sdk-core';
+import { getPrintFormat, getVerificationIdentityFromConfig, initVerificationClient, printFullResponse } from '../../config';
+
+(async () => {
+ console.log('********************************');
+ console.log('* VerificationStatusByIdentity *');
+ console.log('********************************');
+
+ const verificationIdentity = getVerificationIdentityFromConfig();
+ if (!verificationIdentity) {
+ throw new Error('No verification identity has been provided. '
+ + 'Please update your .env file '
+ + 'or edit the ./src/verification/verification-status/verification-by-identity.ts file');
+ }
+
+ const requestData: VerificationStatusByIdentityRequestData = {
+ endpoint: verificationIdentity,
+ method: 'sms',
+ };
+
+ const sinchClient = initVerificationClient();
+ let response;
+ try {
+ response = await sinchClient.verification.verificationStatus.getByIdentity(requestData);
+ } catch (error) {
+ console.log(`Impossible to get the verification status for the identity ${requestData.endpoint}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Verification ID: ${response.id}\nStatus: ${response.status}${response.status === 'SUCCESSFUL' ? '':' (' + response.reason + ')'}\nPrice: ${response.price?.verificationPrice?.amount} ${response.price?.verificationPrice?.currencyId}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/verification/verification-status/verification-by-reference.ts b/examples/simple-examples/src/verification/verification-status/verification-by-reference.ts
new file mode 100644
index 00000000..2608c190
--- /dev/null
+++ b/examples/simple-examples/src/verification/verification-status/verification-by-reference.ts
@@ -0,0 +1,41 @@
+import { VerificationStatusByReferenceRequestData } from '@sinch/sdk-core';
+import {
+ getPrintFormat,
+ getVerificationReferenceFromConfig,
+ initVerificationClient,
+ printFullResponse,
+} from '../../config';
+
+(async () => {
+ console.log('*********************************');
+ console.log('* VerificationStatusByReference *');
+ console.log('*********************************');
+
+ const verificationReference = getVerificationReferenceFromConfig();
+ if (!verificationReference) {
+ throw new Error('No verification reference has been provided. '
+ + 'Please update your .env file '
+ + 'or edit the ./src/verification/verification-status/verification-by-reference.ts file');
+ }
+
+ const requestData: VerificationStatusByReferenceRequestData = {
+ reference: verificationReference,
+ };
+
+ const sinchClient = initVerificationClient();
+ let response;
+ try {
+ response = await sinchClient.verification.verificationStatus.getByReference(requestData);
+ } catch (error) {
+ console.log(`Impossible to get the verification status for the reference ${requestData.reference}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Verification ID: ${response.id}\nStatus: ${response.status}${response.status === 'SUCCESSFUL' ? '':' (' + response.reason + ')'}\nPrice: ${response.price?.verificationPrice?.amount} ${response.price?.verificationPrice?.currencyId}`);
+ } else {
+ printFullResponse(response);
+ }
+})();
diff --git a/examples/simple-examples/src/verification/verifications/callout/report-with-id_callout.ts b/examples/simple-examples/src/verification/verifications/callout/report-with-id_callout.ts
new file mode 100644
index 00000000..c7bb1be1
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/callout/report-with-id_callout.ts
@@ -0,0 +1,36 @@
+import { ReportVerificationByIdRequestData } from '@sinch/sdk-core';
+import {
+ getVerificationCodeFromConfig,
+ getVerificationIdFromConfig,
+} from '../../../config';
+import { reportWithId } from '../report-with-id';
+
+(async () => {
+ console.log('************************************');
+ console.log('* ReportVerificationById - callout *');
+ console.log('************************************');
+
+ const verificationId = getVerificationIdFromConfig();
+ if (!verificationId) {
+ throw new Error('No verification id has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/callout/report-with-id_callout.ts file');
+ }
+
+ const verificationCode = getVerificationCodeFromConfig();
+ if (!verificationCode) {
+ throw new Error('No verification code has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/callout/report-with-id_callout.ts file');
+ }
+
+ const requestData: ReportVerificationByIdRequestData = {
+ id: verificationId,
+ verificationReportRequestBody: {
+ method: 'callout',
+ callout: {
+ code: verificationCode,
+ },
+ },
+ };
+
+ await reportWithId(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/callout/report-with-identity_callout.ts b/examples/simple-examples/src/verification/verifications/callout/report-with-identity_callout.ts
new file mode 100644
index 00000000..fe39b702
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/callout/report-with-identity_callout.ts
@@ -0,0 +1,36 @@
+import { ReportVerificationByIdentityRequestData } from '@sinch/sdk-core';
+import {
+ getVerificationCodeFromConfig,
+ getVerificationIdentityFromConfig,
+} from '../../../config';
+import { reportWithIdentity } from '../report-with-identity';
+
+(async () => {
+ console.log('******************************************');
+ console.log('* ReportVerificationByIdentity - callout *');
+ console.log('******************************************');
+
+ const verificationIdentity = getVerificationIdentityFromConfig();
+ if (!verificationIdentity) {
+ throw new Error('No verification identity has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/callout/report-with-identity_callout.ts file');
+ }
+
+ const verificationCode = getVerificationCodeFromConfig();
+ if (!verificationCode) {
+ throw new Error('No verification code has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/callout/report-with-identity_callout.ts file');
+ }
+
+ const requestData: ReportVerificationByIdentityRequestData = {
+ endpoint: verificationIdentity,
+ verificationReportRequestBody: {
+ method: 'callout',
+ callout: {
+ code: verificationCode,
+ },
+ },
+ };
+
+ await reportWithIdentity(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/callout/start-callout.ts b/examples/simple-examples/src/verification/verifications/callout/start-callout.ts
new file mode 100644
index 00000000..a27fb95a
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/callout/start-callout.ts
@@ -0,0 +1,28 @@
+import { StartVerificationRequestData } from '@sinch/sdk-core';
+import { startVerification } from '../start';
+import { getVerificationIdentityFromConfig } from '../../../config';
+
+(async () => {
+ console.log('*******************************');
+ console.log('* StartVerification - callout *');
+ console.log('*******************************');
+
+ const verificationIdentity = getVerificationIdentityFromConfig();
+ if (!verificationIdentity) {
+ throw new Error('No verification identity has been provided. '
+ + 'Please update your .env file or edit the ./src/verification/verifications/callout/start-callout.ts file');
+ }
+
+ const requestData: StartVerificationRequestData = {
+ initiateVerificationRequestBody: {
+ identity: {
+ type: 'number',
+ endpoint: verificationIdentity,
+ },
+ method: 'callout',
+ reference: `test-reference-for-callout-verification_${verificationIdentity}`,
+ },
+ };
+
+ await startVerification(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/flashcall/report-with-id_flashcall.ts b/examples/simple-examples/src/verification/verifications/flashcall/report-with-id_flashcall.ts
new file mode 100644
index 00000000..488518ed
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/flashcall/report-with-id_flashcall.ts
@@ -0,0 +1,36 @@
+import { ReportVerificationByIdRequestData } from '@sinch/sdk-core';
+import {
+ getVerificationCliFromConfig,
+ getVerificationIdFromConfig,
+} from '../../../config';
+import { reportWithId } from '../report-with-id';
+
+(async () => {
+ console.log('***************************************');
+ console.log('* ReportVerificationById - flashCall *');
+ console.log('***************************************');
+
+ const verificationId = getVerificationIdFromConfig();
+ if (!verificationId) {
+ throw new Error('No verification id has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/flashcall/report-with-id_flashcall.ts file');
+ }
+
+ const verificationCli = getVerificationCliFromConfig();
+ if (!verificationCli) {
+ throw new Error('No verification CLI has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/flashcall/report-with-id_flashcall.ts file');
+ }
+
+ const requestData: ReportVerificationByIdRequestData = {
+ id: verificationId,
+ verificationReportRequestBody: {
+ method: 'flashCall',
+ flashCall: {
+ cli: verificationCli,
+ },
+ },
+ };
+
+ await reportWithId(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/flashcall/report-with-identity_flashcall.ts b/examples/simple-examples/src/verification/verifications/flashcall/report-with-identity_flashcall.ts
new file mode 100644
index 00000000..5c35a8ad
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/flashcall/report-with-identity_flashcall.ts
@@ -0,0 +1,36 @@
+import { ReportVerificationByIdentityRequestData } from '@sinch/sdk-core';
+import {
+ getVerificationCliFromConfig,
+ getVerificationIdentityFromConfig,
+} from '../../../config';
+import { reportWithIdentity } from '../report-with-identity';
+
+(async () => {
+ console.log('*********************************************');
+ console.log('* ReportVerificationByIdentity - flashCall *');
+ console.log('*********************************************');
+
+ const verificationIdentity = getVerificationIdentityFromConfig();
+ if (!verificationIdentity) {
+ throw new Error('No verification identity has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/flashcall/report-with-identity_flashcall.ts file');
+ }
+
+ const verificationCli = getVerificationCliFromConfig();
+ if (!verificationCli) {
+ throw new Error('No verification CLI has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/flashcall/report-with-identity_flashcall.ts file');
+ }
+
+ const requestData: ReportVerificationByIdentityRequestData = {
+ endpoint: verificationIdentity,
+ verificationReportRequestBody: {
+ method: 'flashCall',
+ flashCall: {
+ cli: verificationCli,
+ },
+ },
+ };
+
+ await reportWithIdentity(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/flashcall/start-flashcall.ts b/examples/simple-examples/src/verification/verifications/flashcall/start-flashcall.ts
new file mode 100644
index 00000000..76465263
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/flashcall/start-flashcall.ts
@@ -0,0 +1,31 @@
+import { StartVerificationRequestData } from '@sinch/sdk-core';
+import { startVerification } from '../start';
+import { getVerificationIdentityFromConfig } from '../../../config';
+
+(async () => {
+ console.log('*********************************');
+ console.log('* StartVerification - flashCall *');
+ console.log('*********************************');
+
+ const verificationIdentity = getVerificationIdentityFromConfig();
+ if (!verificationIdentity) {
+ throw new Error('No verification identity has been provided. '
+ + 'Please update your .env file or edit the ./src/verification/verifications/flashcall/start-flashcall.ts file');
+ }
+
+ const requestData: StartVerificationRequestData = {
+ initiateVerificationRequestBody: {
+ identity: {
+ type: 'number',
+ endpoint: verificationIdentity,
+ },
+ method: 'flashCall',
+ reference: `test-reference-for-flashCall-verification_${verificationIdentity}`,
+ flashCallOptions: {
+ dialTimeout: 20,
+ },
+ },
+ };
+
+ await startVerification(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/report-with-id.ts b/examples/simple-examples/src/verification/verifications/report-with-id.ts
new file mode 100644
index 00000000..2be61f42
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/report-with-id.ts
@@ -0,0 +1,21 @@
+import { ReportVerificationByIdRequestData } from '@sinch/sdk-core';
+import { getPrintFormat, initVerificationClient, printFullResponse } from '../../config';
+
+export const reportWithId = async (requestData: ReportVerificationByIdRequestData) => {
+ const sinchClient = initVerificationClient();
+ let response;
+ try {
+ response = await sinchClient.verification.verifications.reportById(requestData);
+ } catch (error) {
+ console.log(`Impossible to report the verification for the id ${requestData.id}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Verification status: ${response.status}${response.status === 'SUCCESSFUL'?'':' - Reason: ' + response.reason}`);
+ } else {
+ printFullResponse(response);
+ }
+};
diff --git a/examples/simple-examples/src/verification/verifications/report-with-identity.ts b/examples/simple-examples/src/verification/verifications/report-with-identity.ts
new file mode 100644
index 00000000..59225067
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/report-with-identity.ts
@@ -0,0 +1,21 @@
+import { ReportVerificationByIdentityRequestData } from '@sinch/sdk-core';
+import { getPrintFormat, initVerificationClient, printFullResponse } from '../../config';
+
+export const reportWithIdentity = async (requestData: ReportVerificationByIdentityRequestData) => {
+ const sinchClient = initVerificationClient();
+ let response;
+ try {
+ response = await sinchClient.verification.verifications.reportByIdentity(requestData);
+ } catch (error) {
+ console.log(`Impossible to report the verification for the identity ${requestData.endpoint}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Verification status: ${response.status}${response.status === 'SUCCESSFUL'?'':' - Reason: ' + response.reason}`);
+ } else {
+ printFullResponse(response);
+ }
+};
diff --git a/examples/simple-examples/src/verification/verifications/seamless/start-seamless.ts b/examples/simple-examples/src/verification/verifications/seamless/start-seamless.ts
new file mode 100644
index 00000000..9fc4dc66
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/seamless/start-seamless.ts
@@ -0,0 +1,28 @@
+import { StartVerificationRequestData } from '@sinch/sdk-core';
+import { startVerification } from '../start';
+import { getVerificationIdentityFromConfig } from '../../../config';
+
+(async () => {
+ console.log('********************************');
+ console.log('* StartVerification - seamless *');
+ console.log('********************************');
+
+ const verificationIdentity = getVerificationIdentityFromConfig();
+ if (!verificationIdentity) {
+ throw new Error('No verification identity has been provided. '
+ + 'Please update your .env file or edit the ./src/verification/verifications/seamless/start-seamless.ts file');
+ }
+
+ const requestData: StartVerificationRequestData = {
+ initiateVerificationRequestBody: {
+ identity: {
+ type: 'number',
+ endpoint: verificationIdentity,
+ },
+ method: 'seamless',
+ reference: `test-reference-for-seamless-verification_${verificationIdentity}`,
+ },
+ };
+
+ await startVerification(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/sms/report-with-id_sms.ts b/examples/simple-examples/src/verification/verifications/sms/report-with-id_sms.ts
new file mode 100644
index 00000000..af422324
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/sms/report-with-id_sms.ts
@@ -0,0 +1,36 @@
+import { ReportVerificationByIdRequestData } from '@sinch/sdk-core';
+import {
+ getVerificationCodeFromConfig,
+ getVerificationIdFromConfig,
+} from '../../../config';
+import { reportWithId } from '../report-with-id';
+
+(async () => {
+ console.log('*********************************');
+ console.log('* ReportVerificationById - SMS *');
+ console.log('*********************************');
+
+ const verificationId = getVerificationIdFromConfig();
+ if (!verificationId) {
+ throw new Error('No verification id has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/sms/report-with-id_sms.ts file');
+ }
+
+ const verificationCode = getVerificationCodeFromConfig();
+ if (!verificationCode) {
+ throw new Error('No verification code has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/sms/report-with-id_sms.ts file');
+ }
+
+ const requestData: ReportVerificationByIdRequestData = {
+ id: verificationId,
+ verificationReportRequestBody: {
+ method: 'sms',
+ sms: {
+ code: verificationCode,
+ },
+ },
+ };
+
+ await reportWithId(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/sms/report-with-identity_sms.ts b/examples/simple-examples/src/verification/verifications/sms/report-with-identity_sms.ts
new file mode 100644
index 00000000..72c86bce
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/sms/report-with-identity_sms.ts
@@ -0,0 +1,36 @@
+import { ReportVerificationByIdentityRequestData } from '@sinch/sdk-core';
+import {
+ getVerificationCodeFromConfig,
+ getVerificationIdentityFromConfig,
+} from '../../../config';
+import { reportWithIdentity } from '../report-with-identity';
+
+(async () => {
+ console.log('***************************************');
+ console.log('* ReportVerificationByIdentity - SMS *');
+ console.log('***************************************');
+
+ const verificationIdentity = getVerificationIdentityFromConfig();
+ if (!verificationIdentity) {
+ throw new Error('No verification identity has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/sms/report-with-identity_sms.ts file');
+ }
+
+ const verificationCode = getVerificationCodeFromConfig();
+ if (!verificationCode) {
+ throw new Error('No verification code has been provided. Please update your .env file '
+ + 'or edit the ./src/verification/verifications/sms/report-with-identity_sms.ts file');
+ }
+
+ const requestData: ReportVerificationByIdentityRequestData = {
+ endpoint: verificationIdentity,
+ verificationReportRequestBody: {
+ method: 'sms',
+ sms: {
+ code: verificationCode,
+ },
+ },
+ };
+
+ await reportWithIdentity(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/sms/start_sms.ts b/examples/simple-examples/src/verification/verifications/sms/start_sms.ts
new file mode 100644
index 00000000..0a1e6c5c
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/sms/start_sms.ts
@@ -0,0 +1,28 @@
+import { StartVerificationRequestData } from '@sinch/sdk-core';
+import { startVerification } from '../start';
+import { getVerificationIdentityFromConfig } from '../../../config';
+
+(async () => {
+ console.log('***************************');
+ console.log('* StartVerification - SMS *');
+ console.log('***************************');
+
+ const verificationIdentity = getVerificationIdentityFromConfig();
+ if (!verificationIdentity) {
+ throw new Error('No verification identity has been provided. '
+ + 'Please update your .env file or edit the ./src/verification/verifications/sms/start_sms.ts file');
+ }
+
+ const requestData: StartVerificationRequestData = {
+ initiateVerificationRequestBody: {
+ identity: {
+ type: 'number',
+ endpoint: verificationIdentity,
+ },
+ method: 'sms',
+ reference: `test-reference-for-sms-verification_${verificationIdentity}`,
+ },
+ };
+
+ await startVerification(requestData);
+})();
diff --git a/examples/simple-examples/src/verification/verifications/start.ts b/examples/simple-examples/src/verification/verifications/start.ts
new file mode 100644
index 00000000..fdedd375
--- /dev/null
+++ b/examples/simple-examples/src/verification/verifications/start.ts
@@ -0,0 +1,21 @@
+import { StartVerificationRequestData } from '@sinch/sdk-core';
+import { getPrintFormat, initVerificationClient, printFullResponse } from '../../config';
+
+export const startVerification = async (requestData: StartVerificationRequestData) => {
+ const sinchClient = initVerificationClient();
+ let response;
+ try {
+ response = await sinchClient.verification.verifications.start(requestData);
+ } catch (error) {
+ console.error(`Impossible to start the verification for the number ${requestData.initiateVerificationRequestBody.identity.endpoint}`);
+ throw error;
+ }
+
+ const printFormat = getPrintFormat(process.argv);
+
+ if (printFormat === 'pretty') {
+ console.log(`Verification ID = ${response.id}`);
+ } else {
+ printFullResponse(response);
+ }
+};
diff --git a/examples/simple-examples/tsconfig.json b/examples/simple-examples/tsconfig.json
new file mode 100644
index 00000000..52f99567
--- /dev/null
+++ b/examples/simple-examples/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "CommonJS",
+ "moduleResolution": "node",
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "baseUrl": "./",
+ "strict": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "incremental": true,
+ "composite": true,
+ "paths": {
+ "@sinch/sdk-core": ["../../packages/sdk-core"]
+ }
+ }
+}
diff --git a/examples/simple-examples/yarn.lock b/examples/simple-examples/yarn.lock
new file mode 100644
index 00000000..719c51b9
--- /dev/null
+++ b/examples/simple-examples/yarn.lock
@@ -0,0 +1,347 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@cspotcode/source-map-support@^0.8.0":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
+ integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
+ dependencies:
+ "@jridgewell/trace-mapping" "0.3.9"
+
+"@jridgewell/resolve-uri@^3.0.3":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+ integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
+"@jridgewell/sourcemap-codec@^1.4.10":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@0.3.9":
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
+ integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.0.3"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+
+"@tsconfig/node10@^1.0.7":
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
+ integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
+
+"@tsconfig/node12@^1.0.7":
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
+ integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
+
+"@tsconfig/node14@^1.0.0":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
+ integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
+
+"@tsconfig/node16@^1.0.2":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9"
+ integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==
+
+"@types/node@^20.8.7":
+ version "20.8.8"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.8.tgz#adee050b422061ad5255fc38ff71b2bb96ea2a0e"
+ integrity sha512-YRsdVxq6OaLfmR9Hy816IMp33xOBjfyOgUd77ehqg96CFywxAPbDbXvAsuN2KVg2HOT8Eh6uAfU+l4WffwPVrQ==
+ dependencies:
+ undici-types "~5.25.1"
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+acorn-walk@^8.1.1:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
+ integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
+
+acorn@^8.4.1:
+ version "8.10.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
+ integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
+
+anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+arg@^4.1.0:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
+ integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+binary-extensions@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
+chokidar@^3.5.2:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+create-require@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
+ integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
+
+debug@^3.2.7:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
+ dependencies:
+ ms "^2.1.1"
+
+diff@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+ integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
+dotenv@^16.3.1:
+ version "16.3.1"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
+ integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
+
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+fsevents@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+ignore-by-default@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
+ integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
+
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-glob@^4.0.1, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+make-error@^1.1.1:
+ version "1.3.6"
+ resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
+ integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
+
+minimatch@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+nodemon@^2.0.13:
+ version "2.0.22"
+ resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258"
+ integrity sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==
+ dependencies:
+ chokidar "^3.5.2"
+ debug "^3.2.7"
+ ignore-by-default "^1.0.1"
+ minimatch "^3.1.2"
+ pstree.remy "^1.1.8"
+ semver "^5.7.1"
+ simple-update-notifier "^1.0.7"
+ supports-color "^5.5.0"
+ touch "^3.1.0"
+ undefsafe "^2.0.5"
+
+nopt@~1.0.10:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
+ integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
+ dependencies:
+ abbrev "1"
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+picomatch@^2.0.4, picomatch@^2.2.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pstree.remy@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
+ integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+semver@^5.7.1:
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
+
+semver@~7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
+ integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
+
+simple-update-notifier@^1.0.7:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82"
+ integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==
+ dependencies:
+ semver "~7.0.0"
+
+supports-color@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+touch@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
+ integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
+ dependencies:
+ nopt "~1.0.10"
+
+ts-node@^10.9.1:
+ version "10.9.1"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
+ integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
+ dependencies:
+ "@cspotcode/source-map-support" "^0.8.0"
+ "@tsconfig/node10" "^1.0.7"
+ "@tsconfig/node12" "^1.0.7"
+ "@tsconfig/node14" "^1.0.0"
+ "@tsconfig/node16" "^1.0.2"
+ acorn "^8.4.1"
+ acorn-walk "^8.1.1"
+ arg "^4.1.0"
+ create-require "^1.1.0"
+ diff "^4.0.1"
+ make-error "^1.1.1"
+ v8-compile-cache-lib "^3.0.1"
+ yn "3.1.1"
+
+typescript@^5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
+ integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
+
+undefsafe@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
+ integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
+
+undici-types@~5.25.1:
+ version "5.25.3"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3"
+ integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==
+
+v8-compile-cache-lib@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
+ integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
+
+yn@3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
+ integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
diff --git a/jest.config.ts b/jest.config.ts
new file mode 100644
index 00000000..abfc5a28
--- /dev/null
+++ b/jest.config.ts
@@ -0,0 +1,33 @@
+import type { Config } from '@jest/types';
+
+const config: Config.InitialOptions = {
+ coverageDirectory: '/coverage/',
+ coveragePathIgnorePatterns: ['node_modules', '/packages/**/tests'],
+ projects: [
+ {
+ displayName: 'SDK-Client',
+ testMatch: ['/packages/sdk-client/tests/**/*.test.ts'],
+ coveragePathIgnorePatterns: ['node_modules', 'tests'],
+ },
+ {
+ displayName: 'Numbers',
+ testMatch: ['/packages/numbers/tests/**/*.test.ts'],
+ coveragePathIgnorePatterns: ['node_modules', 'tests'],
+ },
+ {
+ displayName: 'SMS',
+ testMatch: ['/packages/sms/tests/**/*.test.ts'],
+ coveragePathIgnorePatterns: ['node_modules', 'tests'],
+ },
+ {
+ displayName: 'Verification',
+ testMatch: ['/packages/verification/tests/**/*.test.ts'],
+ coveragePathIgnorePatterns: ['node_modules', 'tests'],
+ },
+ ],
+ moduleNameMapper: {
+ '@sinch/(.+)': '/packages/$1/src',
+ },
+};
+
+export default config;
diff --git a/lerna.json b/lerna.json
new file mode 100644
index 00000000..d8a067fb
--- /dev/null
+++ b/lerna.json
@@ -0,0 +1,5 @@
+{
+ "packages": ["packages/*", "examples/*"],
+ "npmClient": "yarn",
+ "version": "independent"
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..aafec9c4
--- /dev/null
+++ b/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "sinch-sdk-node",
+ "private": true,
+ "version": "0.0.0",
+ "description": "Sinch server SDK for Node.js. Check the README to know which APIs are supported",
+ "repository": "git://github.com/sinch/sinch-sdk-node-monorepo.git",
+ "author": "Sinch",
+ "license": "Apache 2.0",
+ "workspaces": [
+ "packages/*",
+ "examples/*"
+ ],
+ "scripts": {
+ "lerna": "lerna",
+ "bootstrap": "npx lerna bootstrap",
+ "build": "lerna run build",
+ "test": "jest"
+ },
+ "keywords": [],
+ "devDependencies": {
+ "@babel/core": "^7.23.3",
+ "@babel/preset-env": "^7.23.3",
+ "@babel/preset-typescript": "^7.23.3",
+ "@types/jest": "^29.5.1",
+ "@typescript-eslint/eslint-plugin": "^6.9.0",
+ "@typescript-eslint/parser": "^6.9.0",
+ "babel-jest": "^29.7.0",
+ "eslint": "8.52.0",
+ "eslint-config-google": "^0.14.0",
+ "eslint-config-prettier": "^9.0.0",
+ "eslint-plugin-deprecation": "^2.0.0",
+ "eslint-plugin-jest": "^27.4.3",
+ "eslint-plugin-jest-extended": "^2.0.0",
+ "eslint-plugin-jest-formatting": "^3.1.0",
+ "eslint-plugin-prettier": "^5.0.1",
+ "jest": "^29.5.0",
+ "lerna": "^7.4.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+}
diff --git a/packages/numbers/README.md b/packages/numbers/README.md
new file mode 100644
index 00000000..d619c1ab
--- /dev/null
+++ b/packages/numbers/README.md
@@ -0,0 +1,118 @@
+# Sinch Numbers SDK for Node.js
+
+This package contains the Sinch Numbers SDK for Node.js for use with [Sinch APIs](https://developers.sinch.com/). To use it, you will need a Sinch account. Please [sign up](https://dashboard.sinch.com/signup) or [log in](https://dashboard.sinch.com/login) if you already have one.
+
+Warning:
+**This SDK is currently available for preview purposes only. It should not be used in production environments.**
+
+## Installation
+
+We recommend to use this SDK as part of the `@sinch/sdk-core` package as it will take care about the authentication plugins to use.
+
+However, it's still possible to use this SDK standalone is you need to access the Numbers API only.
+
+### With NPM
+
+```bash
+npm install @sinch/numbers
+```
+
+### With Yarn
+
+```bash
+yarn add @sinch/numbers
+```
+
+## Usage
+
+### Credentials
+
+The `Numbers` API uses the Sinch unified authentication with OAuth2. You will need to provide the following credentials:
+ - projectId: can be found in the [Account Dashboard](https://dashboard.sinch.com/settings/access-keys)
+ - keyId:: can be found in your Access key list in the [Account Dashboard](https://dashboard.sinch.com/settings/access-keys)
+ - keySecret: can be found **ONLY** when generating a new access key: keep it safe!
+
+### As part of the Sinch SDK
+
+If you are using this SDK as part of the Sinch SDK (`@sinch/sdk-core`) you can access it as the `numbers` property of the client that you would have instantiated.
+
+```typescript
+import {
+ AvailableNumber,
+ GetAvailableNumberRequestData,
+ SinchClient,
+ SinchClientParameters,
+} from '@sinch/sdk-core';
+
+const credentials: SinchClientParameters = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+};
+
+const sinch = new SinchClient(credentials);
+
+const requestData: GetAvailableNumberRequestData = {
+ phoneNumber: '+17813334444',
+};
+
+// Access the 'numbers' domain registered on the Sinch Client
+const availabilityResult: AvailableNumber
+ = await sinch.numbers.availableNumber.checkAvailability(requestData);
+```
+
+### Standalone
+
+The SDK can be used standalone if you need to use only the Numbers APIs.
+
+```typescript
+import {
+ SinchClientParameters,
+} from '@sinch/sdk-client';
+import {
+ AvailableNumber,
+ GetAvailableNumberRequestData,
+ Numbers,
+ SinchClientParameters,
+} from '@sinch/numbers';
+
+const credentials: SinchClientParameters = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+};
+
+// Declare the 'numbers' service in a standalone way
+const numbers = new Numbers(options);
+
+const requestData: GetAvailableNumberRequestData = {
+ phoneNumber: '+17813334444',
+};
+
+// Use the standalone declaration of the 'numbers' domain
+const availabilityResult: AvailableNumber
+ = await numbers.availableNumber.checkAvailability(requestData);
+```
+
+## Promises
+
+All the methods that interact with the Sinch APIs use Promises. You can use `await` in an `async` method to wait for the response or you can resolve them yourself with `then()` / `catch()`.
+
+```typescript
+// Method 1: Wait for the Promise to complete
+let availabilityResult: AvailableNumber;
+try {
+ availabilityResult = await sinch.numbers.availableNumber.checkAvailability(requestData);
+ console.log(`Phone number: ${availabilityResult.phoneNumber} - Type: ${availabilityResult.type}`);
+} catch (error: any) {
+ console.error(`ERROR ${error.statusCode}: the phone number ${requestData.phoneNumber} is not available`);
+}
+
+// Method 2: Resolve the promise
+sinch.numbers.availableNumber.checkAvailability(requestData)
+ .then(response => console.log(`Phone number: ${response.phoneNumber} - Type: ${response.type}`))
+ .catch(error => console.error(`ERROR ${error.statusCode}: the phone number ${requestData.phoneNumber} is not available`));
+```
+
+## Contact
+Developer Experience team: [devexp@sinch.com](mailto:devexp@sinch.com)
diff --git a/packages/numbers/package.json b/packages/numbers/package.json
new file mode 100644
index 00000000..52312abe
--- /dev/null
+++ b/packages/numbers/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "@sinch/numbers",
+ "version": "0.0.0",
+ "description": "Sinch Numbers API",
+ "homepage": "",
+ "repository": {
+ "type": "git",
+ "url": ""
+ },
+ "license": "Apache-2.0",
+ "author": "Sinch",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": "./dist/index.js",
+ "require": "./dist/index.js"
+ }
+ },
+ "directories": {
+ "src": "dist",
+ "test": "tests"
+ },
+ "files": ["/dist"],
+ "scripts": {
+ "build": "yarn run clean && yarn run compile",
+ "clean": "rimraf dist tsconfig.tsbuildinfo",
+ "compile": "tsc -p tsconfig.build.json && tsc -p tsconfig.tests.json && rimraf dist/tests && rimraf tsconfig.build.tsbuildinfo"
+ },
+ "dependencies": {
+ "@sinch/sdk-client": "^0.0.0"
+ },
+ "devDependencies": {},
+ "publishConfig": {
+ "directory": "dist"
+ }
+}
diff --git a/packages/numbers/src/index.ts b/packages/numbers/src/index.ts
new file mode 100644
index 00000000..20936a85
--- /dev/null
+++ b/packages/numbers/src/index.ts
@@ -0,0 +1,3 @@
+export * from './models';
+export * from './rest';
+export * from '@sinch/sdk-client';
diff --git a/packages/numbers/src/models/index.ts b/packages/numbers/src/models/index.ts
new file mode 100644
index 00000000..5b98253d
--- /dev/null
+++ b/packages/numbers/src/models/index.ts
@@ -0,0 +1 @@
+export * from './v1';
diff --git a/packages/numbers/src/models/v1/active-number-request/active-number-request.ts b/packages/numbers/src/models/v1/active-number-request/active-number-request.ts
new file mode 100644
index 00000000..9d578519
--- /dev/null
+++ b/packages/numbers/src/models/v1/active-number-request/active-number-request.ts
@@ -0,0 +1,21 @@
+/**
+ * Model: ActiveNumberRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { SMSConfiguration } from '../sms-configuration';
+import { VoiceConfiguration } from '../voice-configuration';
+
+/**
+ * The phone number that has been rented by a customer and assigned to a project.
+ */
+export interface ActiveNumberRequest {
+ /** User supplied name for the phone number. */
+ displayName?: string;
+ /** @see SMSConfiguration */
+ smsConfiguration?: SMSConfiguration;
+ /** @see VoiceConfiguration */
+ voiceConfiguration?: VoiceConfiguration;
+}
diff --git a/packages/numbers/src/models/v1/active-number-request/index.ts b/packages/numbers/src/models/v1/active-number-request/index.ts
new file mode 100644
index 00000000..131e1f49
--- /dev/null
+++ b/packages/numbers/src/models/v1/active-number-request/index.ts
@@ -0,0 +1 @@
+export type { ActiveNumberRequest } from './active-number-request';
diff --git a/packages/numbers/src/models/v1/active-number/active-number.ts b/packages/numbers/src/models/v1/active-number/active-number.ts
new file mode 100644
index 00000000..6495febf
--- /dev/null
+++ b/packages/numbers/src/models/v1/active-number/active-number.ts
@@ -0,0 +1,43 @@
+/**
+ * Model: ActiveNumber
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { Money } from '../money';
+import { SMSConfiguration } from '../sms-configuration';
+import { VoiceConfiguration } from '../voice-configuration';
+import { CapabilitiesEnum, NumberTypeEnum } from '../enums';
+
+/**
+ * The phone number that has been rented by a customer and assigned to a project.
+ */
+export interface ActiveNumber {
+ /** The phone number in E.164 format with leading `+`. Example: `+12025550134`. */
+ phoneNumber?: string;
+ /** Project ID. Your project ID can be found on your Sinch Customer Dashboard. */
+ projectId?: string;
+ /** User supplied name for the phone number. */
+ displayName?: string;
+ /** ISO 3166-1 alpha-2 country code of the phone number. Example `US`, `GB` or `SE`. */
+ regionCode?: string;
+ /** The number type. */
+ type?: NumberTypeEnum;
+ /** The capability of the number. */
+ capability?: CapabilitiesEnum[];
+ /** @see Money */
+ money?: Money;
+ /** How often the recurring price is charged in months. */
+ paymentIntervalMonths?: number;
+ /** The date of the next charge. */
+ nextChargeDate?: Date | null;
+ /** The timestamp when the subscription will expire if an expiration date has been set. */
+ expireAt?: Date | null;
+ /** @see SMSConfiguration */
+ smsConfiguration?: SMSConfiguration;
+ /** @see VoiceConfiguration */
+ voiceConfiguration?: VoiceConfiguration;
+ /** The active number\'s callback URL to be called for provisioning / deprovisioning updates */
+ callbackUrl?: string;
+}
diff --git a/packages/numbers/src/models/v1/active-number/index.ts b/packages/numbers/src/models/v1/active-number/index.ts
new file mode 100644
index 00000000..61c3295f
--- /dev/null
+++ b/packages/numbers/src/models/v1/active-number/index.ts
@@ -0,0 +1 @@
+export type { ActiveNumber } from './active-number';
diff --git a/packages/numbers/src/models/v1/active-numbers-response/active-numbers-response.ts b/packages/numbers/src/models/v1/active-numbers-response/active-numbers-response.ts
new file mode 100644
index 00000000..227bbf7e
--- /dev/null
+++ b/packages/numbers/src/models/v1/active-numbers-response/active-numbers-response.ts
@@ -0,0 +1,18 @@
+/**
+ * Model: ActiveNumbersResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ActiveNumber } from '../active-number';
+
+/**
+ * Response message to list your active phone numbers.
+ */
+export interface ActiveNumbersResponse {
+ /** List of numbers associated to the client project specified in `ListActiveNumbers`. */
+ activeNumbers?: ActiveNumber[];
+ nextPageToken?: string;
+ totalSize?: number;
+}
diff --git a/packages/numbers/src/models/v1/active-numbers-response/index.ts b/packages/numbers/src/models/v1/active-numbers-response/index.ts
new file mode 100644
index 00000000..af225735
--- /dev/null
+++ b/packages/numbers/src/models/v1/active-numbers-response/index.ts
@@ -0,0 +1 @@
+export type { ActiveNumbersResponse } from './active-numbers-response';
diff --git a/packages/numbers/src/models/v1/available-number/available-number.ts b/packages/numbers/src/models/v1/available-number/available-number.ts
new file mode 100644
index 00000000..ddd1d072
--- /dev/null
+++ b/packages/numbers/src/models/v1/available-number/available-number.ts
@@ -0,0 +1,30 @@
+/**
+ * Model: AvailableNumber
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { Money } from '../money';
+
+/**
+ * The phone numbers that are available to be rented in the Sinch Customer Dashboard or via the public numbers API.
+ */
+export interface AvailableNumber {
+ /** The phone number in E.164 format with leading `+`. Example `+12025550134`. */
+ phoneNumber?: string;
+ /** ISO 3166-1 alpha-2 country code of the phone number. Example: `US`, `GB` or `SE`. */
+ regionCode?: string;
+ /** The number type. */
+ type?: string;
+ /** The capability of the number. */
+ capability?: string[];
+ /** @see Money */
+ setupPrice?: Money;
+ /** @see Money */
+ monthlyPrice?: Money;
+ /** How often the recurring price is charged in months. */
+ paymentIntervalMonths?: number;
+ /** Whether or not supplementary documentation will be required to complete the number rental. */
+ supportingDocumentationRequired?: boolean;
+}
diff --git a/packages/numbers/src/models/v1/available-number/index.ts b/packages/numbers/src/models/v1/available-number/index.ts
new file mode 100644
index 00000000..412544b3
--- /dev/null
+++ b/packages/numbers/src/models/v1/available-number/index.ts
@@ -0,0 +1 @@
+export type { AvailableNumber } from './available-number';
diff --git a/packages/numbers/src/models/v1/available-numbers-response/available-numbers-response.ts b/packages/numbers/src/models/v1/available-numbers-response/available-numbers-response.ts
new file mode 100644
index 00000000..136ef00c
--- /dev/null
+++ b/packages/numbers/src/models/v1/available-numbers-response/available-numbers-response.ts
@@ -0,0 +1,16 @@
+/**
+ * Model: AvailableNumbersResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { AvailableNumber } from '../available-number';
+
+/**
+ * Response message to list available phone numbers.
+ */
+export interface AvailableNumbersResponse {
+ /** List of available phone numbers. */
+ availableNumbers?: AvailableNumber[];
+}
diff --git a/packages/numbers/src/models/v1/available-numbers-response/index.ts b/packages/numbers/src/models/v1/available-numbers-response/index.ts
new file mode 100644
index 00000000..767c75cf
--- /dev/null
+++ b/packages/numbers/src/models/v1/available-numbers-response/index.ts
@@ -0,0 +1 @@
+export type { AvailableNumbersResponse } from './available-numbers-response';
diff --git a/packages/numbers/src/models/v1/available-region/available-region.ts b/packages/numbers/src/models/v1/available-region/available-region.ts
new file mode 100644
index 00000000..38852ce7
--- /dev/null
+++ b/packages/numbers/src/models/v1/available-region/available-region.ts
@@ -0,0 +1,18 @@
+/**
+ * Model: AvailableRegion
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+/**
+ * A region for which numbers are provided.
+ */
+export interface AvailableRegion {
+ /** ISO 3166-1 alpha-2 region code. Examples: `US`, `GB` or `SE`. */
+ regionCode?: string;
+ /** Display name of the region. Examples: United States, United Kingdom or Sweden. */
+ regionName?: string;
+ /** A list of the different number types available. Examples: `MOBILE` or `LOCAL`. */
+ types?: string[];
+}
diff --git a/packages/numbers/src/models/v1/available-region/index.ts b/packages/numbers/src/models/v1/available-region/index.ts
new file mode 100644
index 00000000..f33589ab
--- /dev/null
+++ b/packages/numbers/src/models/v1/available-region/index.ts
@@ -0,0 +1 @@
+export type { AvailableRegion } from './available-region';
diff --git a/packages/numbers/src/models/v1/bad-request/bad-request.ts b/packages/numbers/src/models/v1/bad-request/bad-request.ts
new file mode 100644
index 00000000..cfb192d5
--- /dev/null
+++ b/packages/numbers/src/models/v1/bad-request/bad-request.ts
@@ -0,0 +1,17 @@
+/**
+ * Model: BadRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { FieldViolation } from '../field-violation';
+
+export interface BadRequest {
+ /** @see TypeEnum */
+ type?: TypeEnum;
+ /** List of FieldViolations */
+ fieldViolations?: FieldViolation[];
+}
+
+export type TypeEnum = 'BadRequest';
diff --git a/packages/numbers/src/models/v1/bad-request/index.ts b/packages/numbers/src/models/v1/bad-request/index.ts
new file mode 100644
index 00000000..95242d8a
--- /dev/null
+++ b/packages/numbers/src/models/v1/bad-request/index.ts
@@ -0,0 +1 @@
+export type { BadRequest } from './bad-request';
diff --git a/packages/numbers/src/models/v1/callback-configuration-update/callback-configuration-update.ts b/packages/numbers/src/models/v1/callback-configuration-update/callback-configuration-update.ts
new file mode 100644
index 00000000..a6d69a28
--- /dev/null
+++ b/packages/numbers/src/models/v1/callback-configuration-update/callback-configuration-update.ts
@@ -0,0 +1,14 @@
+/**
+ * Model: CallbackConfigurationUpdate
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+/**
+ * The request to update the callbacks configuration for the current project
+ */
+export interface CallbackConfigurationUpdate {
+ /** The HMAC secret to be updated for the specified project */
+ hmacSecret?: string;
+}
diff --git a/packages/numbers/src/models/v1/callback-configuration-update/index.ts b/packages/numbers/src/models/v1/callback-configuration-update/index.ts
new file mode 100644
index 00000000..340db0d6
--- /dev/null
+++ b/packages/numbers/src/models/v1/callback-configuration-update/index.ts
@@ -0,0 +1 @@
+export type { CallbackConfigurationUpdate } from './callback-configuration-update';
diff --git a/packages/numbers/src/models/v1/callback-configuration/callback-configuration.ts b/packages/numbers/src/models/v1/callback-configuration/callback-configuration.ts
new file mode 100644
index 00000000..de7ba74f
--- /dev/null
+++ b/packages/numbers/src/models/v1/callback-configuration/callback-configuration.ts
@@ -0,0 +1,14 @@
+/**
+ * Model: CallbackConfiguration
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+/**
+ * Response message containing the callbacks configuration for a specific project
+ */
+export interface CallbackConfiguration {
+ projectId?: string;
+ hmacSecret?: string;
+}
diff --git a/packages/numbers/src/models/v1/callback-configuration/index.ts b/packages/numbers/src/models/v1/callback-configuration/index.ts
new file mode 100644
index 00000000..5547e496
--- /dev/null
+++ b/packages/numbers/src/models/v1/callback-configuration/index.ts
@@ -0,0 +1 @@
+export type { CallbackConfiguration } from './callback-configuration';
diff --git a/packages/numbers/src/models/v1/enums.ts b/packages/numbers/src/models/v1/enums.ts
new file mode 100644
index 00000000..a39298a5
--- /dev/null
+++ b/packages/numbers/src/models/v1/enums.ts
@@ -0,0 +1,19 @@
+export type { TypeEnum as BadRequestTypeEnum } from './bad-request/bad-request';
+export type {
+ CodeEnum as InternalErrorErrorCodeEnum,
+ StatusEnum as InternalErrorErrorStatusEnum,
+} from './internal-error-error/internal-error-error';
+export type {
+ CodeEnum as InvalidArgumentErrorCodeEnum,
+ StatusEnum as InvalidArgumentErrorStatusEnum,
+} from './invalid-argument-error/invalid-argument-error';
+export type {
+ CodeEnum as NotFoundErrorCodeEnum,
+ StatusEnum as NotFoundErrorStatusEnum,
+} from './not-found-error/not-found-error';
+
+export type NumberTypeEnum = 'MOBILE' |'LOCAL' |'TOLL_FREE';
+
+export type SearchPatternEnum = 'START' | 'CONTAINS' | 'END';
+
+export type CapabilitiesEnum = 'SMS' | 'VOICE';
diff --git a/packages/numbers/src/models/v1/field-violation/field-violation.ts b/packages/numbers/src/models/v1/field-violation/field-violation.ts
new file mode 100644
index 00000000..eccf3dda
--- /dev/null
+++ b/packages/numbers/src/models/v1/field-violation/field-violation.ts
@@ -0,0 +1,11 @@
+/**
+ * Model: FieldViolation
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+export interface FieldViolation {
+ field?: string;
+ description?: string;
+}
diff --git a/packages/numbers/src/models/v1/field-violation/index.ts b/packages/numbers/src/models/v1/field-violation/index.ts
new file mode 100644
index 00000000..c2f46268
--- /dev/null
+++ b/packages/numbers/src/models/v1/field-violation/index.ts
@@ -0,0 +1 @@
+export type { FieldViolation } from './field-violation';
diff --git a/packages/numbers/src/models/v1/index.ts b/packages/numbers/src/models/v1/index.ts
new file mode 100644
index 00000000..4d0d1ef7
--- /dev/null
+++ b/packages/numbers/src/models/v1/index.ts
@@ -0,0 +1,33 @@
+export * from './active-number';
+export * from './active-number-request';
+export * from './active-numbers-response';
+export * from './available-number';
+export * from './available-numbers-response';
+export * from './available-region';
+export * from './bad-request';
+export * from './callback-configuration';
+export * from './callback-configuration-update';
+export * from './field-violation';
+export * from './internal-error';
+export * from './internal-error-error';
+export * from './invalid-argument';
+export * from './invalid-argument-error';
+export * from './list-available-number-request';
+export * from './list-available-regions-response';
+export * from './money';
+export * from './not-found';
+export * from './not-found-error';
+export * from './number-pattern-pattern';
+export * from './number-pattern-search-pattern';
+export * from './provisioning-status';
+export * from './rent-any-number-request';
+export * from './rent-any-number-request-sms-configuration';
+export * from './rent-any-number-request-voice-configuration';
+export * from './rent-number-request';
+export * from './sms-configuration';
+export * from './scheduled-provisioning';
+export * from './scheduled-voice-provisioning';
+export * from './search-pattern';
+export * from './sms-error-code';
+export * from './voice-configuration';
+export * from './enums';
diff --git a/packages/numbers/src/models/v1/internal-error-error/index.ts b/packages/numbers/src/models/v1/internal-error-error/index.ts
new file mode 100644
index 00000000..c32324e4
--- /dev/null
+++ b/packages/numbers/src/models/v1/internal-error-error/index.ts
@@ -0,0 +1 @@
+export type { InternalErrorError } from './internal-error-error';
diff --git a/packages/numbers/src/models/v1/internal-error-error/internal-error-error.ts b/packages/numbers/src/models/v1/internal-error-error/internal-error-error.ts
new file mode 100644
index 00000000..50af5acf
--- /dev/null
+++ b/packages/numbers/src/models/v1/internal-error-error/internal-error-error.ts
@@ -0,0 +1,19 @@
+/**
+ * Model: InternalErrorError
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+export interface InternalErrorError {
+ /** @see CodeEnum */
+ code?: CodeEnum;
+ message?: string;
+ /** @see StatusEnum */
+ status?: StatusEnum;
+ /** List of objects */
+ details?: object[];
+}
+
+export type CodeEnum = '500';
+export type StatusEnum = 'INTERNAL' | 'UNKNOWN';
diff --git a/packages/numbers/src/models/v1/internal-error/index.ts b/packages/numbers/src/models/v1/internal-error/index.ts
new file mode 100644
index 00000000..e817cbf4
--- /dev/null
+++ b/packages/numbers/src/models/v1/internal-error/index.ts
@@ -0,0 +1 @@
+export type { InternalError } from './internal-error';
diff --git a/packages/numbers/src/models/v1/internal-error/internal-error.ts b/packages/numbers/src/models/v1/internal-error/internal-error.ts
new file mode 100644
index 00000000..dd20b941
--- /dev/null
+++ b/packages/numbers/src/models/v1/internal-error/internal-error.ts
@@ -0,0 +1,13 @@
+/**
+ * Model: InternalError
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { InternalErrorError } from '../internal-error-error';
+
+export interface InternalError {
+ /** @see InternalErrorError */
+ error?: InternalErrorError;
+}
diff --git a/packages/numbers/src/models/v1/invalid-argument-error/index.ts b/packages/numbers/src/models/v1/invalid-argument-error/index.ts
new file mode 100644
index 00000000..e6ec0c99
--- /dev/null
+++ b/packages/numbers/src/models/v1/invalid-argument-error/index.ts
@@ -0,0 +1 @@
+export type { InvalidArgumentError } from './invalid-argument-error';
diff --git a/packages/numbers/src/models/v1/invalid-argument-error/invalid-argument-error.ts b/packages/numbers/src/models/v1/invalid-argument-error/invalid-argument-error.ts
new file mode 100644
index 00000000..2f7f99ad
--- /dev/null
+++ b/packages/numbers/src/models/v1/invalid-argument-error/invalid-argument-error.ts
@@ -0,0 +1,21 @@
+/**
+ * Model: InvalidArgumentError
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { BadRequest } from '../bad-request';
+
+export interface InvalidArgumentError {
+ /** @see CodeEnum */
+ code?: CodeEnum;
+ message?: string;
+ /** @see StatusEnum */
+ status?: StatusEnum;
+ /** List of BadRequests */
+ details?: BadRequest[];
+}
+
+export type CodeEnum = '400';
+export type StatusEnum = 'INVALID_ARGUMENT';
diff --git a/packages/numbers/src/models/v1/invalid-argument/index.ts b/packages/numbers/src/models/v1/invalid-argument/index.ts
new file mode 100644
index 00000000..d1d7c019
--- /dev/null
+++ b/packages/numbers/src/models/v1/invalid-argument/index.ts
@@ -0,0 +1 @@
+export type { InvalidArgument } from './invalid-argument';
diff --git a/packages/numbers/src/models/v1/invalid-argument/invalid-argument.ts b/packages/numbers/src/models/v1/invalid-argument/invalid-argument.ts
new file mode 100644
index 00000000..08675ecb
--- /dev/null
+++ b/packages/numbers/src/models/v1/invalid-argument/invalid-argument.ts
@@ -0,0 +1,13 @@
+/**
+ * Model: InvalidArgument
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { InvalidArgumentError } from '../invalid-argument-error';
+
+export interface InvalidArgument {
+ /** @see InvalidArgumentError */
+ error?: InvalidArgumentError;
+}
diff --git a/packages/numbers/src/models/v1/list-available-number-request/index.ts b/packages/numbers/src/models/v1/list-available-number-request/index.ts
new file mode 100644
index 00000000..7c0f2f40
--- /dev/null
+++ b/packages/numbers/src/models/v1/list-available-number-request/index.ts
@@ -0,0 +1 @@
+export type { ListAvailableNumberRequest } from './list-available-number-request';
diff --git a/packages/numbers/src/models/v1/list-available-number-request/list-available-number-request.ts b/packages/numbers/src/models/v1/list-available-number-request/list-available-number-request.ts
new file mode 100644
index 00000000..89f4c22c
--- /dev/null
+++ b/packages/numbers/src/models/v1/list-available-number-request/list-available-number-request.ts
@@ -0,0 +1,25 @@
+/**
+ * Model: ListAvailableNumberRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { NumberPatternPattern } from '../number-pattern-pattern';
+import { NumberPatternSearchPattern } from '../number-pattern-search-pattern';
+
+/**
+ * Available numbers schema base.
+ */
+export interface ListAvailableNumberRequest {
+ /** @see NumberPatternPattern */
+ NumberPattern?: NumberPatternPattern;
+ /** @see NumberPatternSearchPattern */
+ NumberPatternSearchPattern?: NumberPatternSearchPattern;
+ /** Region code to filter by. ISO 3166-1 alpha-2 country code of the phone number. Example: `US`, `GB` or `SE`. */
+ regionCode?: string;
+ /** Number type to filter by. `MOBILE`, `LOCAL` or `TOLL_FREE`. */
+ type?: string;
+ /** Number capabilities to filter by, `SMS` and/or `VOICE`. */
+ capabilities?: string[];
+}
diff --git a/packages/numbers/src/models/v1/list-available-regions-response/index.ts b/packages/numbers/src/models/v1/list-available-regions-response/index.ts
new file mode 100644
index 00000000..b63c4c14
--- /dev/null
+++ b/packages/numbers/src/models/v1/list-available-regions-response/index.ts
@@ -0,0 +1 @@
+export type { ListAvailableRegionsResponse } from './list-available-regions-response';
diff --git a/packages/numbers/src/models/v1/list-available-regions-response/list-available-regions-response.ts b/packages/numbers/src/models/v1/list-available-regions-response/list-available-regions-response.ts
new file mode 100644
index 00000000..94330c3c
--- /dev/null
+++ b/packages/numbers/src/models/v1/list-available-regions-response/list-available-regions-response.ts
@@ -0,0 +1,16 @@
+/**
+ * Model: ListAvailableRegionsResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { AvailableRegion } from '../available-region';
+
+/**
+ * Response message to list regions for which numbers are provided.
+ */
+export interface ListAvailableRegionsResponse {
+ /** */
+ availableRegions?: AvailableRegion[];
+}
diff --git a/packages/numbers/src/models/v1/money/index.ts b/packages/numbers/src/models/v1/money/index.ts
new file mode 100644
index 00000000..6b156e03
--- /dev/null
+++ b/packages/numbers/src/models/v1/money/index.ts
@@ -0,0 +1 @@
+export type { Money } from './money';
diff --git a/packages/numbers/src/models/v1/money/money.ts b/packages/numbers/src/models/v1/money/money.ts
new file mode 100644
index 00000000..dbd14246
--- /dev/null
+++ b/packages/numbers/src/models/v1/money/money.ts
@@ -0,0 +1,16 @@
+/**
+ * Model: Money
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+/**
+ * An object giving details on currency code and the amount charged.
+ */
+export interface Money {
+ /** The 3-letter currency code defined in ISO 4217. */
+ currencyCode?: string;
+ /** The amount in decimal form. For example `2.00`. There are no guarantees on the precision unless documented by the message origin. The amount cannot be updated and is read-only. */
+ amount?: string;
+}
diff --git a/packages/numbers/src/models/v1/not-found-error/index.ts b/packages/numbers/src/models/v1/not-found-error/index.ts
new file mode 100644
index 00000000..7e0a7de1
--- /dev/null
+++ b/packages/numbers/src/models/v1/not-found-error/index.ts
@@ -0,0 +1 @@
+export type { NotFoundError } from './not-found-error';
diff --git a/packages/numbers/src/models/v1/not-found-error/not-found-error.ts b/packages/numbers/src/models/v1/not-found-error/not-found-error.ts
new file mode 100644
index 00000000..ba8224f8
--- /dev/null
+++ b/packages/numbers/src/models/v1/not-found-error/not-found-error.ts
@@ -0,0 +1,19 @@
+/**
+ * Model: NotFoundError
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+export interface NotFoundError {
+ /** @see CodeEnum */
+ code?: CodeEnum;
+ message?: string;
+ /** @see StatusEnum */
+ status?: StatusEnum;
+ /** List of objects */
+ details?: object[];
+}
+
+export type CodeEnum = '404';
+export type StatusEnum = 'NOT_FOUND';
diff --git a/packages/numbers/src/models/v1/not-found/index.ts b/packages/numbers/src/models/v1/not-found/index.ts
new file mode 100644
index 00000000..af0b74f7
--- /dev/null
+++ b/packages/numbers/src/models/v1/not-found/index.ts
@@ -0,0 +1 @@
+export type { NotFound } from './not-found';
diff --git a/packages/numbers/src/models/v1/not-found/not-found.ts b/packages/numbers/src/models/v1/not-found/not-found.ts
new file mode 100644
index 00000000..923aa48c
--- /dev/null
+++ b/packages/numbers/src/models/v1/not-found/not-found.ts
@@ -0,0 +1,13 @@
+/**
+ * Model: NotFound
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { NotFoundError } from '../not-found-error';
+
+export interface NotFound {
+ /** @see NotFoundError */
+ error?: NotFoundError;
+}
diff --git a/packages/numbers/src/models/v1/number-pattern-pattern/index.ts b/packages/numbers/src/models/v1/number-pattern-pattern/index.ts
new file mode 100644
index 00000000..2491bdb3
--- /dev/null
+++ b/packages/numbers/src/models/v1/number-pattern-pattern/index.ts
@@ -0,0 +1 @@
+export type { NumberPatternPattern } from './number-pattern-pattern';
diff --git a/packages/numbers/src/models/v1/number-pattern-pattern/number-pattern-pattern.ts b/packages/numbers/src/models/v1/number-pattern-pattern/number-pattern-pattern.ts
new file mode 100644
index 00000000..c29f826d
--- /dev/null
+++ b/packages/numbers/src/models/v1/number-pattern-pattern/number-pattern-pattern.ts
@@ -0,0 +1,16 @@
+/**
+ * Model: NumberPatternPattern
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { SearchPattern } from '../search-pattern';
+
+/**
+ * Sequence of digits to search for.
+ */
+export interface NumberPatternPattern {
+ /** @see SearchPattern */
+ NumberPattern?: SearchPattern;
+}
diff --git a/packages/numbers/src/models/v1/number-pattern-search-pattern/index.ts b/packages/numbers/src/models/v1/number-pattern-search-pattern/index.ts
new file mode 100644
index 00000000..d9f5e1ee
--- /dev/null
+++ b/packages/numbers/src/models/v1/number-pattern-search-pattern/index.ts
@@ -0,0 +1 @@
+export type { NumberPatternSearchPattern } from './number-pattern-search-pattern';
diff --git a/packages/numbers/src/models/v1/number-pattern-search-pattern/number-pattern-search-pattern.ts b/packages/numbers/src/models/v1/number-pattern-search-pattern/number-pattern-search-pattern.ts
new file mode 100644
index 00000000..9d5aabf2
--- /dev/null
+++ b/packages/numbers/src/models/v1/number-pattern-search-pattern/number-pattern-search-pattern.ts
@@ -0,0 +1,20 @@
+/**
+ * Model: NumberPatternSearchPattern
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+/**
+ * Search pattern to apply. Options include, `START`, `CONTAIN`, and `END`.
+ */
+export interface NumberPatternSearchPattern {
+ /** The pattern to apply to searches. Options include, `START`, `CONTAIN`, and `END`. */
+ NumberPatternSearchPattern?: NumberPatternSearchPatternEnum;
+}
+
+export enum NumberPatternSearchPatternEnum {
+ START = 'START',
+ CONTAINS = 'CONTAINS',
+ END = 'END',
+}
diff --git a/packages/numbers/src/models/v1/provisioning-status/index.ts b/packages/numbers/src/models/v1/provisioning-status/index.ts
new file mode 100644
index 00000000..94b0968c
--- /dev/null
+++ b/packages/numbers/src/models/v1/provisioning-status/index.ts
@@ -0,0 +1 @@
+export type { ProvisioningStatus } from './provisioning-status';
diff --git a/packages/numbers/src/models/v1/provisioning-status/provisioning-status.ts b/packages/numbers/src/models/v1/provisioning-status/provisioning-status.ts
new file mode 100644
index 00000000..46ad6f18
--- /dev/null
+++ b/packages/numbers/src/models/v1/provisioning-status/provisioning-status.ts
@@ -0,0 +1,15 @@
+/**
+ * Model: ProvisioningStatus
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+/**
+ * The provisioning status. It will be either `WAITING`, `IN_PROGRESS` or `FAILED`. If the provisioning fails, a reason for the failure will be provided.
+ */
+export type ProvisioningStatus =
+ | 'PROVISIONING_STATUS_UNSPECIFIED'
+ | 'WAITING'
+ | 'IN_PROGRESS'
+ | 'FAILED';
diff --git a/packages/numbers/src/models/v1/rent-any-number-request-sms-configuration/index.ts b/packages/numbers/src/models/v1/rent-any-number-request-sms-configuration/index.ts
new file mode 100644
index 00000000..e814aada
--- /dev/null
+++ b/packages/numbers/src/models/v1/rent-any-number-request-sms-configuration/index.ts
@@ -0,0 +1 @@
+export type { RentAnyNumberRequestSmsConfiguration } from './rent-any-number-request-sms-configuration';
diff --git a/packages/numbers/src/models/v1/rent-any-number-request-sms-configuration/rent-any-number-request-sms-configuration.ts b/packages/numbers/src/models/v1/rent-any-number-request-sms-configuration/rent-any-number-request-sms-configuration.ts
new file mode 100644
index 00000000..8b55a3a6
--- /dev/null
+++ b/packages/numbers/src/models/v1/rent-any-number-request-sms-configuration/rent-any-number-request-sms-configuration.ts
@@ -0,0 +1,13 @@
+/**
+ * Model: RentAnyNumberRequestSmsConfiguration
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+export interface RentAnyNumberRequestSmsConfiguration {
+ /** The SMS service that the number will be linked to. The `servicePlanId` can be found in the [Sinch Customer Dashboard](https://dashboard.sinch.com/sms/api/rest). */
+ servicePlanId: string;
+ /** The 10DLC campaign ID that the number will be linked to. */
+ campaignId?: string;
+}
diff --git a/packages/numbers/src/models/v1/rent-any-number-request-voice-configuration/index.ts b/packages/numbers/src/models/v1/rent-any-number-request-voice-configuration/index.ts
new file mode 100644
index 00000000..5595bfcf
--- /dev/null
+++ b/packages/numbers/src/models/v1/rent-any-number-request-voice-configuration/index.ts
@@ -0,0 +1 @@
+export type { RentAnyNumberRequestVoiceConfiguration } from './rent-any-number-request-voice-configuration';
diff --git a/packages/numbers/src/models/v1/rent-any-number-request-voice-configuration/rent-any-number-request-voice-configuration.ts b/packages/numbers/src/models/v1/rent-any-number-request-voice-configuration/rent-any-number-request-voice-configuration.ts
new file mode 100644
index 00000000..ae946bf8
--- /dev/null
+++ b/packages/numbers/src/models/v1/rent-any-number-request-voice-configuration/rent-any-number-request-voice-configuration.ts
@@ -0,0 +1,11 @@
+/**
+ * Model: RentAnyNumberRequestVoiceConfiguration
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+export interface RentAnyNumberRequestVoiceConfiguration {
+ /** Your app ID for the Voice API. The `appId` can be found in your Sinch Customer Dashboard under Voice, then apps. */
+ appId: string;
+}
diff --git a/packages/numbers/src/models/v1/rent-any-number-request/index.ts b/packages/numbers/src/models/v1/rent-any-number-request/index.ts
new file mode 100644
index 00000000..5513013b
--- /dev/null
+++ b/packages/numbers/src/models/v1/rent-any-number-request/index.ts
@@ -0,0 +1 @@
+export type { RentAnyNumberRequest } from './rent-any-number-request';
diff --git a/packages/numbers/src/models/v1/rent-any-number-request/rent-any-number-request.ts b/packages/numbers/src/models/v1/rent-any-number-request/rent-any-number-request.ts
new file mode 100644
index 00000000..a3a9c9c7
--- /dev/null
+++ b/packages/numbers/src/models/v1/rent-any-number-request/rent-any-number-request.ts
@@ -0,0 +1,29 @@
+/**
+ * Model: RentAnyNumberRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { RentAnyNumberRequestSmsConfiguration } from '../rent-any-number-request-sms-configuration';
+import { RentAnyNumberRequestVoiceConfiguration } from '../rent-any-number-request-voice-configuration';
+import { SearchPattern } from '../search-pattern';
+import { CapabilitiesEnum, NumberTypeEnum } from '../enums';
+
+/**
+ * Request message for searching and renting in one go any number that matches the search criteria.
+ */
+export interface RentAnyNumberRequest {
+ /** @see SearchPattern */
+ numberPattern?: SearchPattern;
+ /** Region code to filter by. ISO 3166-1 alpha-2 country code of the phone number. Example: `US`, `GB` or `SE`. */
+ regionCode: string;
+ /** Number type to filter by. `MOBILE`, `LOCAL` or `TOLL_FREE`. */
+ type: NumberTypeEnum;
+ /** Number capabilities to filter by, `SMS` and/or `VOICE`. */
+ capabilities?: CapabilitiesEnum[];
+ /** @see RentAnyNumberRequestSmsConfiguration */
+ smsConfiguration?: RentAnyNumberRequestSmsConfiguration;
+ /** @see RentAnyNumberRequestVoiceConfiguration */
+ voiceConfiguration?: RentAnyNumberRequestVoiceConfiguration;
+}
diff --git a/packages/numbers/src/models/v1/rent-number-request/index.ts b/packages/numbers/src/models/v1/rent-number-request/index.ts
new file mode 100644
index 00000000..0a1c216f
--- /dev/null
+++ b/packages/numbers/src/models/v1/rent-number-request/index.ts
@@ -0,0 +1 @@
+export type { RentNumberRequest } from './rent-number-request';
diff --git a/packages/numbers/src/models/v1/rent-number-request/rent-number-request.ts b/packages/numbers/src/models/v1/rent-number-request/rent-number-request.ts
new file mode 100644
index 00000000..57ab0aac
--- /dev/null
+++ b/packages/numbers/src/models/v1/rent-number-request/rent-number-request.ts
@@ -0,0 +1,21 @@
+/**
+ * Model: RentNumberRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { RentAnyNumberRequestSmsConfiguration } from '../rent-any-number-request-sms-configuration';
+import { RentAnyNumberRequestVoiceConfiguration } from '../rent-any-number-request-voice-configuration';
+
+/**
+ * Request message for renting a phone number.
+ */
+export interface RentNumberRequest {
+ /** @see RentAnyNumberRequestSmsConfiguration */
+ smsConfiguration?: RentAnyNumberRequestSmsConfiguration;
+ /** @see RentAnyNumberRequestVoiceConfiguration */
+ voiceConfiguration?: RentAnyNumberRequestVoiceConfiguration;
+ /** The callback URL to be called for a rented number provisioning / deprovisioning operations */
+ callbackUrl?: string;
+}
diff --git a/packages/numbers/src/models/v1/scheduled-provisioning/index.ts b/packages/numbers/src/models/v1/scheduled-provisioning/index.ts
new file mode 100644
index 00000000..31ff99a9
--- /dev/null
+++ b/packages/numbers/src/models/v1/scheduled-provisioning/index.ts
@@ -0,0 +1 @@
+export type { ScheduledProvisioning } from './scheduled-provisioning';
diff --git a/packages/numbers/src/models/v1/scheduled-provisioning/scheduled-provisioning.ts b/packages/numbers/src/models/v1/scheduled-provisioning/scheduled-provisioning.ts
new file mode 100644
index 00000000..017b5245
--- /dev/null
+++ b/packages/numbers/src/models/v1/scheduled-provisioning/scheduled-provisioning.ts
@@ -0,0 +1,25 @@
+/**
+ * Model: ScheduledProvisioning
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ProvisioningStatus } from '../provisioning-status';
+import { SmsErrorCode } from '../sms-error-code';
+
+/**
+ * Represents the ongoing or failed scheduled provisioning job. This field will be empty if both the was successfully provisioned into the SMS platform and linked to the 10DLC campaign.
+ */
+export interface ScheduledProvisioning {
+ /** The SMS service plan that the scheduled provisioning job will configured with the number. */
+ servicePlanId?: string;
+ /** TCR campaign ID that the scheduled provisioning job will configure with the number. */
+ campaignId?: string;
+ /** @see ProvisioningStatus */
+ status?: ProvisioningStatus;
+ /** Timestamp when the status was last updated. */
+ lastUpdatedTime?: Date;
+ /** List of SmsErrorCodes */
+ errorCodes?: SmsErrorCode[];
+}
diff --git a/packages/numbers/src/models/v1/scheduled-voice-provisioning/index.ts b/packages/numbers/src/models/v1/scheduled-voice-provisioning/index.ts
new file mode 100644
index 00000000..ae040a4d
--- /dev/null
+++ b/packages/numbers/src/models/v1/scheduled-voice-provisioning/index.ts
@@ -0,0 +1 @@
+export type { ScheduledVoiceProvisioning } from './scheduled-voice-provisioning';
diff --git a/packages/numbers/src/models/v1/scheduled-voice-provisioning/scheduled-voice-provisioning.ts b/packages/numbers/src/models/v1/scheduled-voice-provisioning/scheduled-voice-provisioning.ts
new file mode 100644
index 00000000..737e3961
--- /dev/null
+++ b/packages/numbers/src/models/v1/scheduled-voice-provisioning/scheduled-voice-provisioning.ts
@@ -0,0 +1,20 @@
+/**
+ * Model: ScheduledVoiceProvisioning
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ProvisioningStatus } from '../provisioning-status';
+
+/**
+ * Represents the ongoing or failed scheduled voice provisioning job. This field will be empty if the number was successfully provisioned provisioned for voice.
+ */
+export interface ScheduledVoiceProvisioning {
+ /** Your app ID for the Voice API. The `appId` can be found in your Sinch Customer Dashboard under Voice, then apps. */
+ appId?: string;
+ /** @see ProvisioningStatus */
+ status?: ProvisioningStatus;
+ /** Timestamp when the status was last updated. */
+ lastUpdatedTime?: string;
+}
diff --git a/packages/numbers/src/models/v1/search-pattern/index.ts b/packages/numbers/src/models/v1/search-pattern/index.ts
new file mode 100644
index 00000000..1f216f15
--- /dev/null
+++ b/packages/numbers/src/models/v1/search-pattern/index.ts
@@ -0,0 +1 @@
+export type { SearchPattern } from './search-pattern';
diff --git a/packages/numbers/src/models/v1/search-pattern/search-pattern.ts b/packages/numbers/src/models/v1/search-pattern/search-pattern.ts
new file mode 100644
index 00000000..dbe3d555
--- /dev/null
+++ b/packages/numbers/src/models/v1/search-pattern/search-pattern.ts
@@ -0,0 +1,14 @@
+/**
+ * Model: SearchPattern
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+import { SearchPatternEnum } from '../enums';
+
+export interface SearchPattern {
+ /** Sequence of digits to search for. */
+ pattern?: string;
+ /** The pattern to apply to searches. */
+ searchPattern?: SearchPatternEnum;
+}
diff --git a/packages/numbers/src/models/v1/sms-configuration/index.ts b/packages/numbers/src/models/v1/sms-configuration/index.ts
new file mode 100644
index 00000000..6dd3fce9
--- /dev/null
+++ b/packages/numbers/src/models/v1/sms-configuration/index.ts
@@ -0,0 +1 @@
+export type { SMSConfiguration } from './sms-configuration';
diff --git a/packages/numbers/src/models/v1/sms-configuration/sms-configuration.ts b/packages/numbers/src/models/v1/sms-configuration/sms-configuration.ts
new file mode 100644
index 00000000..318ba196
--- /dev/null
+++ b/packages/numbers/src/models/v1/sms-configuration/sms-configuration.ts
@@ -0,0 +1,20 @@
+/**
+ * Model: SMSConfiguration
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ScheduledProvisioning } from '../scheduled-provisioning';
+
+/**
+ * The current SMS configuration for this number. Once the `servicePlanId` is sent, it enters scheduled provisioning. The status of scheduled provisioning will show under a `scheduledProvisioning` object if it\'s still running. Once processed successfully, the `servicePlanId` sent will appear directly under the `smsConfiguration` object.
+ */
+export interface SMSConfiguration {
+ /** The `servicePlanId` can be found in the Sinch Customer Dashboard. The service plan ID is what ties this number to the configured SMS service. */
+ servicePlanId: string;
+ /** Only for US virtual numbers. This campaign ID relates to 10DLC numbers. So, it is the current campaign ID for this number. The `campaignId` is found on your TCR platform. */
+ campaignId?: string;
+ /** @see ScheduledProvisioning */
+ scheduledProvisioning?: ScheduledProvisioning | null;
+}
diff --git a/packages/numbers/src/models/v1/sms-error-code/index.ts b/packages/numbers/src/models/v1/sms-error-code/index.ts
new file mode 100644
index 00000000..50ca7404
--- /dev/null
+++ b/packages/numbers/src/models/v1/sms-error-code/index.ts
@@ -0,0 +1 @@
+export type { SmsErrorCode } from './sms-error-code';
diff --git a/packages/numbers/src/models/v1/sms-error-code/sms-error-code.ts b/packages/numbers/src/models/v1/sms-error-code/sms-error-code.ts
new file mode 100644
index 00000000..5562854f
--- /dev/null
+++ b/packages/numbers/src/models/v1/sms-error-code/sms-error-code.ts
@@ -0,0 +1,29 @@
+/**
+ * Model: SmsErrorCode
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+/**
+ * The error codes that show the reason of failure of a scheduled provisioning
+ */
+export type SmsErrorCode =
+ | 'ERROR_CODE_UNSPECIFIED'
+ | 'INTERNAL_ERROR'
+ | 'SMS_PROVISIONING_FAILED'
+ | 'CAMPAIGN_PROVISIONING_FAILED'
+ | 'CAMPAIGN_NOT_AVAILABLE'
+ | 'EXCEEDED_10DLC_LIMIT'
+ | 'NUMBER_PROVISIONING_FAILED'
+ | 'PARTNER_SERVICE_UNAVAILABLE'
+ | 'CAMPAIGN_PENDING_ACCEPTANCE'
+ | 'MNO_SHARING_ERROR'
+ | 'CAMPAIGN_EXPIRED'
+ | 'CAMPAIGN_MNO_REJECTED'
+ | 'CAMPAIGN_MNO_SUSPENDED'
+ | 'CAMPAIGN_MNO_REVIEW'
+ | 'INSUFFICIENT_BALANCE'
+ | 'MOCK_CAMPAIGN_NOT_ALLOWED'
+ | 'TFN_NOT_ALLOWED'
+ | 'INVALID_NNID';
diff --git a/packages/numbers/src/models/v1/voice-configuration/index.ts b/packages/numbers/src/models/v1/voice-configuration/index.ts
new file mode 100644
index 00000000..c48d6541
--- /dev/null
+++ b/packages/numbers/src/models/v1/voice-configuration/index.ts
@@ -0,0 +1 @@
+export type { VoiceConfiguration } from './voice-configuration';
diff --git a/packages/numbers/src/models/v1/voice-configuration/voice-configuration.ts b/packages/numbers/src/models/v1/voice-configuration/voice-configuration.ts
new file mode 100644
index 00000000..7e0a6dd6
--- /dev/null
+++ b/packages/numbers/src/models/v1/voice-configuration/voice-configuration.ts
@@ -0,0 +1,20 @@
+/**
+ * Model: VoiceConfiguration
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ScheduledVoiceProvisioning } from '../scheduled-voice-provisioning';
+
+/**
+ * The current voice configuration for this number. During scheduled provisioning, the app ID value may be empty in a response if it is still processing or if it has failed. The status of scheduled provisioning will show under a `scheduledVoiceProvisioning` object if it\'s still running. Once processed successfully, the `appId` sent will appear directly under the `voiceConfiguration` object.
+ */
+export interface VoiceConfiguration {
+ /** Your app ID for the Voice API. The `appId` can be found in your Sinch Customer Dashboard under Voice, then apps. */
+ appId?: string;
+ /** Timestamp when the status was last updated. */
+ lastUpdatedTime?: Date | null;
+ /** @see ScheduledVoiceProvisioning */
+ scheduledVoiceProvisioning?: ScheduledVoiceProvisioning | null;
+}
diff --git a/packages/numbers/src/rest/index.ts b/packages/numbers/src/rest/index.ts
new file mode 100644
index 00000000..5b98253d
--- /dev/null
+++ b/packages/numbers/src/rest/index.ts
@@ -0,0 +1 @@
+export * from './v1';
diff --git a/packages/numbers/src/rest/v1/active-number/active-number-api.jest.fixture.ts b/packages/numbers/src/rest/v1/active-number/active-number-api.jest.fixture.ts
new file mode 100644
index 00000000..e375f213
--- /dev/null
+++ b/packages/numbers/src/rest/v1/active-number/active-number-api.jest.fixture.ts
@@ -0,0 +1,30 @@
+import { ActiveNumber } from '../../../models';
+import {
+ ActiveNumberApi,
+ GetActiveNumberRequestData,
+ ListActiveNumbersRequestData,
+ ReleaseNumberRequestData,
+ UpdateActiveNumberRequestData,
+} from './active-number-api';
+import { ApiListPromise } from '@sinch/sdk-client';
+
+export class ActiveNumberApiFixture implements Partial> {
+
+ /**
+ * Fixture associated to function get
+ */
+ public get: jest.Mock, [GetActiveNumberRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function list
+ */
+ public list: jest.Mock, [ListActiveNumbersRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function release
+ */
+ public release: jest.Mock, [ReleaseNumberRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function update
+ */
+ public update: jest.Mock, [UpdateActiveNumberRequestData]> = jest.fn();
+}
+
diff --git a/packages/numbers/src/rest/v1/active-number/active-number-api.ts b/packages/numbers/src/rest/v1/active-number/active-number-api.ts
new file mode 100644
index 00000000..8f2296f1
--- /dev/null
+++ b/packages/numbers/src/rest/v1/active-number/active-number-api.ts
@@ -0,0 +1,229 @@
+import {
+ ActiveNumber,
+ ActiveNumberRequest,
+ CapabilitiesEnum,
+ NumberTypeEnum,
+ SearchPatternEnum,
+} from '../../../models';
+import {
+ ApiListPromise,
+ PaginatedApiProperties,
+ PaginationEnum,
+ RequestBody,
+ SinchClientParameters,
+ buildPageResultPromise,
+ createIteratorMethodsForPagination,
+} from '@sinch/sdk-client';
+import { NumbersApi } from '../numbers-api';
+
+export interface GetActiveNumberRequestData {
+ /** Output only. The phone number in E.164 format with leading `+`. */
+ phoneNumber: string;
+}
+
+export interface ListActiveNumbersRequestData {
+ /** Region code to filter by. ISO 3166-1 alpha-2 country code of the phone number. Example: `US`, `GB` or `SE`. */
+ regionCode: string;
+ /** Number type to filter by. Options include, `MOBILE`, `LOCAL` or `TOLL_FREE`. */
+ type: NumberTypeEnum;
+ /** Sequence of digits to search for. If you prefer or need certain digits in sequential order, you can enter the sequence of numbers here. For example, `2020`. */
+ 'numberPattern.pattern'?: string;
+ /** Search pattern to apply. The options are, `START`, `CONTAIN`, and `END`. */
+ 'numberPattern.searchPattern'?: SearchPatternEnum;
+ /** Number capabilities to filter by, `SMS` and/or `VOICE`. */
+ capability?: Array;
+ /** The maximum number of items to return. */
+ pageSize?: number;
+ /** The next page token value returned from a previous List request, if any. */
+ pageToken?: string;
+ /** Supported fields for ordering by `phoneNumber` or `displayName`. */
+ orderBy?: string;
+}
+export interface ReleaseNumberRequestData {
+ /** Output only. The phone number in E.164 format with leading `+`. */
+ phoneNumber: string;
+}
+export interface UpdateActiveNumberRequestData {
+ /** Output only. The phone number in E.164 format with leading `+`. */
+ phoneNumber: string;
+ /** The number body to be updated. */
+ activeNumberRequestBody?: ActiveNumberRequest;
+}
+
+export class ActiveNumberApi extends NumbersApi {
+
+ /**
+ * Initialize your interface with the provided API client.
+ *
+ * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client.
+ */
+ constructor(sinchClientParameters: SinchClientParameters) {
+ super(sinchClientParameters, 'ActiveNumberApi');
+ }
+
+ /**
+ * Get active Number
+ * Get a virtual number
+ * @param {GetActiveNumberRequestData} data - The data to provide to the API call.
+ */
+ public async get(data: GetActiveNumberRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams
+ = this.client.extractQueryParams(
+ data,
+ [] as never[],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/activeNumbers/${data['phoneNumber']}`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'GET',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'GetActiveNumber',
+ });
+ }
+
+ /**
+ * List active numbers
+ * Lists all virtual numbers for a project.
+ * @param {ListActiveNumbersRequestData} data - The data to provide to the API call.
+ * @return {ApiListPromise}
+ */
+ public list(data: ListActiveNumbersRequestData): ApiListPromise {
+ this.client = this.getSinchClient();
+ const getParams
+ = this.client.extractQueryParams(data, [
+ 'regionCode',
+ 'numberPattern.pattern',
+ 'numberPattern.searchPattern',
+ 'type',
+ 'capability',
+ 'pageSize',
+ 'pageToken',
+ 'orderBy',
+ ]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/activeNumbers`;
+
+ const requestOptionsPromise = this.client.prepareOptions(
+ basePathUrl, 'GET', getParams, headers, body || undefined);
+
+ const operationProperties: PaginatedApiProperties = {
+ pagination: PaginationEnum.TOKEN,
+ apiName: this.apiName,
+ operationId: 'ListActiveNumbers',
+ dataKey: 'activeNumbers',
+ };
+
+ // Create the promise containing the response wrapped as a PageResult
+ const listPromise = buildPageResultPromise(
+ this.client,
+ requestOptionsPromise,
+ operationProperties);
+
+ // Add properties to the Promise to offer the possibility to use it as an iterator
+ Object.assign(
+ listPromise,
+ createIteratorMethodsForPagination(
+ this.client, requestOptionsPromise, listPromise, operationProperties),
+ );
+
+ return listPromise as ApiListPromise;
+ }
+
+ /**
+ * Release number
+ * With this endpoint, you can cancel your subscription for a specific virtual phone number.
+ * @param {ReleaseNumberRequestData} data - The data to provide to the API call.
+ */
+ public async release(data: ReleaseNumberRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(
+ data,
+ [] as never[],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/activeNumbers/${data['phoneNumber']}:release`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'POST',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'ReleaseNumber',
+ });
+ }
+
+ /**
+ * Update active number
+ * Update a virtual phone number. For example: you can configure SMS/Voice services or set a friendly name. To update the name that displays, modify the `displayName` parameter.
+ * You'll use `smsConfiguration` to update your SMS configuration and `voiceConfiguration` to update the voice configuration.
+ * @param {UpdateActiveNumberRequestData} data - The data to provide to the API call.
+ */
+ public async update(data: UpdateActiveNumberRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams
+ = this.client.extractQueryParams(
+ data,
+ [] as never[],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['activeNumberRequestBody']
+ ? JSON.stringify(data['activeNumberRequestBody'])
+ : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/activeNumbers/${data['phoneNumber']}`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'PATCH',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'UpdateActiveNumber',
+ });
+ }
+}
diff --git a/packages/numbers/src/rest/v1/active-number/index.ts b/packages/numbers/src/rest/v1/active-number/index.ts
new file mode 100644
index 00000000..99dd9583
--- /dev/null
+++ b/packages/numbers/src/rest/v1/active-number/index.ts
@@ -0,0 +1,2 @@
+export * from './active-number-api';
+export * from './active-number-api.jest.fixture';
diff --git a/packages/numbers/src/rest/v1/available-number/available-number-api.jest.fixture.ts b/packages/numbers/src/rest/v1/available-number/available-number-api.jest.fixture.ts
new file mode 100644
index 00000000..020d86c8
--- /dev/null
+++ b/packages/numbers/src/rest/v1/available-number/available-number-api.jest.fixture.ts
@@ -0,0 +1,30 @@
+import { ActiveNumber, AvailableNumber, AvailableNumbersResponse } from '../../../models';
+import {
+ AvailableNumberApi,
+ GetAvailableNumberRequestData,
+ ListAvailableNumbersRequestData,
+ RentAnyNumberRequestData,
+ RentNumberRequestData,
+} from './available-number-api';
+
+export class AvailableNumberApiFixture implements Partial> {
+
+ /**
+ * Fixture associated to function checkAvailability
+ */
+ public checkAvailability: jest.Mock, [GetAvailableNumberRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function list
+ */
+ public list:
+ jest.Mock, [ListAvailableNumbersRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function rentAny
+ */
+ public rentAny: jest.Mock, [RentAnyNumberRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function rent
+ */
+ public rent: jest.Mock, [RentNumberRequestData]> = jest.fn();
+}
+
diff --git a/packages/numbers/src/rest/v1/available-number/available-number-api.ts b/packages/numbers/src/rest/v1/available-number/available-number-api.ts
new file mode 100644
index 00000000..86afff9f
--- /dev/null
+++ b/packages/numbers/src/rest/v1/available-number/available-number-api.ts
@@ -0,0 +1,210 @@
+import {
+ ActiveNumber,
+ AvailableNumber,
+ AvailableNumbersResponse,
+ CapabilitiesEnum,
+ NumberTypeEnum,
+ RentAnyNumberRequest,
+ RentNumberRequest,
+ SearchPatternEnum,
+} from '../../../models';
+import {
+ RequestBody,
+ SinchClientParameters,
+} from '@sinch/sdk-client';
+import { NumbersApi } from '../numbers-api';
+
+export interface GetAvailableNumberRequestData {
+ /** Output only. The phone number in E.164 format with leading `+`. */
+ phoneNumber: string;
+}
+export interface ListAvailableNumbersRequestData {
+ /** Region code to filter by. ISO 3166-1 alpha-2 country code of the phone number. Example: `US`, `GB` or `SE`. */
+ regionCode: string;
+ /** Number type to filter by. Options include, `MOBILE`, `LOCAL` or `TOLL_FREE`. */
+ type: NumberTypeEnum;
+ /** Sequence of digits to search for. If you prefer or need certain digits in sequential order, you can enter the sequence of numbers here. For example, `2020`. */
+ 'numberPattern.pattern'?: string;
+ /** Search pattern to apply. The options are, `START`, `CONTAIN`, and `END`. */
+ 'numberPattern.searchPattern'?: SearchPatternEnum;
+ /** Number capabilities to filter by SMS and/or VOICE. When searching, indicate the `capabilities` of the number as `SMS` and/or `VOICE`. To search for a number capable of both, list both `SMS` and `VOICE`. */
+ capabilities?: Array;
+ /** Optional. The maximum number of items to return. */
+ size?: number;
+}
+export interface RentAnyNumberRequestData {
+ /** The request to search and rent a number that matches the criteria. */
+ rentAnyNumberRequestBody: RentAnyNumberRequest;
+}
+export interface RentNumberRequestData {
+ /** Output only. The phone number in E.164 format with leading `+`. */
+ phoneNumber: string;
+ /** The request to rent a number. */
+ rentNumberRequestBody: RentNumberRequest;
+}
+
+export class AvailableNumberApi extends NumbersApi {
+
+ /**
+ * Initialize your interface with the provided API client.
+ *
+ * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client.
+ */
+ constructor(sinchClientParameters: SinchClientParameters) {
+ super(sinchClientParameters, 'AvailableRegionsApi');
+ }
+
+ /**
+ * Get available number
+ * This endpoint allows you to enter a specific phone number to check if it\'s available for use. A 200 response will return the number\'s capability, setup costs, monthly costs and if supporting documentation is required.
+ * @param {GetAvailableNumberRequestData} data - The data to provide to the API call.
+ */
+ public async checkAvailability(data: GetAvailableNumberRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams
+ = this.client.extractQueryParams(
+ data,
+ [] as never[],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/availableNumbers/${data['phoneNumber']}`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'GET',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'GetAvailableNumber',
+ });
+ }
+
+ /**
+ * List available numbers
+ * Search for virtual numbers that are available for you to activate. You can filter by any property on the available number resource.
+ * @param {ListAvailableNumbersRequestData} data - The data to provide to the API call.
+ */
+ public async list(data: ListAvailableNumbersRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams
+ = this.client.extractQueryParams(data, [
+ 'numberPattern.pattern',
+ 'numberPattern.searchPattern',
+ 'regionCode',
+ 'type',
+ 'capabilities',
+ 'size',
+ ]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/availableNumbers`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'GET',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'ListAvailableNumbers',
+ });
+ }
+
+ /**
+ * Rent any number that matches the criteria
+ * Search for and activate an available Sinch virtual number all in one API call. Currently, the rentAny operation works only for US 10DLC numbers
+ * @param {RentAnyNumberRequestData} data - The data to provide to the API call.
+ */
+ public async rentAny(data: RentAnyNumberRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(
+ data,
+ [] as never[],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['rentAnyNumberRequestBody']
+ ? JSON.stringify(data['rentAnyNumberRequestBody'])
+ : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/availableNumbers:rentAny`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'POST',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'RentAnyNumber',
+ });
+ }
+
+ /**
+ * Rent an available number
+ * Activate a virtual number to use with SMS products, Voice products, or both. You'll use 'smsConfiguration' to set up your number for SMS and 'voiceConfiguration' for Voice.
+ * @param {RentNumberRequestData} data - The data to provide to the API call.
+ */
+ public async rent(data: RentNumberRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(
+ data,
+ [] as never[],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['rentNumberRequestBody']
+ ? JSON.stringify(data['rentNumberRequestBody'])
+ : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/availableNumbers/${data['phoneNumber']}:rent`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'POST',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'RentNumber',
+ });
+ }
+}
diff --git a/packages/numbers/src/rest/v1/available-number/index.ts b/packages/numbers/src/rest/v1/available-number/index.ts
new file mode 100644
index 00000000..b78a34dd
--- /dev/null
+++ b/packages/numbers/src/rest/v1/available-number/index.ts
@@ -0,0 +1,2 @@
+export * from './available-number-api';
+export * from './available-number-api.jest.fixture';
diff --git a/packages/numbers/src/rest/v1/available-regions/available-regions-api.jest.fixture.ts b/packages/numbers/src/rest/v1/available-regions/available-regions-api.jest.fixture.ts
new file mode 100644
index 00000000..cb0c825e
--- /dev/null
+++ b/packages/numbers/src/rest/v1/available-regions/available-regions-api.jest.fixture.ts
@@ -0,0 +1,12 @@
+import { ListAvailableRegionsResponse } from '../../../models';
+import { AvailableRegionsApi, ListAvailableRegionsRequestData } from './available-regions-api';
+
+export class AvailableRegionsApiFixture implements Partial> {
+
+ /**
+ * Fixture associated to function list
+ */
+ public list:
+ jest.Mock, [ListAvailableRegionsRequestData]> = jest.fn();
+}
+
diff --git a/packages/numbers/src/rest/v1/available-regions/available-regions-api.ts b/packages/numbers/src/rest/v1/available-regions/available-regions-api.ts
new file mode 100644
index 00000000..b9566be6
--- /dev/null
+++ b/packages/numbers/src/rest/v1/available-regions/available-regions-api.ts
@@ -0,0 +1,67 @@
+import { ListAvailableRegionsResponse } from '../../../models';
+import {
+ RequestBody,
+ SinchClientParameters,
+} from '@sinch/sdk-client';
+import { NumbersApi } from '../numbers-api';
+
+export type RegionNumberTypeEnum = 'NUMBER_TYPE_UNSPECIFIED' | 'MOBILE' | 'LOCAL' | 'TOLL_FREE';
+
+export interface ListAvailableRegionsRequestData {
+ /** Only returns regions for which numbers are provided with the given types v1: `MOBILE`, `LOCAL` or `TOLL_FREE`. However, you can indicate `NUMBER_TYPE_UNSPECIFIED: null` when searching.
+ * - NUMBER_TYPE_UNSPECIFIED: Null value
+ * - MOBILE: Numbers that belong to a specific range.
+ * - LOCAL: Numbers that are assigned to a specific geographic region.
+ * - TOLL_FREE: Number that are free of charge for the calling party but billed for all arriving calls.
+ */
+ types?: RegionNumberTypeEnum;
+}
+
+export class AvailableRegionsApi extends NumbersApi {
+
+ /**
+ * Initialize your interface with the provided API client.
+ *
+ * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client.
+ */
+ constructor(sinchClientParameters: SinchClientParameters) {
+ super(sinchClientParameters, 'AvailableRegionsApi');
+ }
+
+ /**
+ * List available regions
+ * Lists all regions for numbers provided for the project ID.
+ * @param {ListAvailableRegionsRequestData} data - The data to provide to the API call.
+ */
+ public async list(data: ListAvailableRegionsRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams
+ = this.client.extractQueryParams(data, [
+ 'types',
+ ]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/availableRegions`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'GET',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'ListAvailableRegions',
+ });
+ }
+
+}
diff --git a/packages/numbers/src/rest/v1/available-regions/index.ts b/packages/numbers/src/rest/v1/available-regions/index.ts
new file mode 100644
index 00000000..251c5d3e
--- /dev/null
+++ b/packages/numbers/src/rest/v1/available-regions/index.ts
@@ -0,0 +1,2 @@
+export * from './available-regions-api';
+export * from './available-regions-api.jest.fixture';
diff --git a/packages/numbers/src/rest/v1/callback-configuration/callback-configuration-api.jest.fixture.ts b/packages/numbers/src/rest/v1/callback-configuration/callback-configuration-api.jest.fixture.ts
new file mode 100644
index 00000000..f2fa8736
--- /dev/null
+++ b/packages/numbers/src/rest/v1/callback-configuration/callback-configuration-api.jest.fixture.ts
@@ -0,0 +1,21 @@
+import { CallbackConfiguration } from '../../../models';
+import {
+ CallbackConfigurationApi,
+ GetCallbackConfigurationRequestData,
+ UpdateCallbackConfigurationRequestData,
+} from './callback-configuration-api';
+
+export class CallbackConfigurationApiFixture implements Partial> {
+
+ /**
+ * Fixture associated to function get
+ */
+ public get:
+ jest.Mock, [GetCallbackConfigurationRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function update
+ */
+ public update:
+ jest.Mock, [UpdateCallbackConfigurationRequestData]> = jest.fn();
+}
+
diff --git a/packages/numbers/src/rest/v1/callback-configuration/callback-configuration-api.ts b/packages/numbers/src/rest/v1/callback-configuration/callback-configuration-api.ts
new file mode 100644
index 00000000..3767298e
--- /dev/null
+++ b/packages/numbers/src/rest/v1/callback-configuration/callback-configuration-api.ts
@@ -0,0 +1,100 @@
+import { CallbackConfiguration, CallbackConfigurationUpdate } from '../../../models';
+import {
+ RequestBody,
+ SinchClientParameters,
+} from '@sinch/sdk-client';
+import { NumbersApi } from '../numbers-api';
+
+export interface GetCallbackConfigurationRequestData {}
+export interface UpdateCallbackConfigurationRequestData {
+ /** The callback configuration details to be updated. */
+ callbackConfigurationUpdateRequestBody?: CallbackConfigurationUpdate;
+}
+
+export class CallbackConfigurationApi extends NumbersApi {
+
+ /**
+ * Initialize your interface with the provided API client.
+ *
+ * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client.
+ */
+ constructor(sinchClientParameters: SinchClientParameters) {
+ super(sinchClientParameters, 'CallbackConfigurationApi');
+ }
+
+ /**
+ * Get callbacks configuration
+ * Returns the callbacks configuration for the specified project
+ * @param {GetCallbackConfigurationRequestData} data - The data to provide to the API call.
+ */
+ public async get(data: GetCallbackConfigurationRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams
+ = this.client.extractQueryParams(
+ data,
+ [] as never[],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/callbackConfiguration`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'GET',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'GetCallbackConfiguration',
+ });
+ }
+
+ /**
+ * Update callback configuration
+ * Updates the callbacks configuration for the specified project
+ * @param {UpdateCallbackConfigurationRequestData} data - The data to provide to the API call.
+ */
+ public async update(data: UpdateCallbackConfigurationRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams
+ = this.client.extractQueryParams(
+ data,
+ [] as never[],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['callbackConfigurationUpdateRequestBody']
+ ? JSON.stringify(data['callbackConfigurationUpdateRequestBody'])
+ : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/callbackConfiguration`;
+
+ const requestOptions = await this.client.prepareOptions(
+ basePathUrl,
+ 'PATCH',
+ getParams,
+ headers,
+ body || undefined,
+ );
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'UpdateCallbackConfiguration',
+ });
+ }
+}
diff --git a/packages/numbers/src/rest/v1/callback-configuration/index.ts b/packages/numbers/src/rest/v1/callback-configuration/index.ts
new file mode 100644
index 00000000..83b746bc
--- /dev/null
+++ b/packages/numbers/src/rest/v1/callback-configuration/index.ts
@@ -0,0 +1,2 @@
+export * from './callback-configuration-api';
+export * from './callback-configuration-api.jest.fixture';
diff --git a/packages/numbers/src/rest/v1/enums.ts b/packages/numbers/src/rest/v1/enums.ts
new file mode 100644
index 00000000..cb0ff5c3
--- /dev/null
+++ b/packages/numbers/src/rest/v1/enums.ts
@@ -0,0 +1 @@
+export {};
diff --git a/packages/numbers/src/rest/v1/index.ts b/packages/numbers/src/rest/v1/index.ts
new file mode 100644
index 00000000..5d260fe3
--- /dev/null
+++ b/packages/numbers/src/rest/v1/index.ts
@@ -0,0 +1,5 @@
+export * from './active-number';
+export * from './available-number';
+export * from './available-regions';
+export * from './callback-configuration';
+export * from './numbers';
diff --git a/packages/numbers/src/rest/v1/numbers-api.ts b/packages/numbers/src/rest/v1/numbers-api.ts
new file mode 100644
index 00000000..07d49fee
--- /dev/null
+++ b/packages/numbers/src/rest/v1/numbers-api.ts
@@ -0,0 +1,78 @@
+import {
+ Api,
+ ApiClient, ApiClientOptions,
+ ApiFetchClient,
+ SinchClientParameters,
+ Oauth2TokenRequest, UnifiedCredentials,
+} from '@sinch/sdk-client';
+
+export class NumbersApi implements Api {
+ public readonly apiName: string;
+ public client?: ApiClient;
+ private sinchClientParameters: SinchClientParameters;
+
+ constructor(sinchClientParameters: SinchClientParameters, apiName: string) {
+ this.sinchClientParameters = sinchClientParameters;
+ this.apiName = apiName;
+ }
+
+ /**
+ * Update the default basePath for the API
+ * @param {string} basePath - The new base path to use for the APIs.
+ */
+ public setBasePath(basePath: string) {
+ this.client = this.getSinchClient();
+ this.client.apiClientOptions.basePath = basePath;
+ }
+
+ /**
+ * Updates the credentials used to authenticate API requests
+ * @param {UnifiedCredentials} credentials
+ */
+ public setCredentials(credentials: UnifiedCredentials) {
+ const parametersBackup = { ...this.sinchClientParameters };
+ this.sinchClientParameters = {
+ ...parametersBackup,
+ ...credentials,
+ };
+ this.resetApiClient();
+ try {
+ this.getSinchClient();
+ } catch (error) {
+ console.error('Impossible to assign the new credentials to the Numbers API');
+ this.sinchClientParameters = parametersBackup;
+ throw error;
+ }
+ }
+
+ private resetApiClient() {
+ this.client = undefined;
+ }
+
+ /**
+ * Checks the configuration parameters are ok and initialize the API client. Once initialized, the same instance will
+ * be returned for the subsequent API calls (singleton pattern)
+ * @return {ApiClient} the API Client or throws an error in case the configuration parameters are not ok
+ * @private
+ */
+ public getSinchClient(): ApiClient {
+ if (!this.client) {
+ const apiClientOptions = this.buildApiClientOptions(this.sinchClientParameters);
+ this.client = new ApiFetchClient(apiClientOptions);
+ this.client.apiClientOptions.basePath = 'https://numbers.api.sinch.com';
+ }
+ return this.client;
+ }
+
+ private buildApiClientOptions(params: SinchClientParameters): ApiClientOptions {
+ if (!params.projectId || !params.keyId || !params.keySecret) {
+ throw new Error('Invalid configuration for the Numbers API: '
+ + '"projectId", "keyId" and "keySecret" values must be provided');
+ }
+ return {
+ projectId: params.projectId,
+ requestPlugins: [new Oauth2TokenRequest( params.keyId, params.keySecret)],
+ useServicePlanId: false,
+ };
+ }
+}
diff --git a/packages/numbers/src/rest/v1/numbers.ts b/packages/numbers/src/rest/v1/numbers.ts
new file mode 100644
index 00000000..b4cb09b6
--- /dev/null
+++ b/packages/numbers/src/rest/v1/numbers.ts
@@ -0,0 +1,37 @@
+/**
+ * Domain: numbers
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+import { SinchClientParameters } from '@sinch/sdk-client';
+import { AvailableRegionsApi } from './available-regions';
+import { CallbackConfigurationApi } from './callback-configuration';
+import { AvailableNumberApi } from './available-number';
+import { ActiveNumberApi } from './active-number';
+
+export class Numbers {
+ public readonly availableRegions: AvailableRegionsApi;
+ public readonly callbackConfiguration: CallbackConfigurationApi;
+ public readonly availableNumber: AvailableNumberApi;
+ public readonly activeNumber: ActiveNumberApi;
+
+ constructor(params: SinchClientParameters) {
+ this.availableRegions = new AvailableRegionsApi(params);
+ this.callbackConfiguration = new CallbackConfigurationApi(params);
+ this.availableNumber = new AvailableNumberApi(params);
+ this.activeNumber = new ActiveNumberApi(params);
+ }
+
+ /**
+ * Update the default basePath for each API
+ *
+ * @param {string} basePath - The new base path to use for all the APIs.
+ */
+ public setBasePath(basePath: string) {
+ this.activeNumber.setBasePath(basePath);
+ this.availableNumber.setBasePath(basePath);
+ this.availableRegions.setBasePath(basePath);
+ this.callbackConfiguration.setBasePath(basePath);
+ }
+}
diff --git a/packages/numbers/tests/rest/v1/active-number/active-number-api.test.ts b/packages/numbers/tests/rest/v1/active-number/active-number-api.test.ts
new file mode 100644
index 00000000..96b17633
--- /dev/null
+++ b/packages/numbers/tests/rest/v1/active-number/active-number-api.test.ts
@@ -0,0 +1,230 @@
+import { SinchClientParameters } from '@sinch/sdk-client';
+import {
+ ActiveNumber,
+ ActiveNumberApi,
+ ActiveNumberApiFixture,
+ GetActiveNumberRequestData,
+ ListActiveNumbersRequestData,
+ ReleaseNumberRequestData,
+ UpdateActiveNumberRequestData,
+} from '../../../../src';
+
+describe('ActiveNumberApi', () => {
+ let activeNumberApi: ActiveNumberApi;
+ let fixture: ActiveNumberApiFixture;
+ let credentials: SinchClientParameters;
+
+ beforeEach(() => {
+ fixture = new ActiveNumberApiFixture();
+ credentials = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+ };
+ activeNumberApi = new ActiveNumberApi(credentials);
+ });
+
+ describe ('getActiveNumber', () => {
+ it('should make a GET request to ...', async () => {
+ // Given
+ const requestData: GetActiveNumberRequestData = {
+ phoneNumber: '+17813334444',
+ };
+ const expectedResponse: ActiveNumber = {
+ phoneNumber: '+17813334444',
+ projectId: 'projectIdFromDashboard',
+ displayName: '',
+ regionCode: 'US',
+ type: 'LOCAL',
+ capability: [
+ 'SMS',
+ 'VOICE',
+ ],
+ money: {
+ currencyCode: 'EUR',
+ amount: '1.00',
+ },
+ paymentIntervalMonths: 1,
+ nextChargeDate: new Date('2023-12-21T17:47:51.476076Z'),
+ expireAt: null,
+ smsConfiguration: {
+ servicePlanId: 'servicePlanIdFromDashboard',
+ scheduledProvisioning: null,
+ campaignId: '',
+ },
+ voiceConfiguration: {
+ appId: '',
+ scheduledVoiceProvisioning: null,
+ lastUpdatedTime: null,
+ },
+ callbackUrl: '',
+ };
+
+ // When
+ fixture.get.mockResolvedValue(expectedResponse);
+ activeNumberApi.get = fixture.get;
+ const response = await activeNumberApi.get(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.get).toHaveBeenCalledWith(requestData);
+ });
+ });
+
+ describe ('listActiveNumbers', () => {
+ it('should make a GET request to list all active numbers for a project', async () => {
+ // Given
+ const requestData: ListActiveNumbersRequestData = {
+ type: 'LOCAL',
+ regionCode: 'US',
+ };
+ const mockData: ActiveNumber[] = [
+ {
+ phoneNumber: '+17813334444',
+ projectId: 'projectIdFromDashboard',
+ displayName: '',
+ regionCode: 'US',
+ type: 'LOCAL',
+ capability: [
+ 'SMS',
+ 'VOICE',
+ ],
+ money: {
+ currencyCode: 'EUR',
+ amount: '1.00',
+ },
+ paymentIntervalMonths: 1,
+ nextChargeDate: new Date('2023-12-21T17:47:51.476076Z'),
+ expireAt: null,
+ smsConfiguration: {
+ servicePlanId: 'servicePlanIdFromDashboard',
+ scheduledProvisioning: null,
+ campaignId: '',
+ },
+ voiceConfiguration: {
+ appId: '',
+ scheduledVoiceProvisioning: null,
+ lastUpdatedTime: null,
+ },
+ callbackUrl: '',
+ },
+ ];
+ const expectedResponse = {
+ data: mockData,
+ hasNextPage: false,
+ nextPageValue: '',
+ nextPage: jest.fn(),
+ };
+
+ // When
+ fixture.list.mockResolvedValue(expectedResponse);
+ activeNumberApi.list = fixture.list;
+ const response = await activeNumberApi.list(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(response.data).toBeDefined();
+ expect(fixture.list).toHaveBeenCalledWith(requestData);
+ });
+ });
+
+ describe ('releaseNumber', () => {
+ it('should make a POST request to cancel the subscription for a specific phone number', async () => {
+ // Given
+ const requestData: ReleaseNumberRequestData = {
+ phoneNumber: '+17813334444',
+ };
+ const expectedResponse: ActiveNumber = {
+ phoneNumber: '+17813334444',
+ projectId: 'projectIdFromDashboard',
+ displayName: '',
+ regionCode: 'US',
+ type: 'LOCAL',
+ capability: [
+ 'SMS',
+ 'VOICE',
+ ],
+ money: {
+ currencyCode: 'EUR',
+ amount: '1.00',
+ },
+ paymentIntervalMonths: 1,
+ nextChargeDate: new Date('2023-12-21T17:47:51.476076Z'),
+ expireAt: new Date('2023-12-21T17:47:51.476076Z'),
+ smsConfiguration: {
+ servicePlanId: '',
+ scheduledProvisioning: null,
+ campaignId: '',
+ },
+ voiceConfiguration: {
+ appId: '',
+ scheduledVoiceProvisioning: null,
+ lastUpdatedTime: null,
+ },
+ callbackUrl: '',
+ };
+
+ // When
+ fixture.release.mockResolvedValue(expectedResponse);
+ activeNumberApi.release = fixture.release;
+ const response = await activeNumberApi.release(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.release).toHaveBeenCalledWith(requestData);
+ });
+ });
+
+ describe ('updateActiveNumber', () => {
+ it('should make a PATCH request to update an active phone number configuration', async () => {
+ // Given
+ const requestData: UpdateActiveNumberRequestData = {
+ phoneNumber: '+17813334444',
+ activeNumberRequestBody: {
+ displayName: 'Updated display name',
+ smsConfiguration: {
+ servicePlanId: 'newServicePlanId',
+ },
+ },
+ };
+ const expectedResponse: ActiveNumber = {
+ phoneNumber: '+17813334444',
+ projectId: 'projectIdFromDashboard',
+ displayName: 'Updated display name',
+ regionCode: 'US',
+ type: 'LOCAL',
+ capability: [
+ 'SMS',
+ 'VOICE',
+ ],
+ money: {
+ currencyCode: 'EUR',
+ amount: '1.00',
+ },
+ paymentIntervalMonths: 1,
+ nextChargeDate: new Date('2023-12-21T17:47:51.476076Z'),
+ expireAt: null,
+ smsConfiguration: {
+ servicePlanId: 'newServicePlanId',
+ scheduledProvisioning: null,
+ campaignId: '',
+ },
+ voiceConfiguration: {
+ appId: '',
+ scheduledVoiceProvisioning: null,
+ lastUpdatedTime: null,
+ },
+ callbackUrl: '',
+ };
+
+ // When
+ fixture.update.mockResolvedValue(expectedResponse);
+ activeNumberApi.update = fixture.update;
+ const response = await activeNumberApi.update(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.update).toHaveBeenCalledWith(requestData);
+ });
+ });
+});
diff --git a/packages/numbers/tests/rest/v1/available-number/available-number-api.test.ts b/packages/numbers/tests/rest/v1/available-number/available-number-api.test.ts
new file mode 100644
index 00000000..6f0a1649
--- /dev/null
+++ b/packages/numbers/tests/rest/v1/available-number/available-number-api.test.ts
@@ -0,0 +1,229 @@
+import { SinchClientParameters } from '@sinch/sdk-client';
+import {
+ ActiveNumber,
+ AvailableNumber,
+ AvailableNumberApi,
+ AvailableNumberApiFixture,
+ AvailableNumbersResponse,
+ GetAvailableNumberRequestData,
+ ListAvailableNumbersRequestData,
+ RentAnyNumberRequestData,
+ RentNumberRequestData,
+} from '../../../../src';
+
+describe('AvailableNumberApi', () => {
+ let availableNumberApi: AvailableNumberApi;
+ let fixture: AvailableNumberApiFixture;
+ let credentials: SinchClientParameters;
+
+ beforeEach(() => {
+ fixture = new AvailableNumberApiFixture();
+ credentials = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+ };
+ availableNumberApi = new AvailableNumberApi(credentials);
+ });
+
+ describe ('getAvailableNumber', () => {
+ it('should make a GET request to check if a phone number is available for use', async () => {
+ // Given
+ const requestData: GetAvailableNumberRequestData = {
+ phoneNumber: '+17813334444',
+ };
+ const expectedResponse: AvailableNumber = {
+ phoneNumber: '+17813334444',
+ regionCode: 'US',
+ type: 'LOCAL',
+ capability: [
+ 'SMS',
+ 'VOICE',
+ ],
+ setupPrice: {
+ currencyCode: 'EUR',
+ amount: "2.00",
+ },
+ monthlyPrice: {
+ currencyCode: 'EUR',
+ amount: '1.00',
+ },
+ paymentIntervalMonths: 1,
+ supportingDocumentationRequired: true,
+ };
+
+ // When
+ fixture.checkAvailability.mockResolvedValue(expectedResponse);
+ availableNumberApi.checkAvailability = fixture.checkAvailability;
+ const response = await availableNumberApi.checkAvailability(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.checkAvailability).toHaveBeenCalledWith(requestData);
+ });
+ });
+
+ describe ('listAvailableNumbers', () => {
+ it('should make a GET request to list the phone numbers that are available for you to activate', async () => {
+ // Given
+ const requestData: ListAvailableNumbersRequestData = {
+ regionCode: 'US',
+ type: 'LOCAL',
+ 'numberPattern.pattern': '%2B1781333',
+ 'numberPattern.searchPattern': 'START',
+ capabilities: ['SMS', 'VOICE'],
+ };
+ const expectedResponse: AvailableNumbersResponse = {
+ availableNumbers: [
+ {
+ phoneNumber: '+17813334444',
+ regionCode: 'US',
+ type: 'LOCAL',
+ capability: [
+ 'SMS',
+ 'VOICE',
+ ],
+ setupPrice: {
+ currencyCode: 'EUR',
+ amount: "2.00",
+ },
+ monthlyPrice: {
+ currencyCode: 'EUR',
+ amount: '1.00',
+ },
+ paymentIntervalMonths: 1,
+ supportingDocumentationRequired: true,
+ },
+ ],
+ };
+
+ // When
+ fixture.list.mockResolvedValue(expectedResponse);
+ availableNumberApi.list = fixture.list;
+ const response = await availableNumberApi.list(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.list).toHaveBeenCalledWith(requestData);
+ });
+ });
+
+ describe ('rentAnyNumber', () => {
+ it('should make a POST request to rent any number that match the criteria', async () => {
+ // Given
+ const requestData: RentAnyNumberRequestData = {
+ rentAnyNumberRequestBody: {
+ regionCode: 'US',
+ type: 'LOCAL',
+ numberPattern: {
+ pattern: '%2B1781333',
+ searchPattern: 'START',
+ },
+ capabilities: ['SMS', 'VOICE'],
+ },
+ };
+ const expectedResponse: ActiveNumber = {
+ phoneNumber: '+17813334444',
+ projectId: 'projectIdFromDashboard',
+ displayName: '',
+ regionCode: 'US',
+ type: 'LOCAL',
+ capability: [
+ 'SMS',
+ 'VOICE',
+ ],
+ money: {
+ currencyCode: 'EUR',
+ amount: '1.00',
+ },
+ paymentIntervalMonths: 1,
+ nextChargeDate: new Date('2023-12-21T17:47:51.476076Z'),
+ expireAt: null,
+ smsConfiguration: {
+ servicePlanId: '',
+ scheduledProvisioning: {
+ servicePlanId: 'a4c187cffc754d2da37f594d46f35246',
+ status: 'WAITING',
+ lastUpdatedTime: new Date('2023-11-21T17:47:52.950101Z'),
+ campaignId: '',
+ errorCodes: [],
+ },
+ campaignId: '',
+ },
+ voiceConfiguration: {
+ appId: '',
+ scheduledVoiceProvisioning: null,
+ lastUpdatedTime: null,
+ },
+ callbackUrl: '',
+ };
+
+ // When
+ fixture.rentAny.mockResolvedValue(expectedResponse);
+ availableNumberApi.rentAny = fixture.rentAny;
+ const response = await availableNumberApi.rentAny(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.rentAny).toHaveBeenCalledWith(requestData);
+ });
+ });
+
+ describe ('rentNumber', () => {
+ it('should make a POST request to rent a number', async () => {
+ // Given
+ const requestData: RentNumberRequestData = {
+ phoneNumber: '+17813334444',
+ rentNumberRequestBody: {
+ smsConfiguration: {
+ servicePlanId: 'servicePlanIdFromSinchDashboard',
+ },
+ },
+ };
+ const expectedResponse: ActiveNumber = {
+ phoneNumber: '+17813334444',
+ projectId: 'projectIdFromDashboard',
+ displayName: '',
+ regionCode: 'US',
+ type: 'LOCAL',
+ capability: [
+ 'SMS',
+ 'VOICE',
+ ],
+ money: {
+ currencyCode: 'EUR',
+ amount: '1.00',
+ },
+ paymentIntervalMonths: 1,
+ nextChargeDate: new Date('2023-12-21T17:47:51.476076Z'),
+ expireAt: null,
+ smsConfiguration: {
+ servicePlanId: '',
+ scheduledProvisioning: {
+ servicePlanId: 'a4c187cffc754d2da37f594d46f35246',
+ status: 'WAITING',
+ lastUpdatedTime: new Date('2023-11-21T17:47:52.950101Z'),
+ campaignId: '',
+ errorCodes: [],
+ },
+ campaignId: '',
+ },
+ voiceConfiguration: {
+ appId: '',
+ scheduledVoiceProvisioning: null,
+ lastUpdatedTime: null,
+ },
+ callbackUrl: '',
+ };
+
+ // When
+ fixture.rent.mockResolvedValue(expectedResponse);
+ availableNumberApi.rent = fixture.rent;
+ const response = await availableNumberApi.rent(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.rent).toHaveBeenCalledWith(requestData);
+ });
+ });
+});
diff --git a/packages/numbers/tests/rest/v1/available-regions/available-regions-api.test.ts b/packages/numbers/tests/rest/v1/available-regions/available-regions-api.test.ts
new file mode 100644
index 00000000..a51b4369
--- /dev/null
+++ b/packages/numbers/tests/rest/v1/available-regions/available-regions-api.test.ts
@@ -0,0 +1,59 @@
+import { SinchClientParameters } from '@sinch/sdk-client';
+import {
+ AvailableRegionsApi,
+ AvailableRegionsApiFixture,
+ ListAvailableRegionsRequestData,
+ ListAvailableRegionsResponse,
+} from '../../../../src';
+
+describe('AvailableRegionsApi', () => {
+ let availableRegionsApi: AvailableRegionsApi;
+ let fixture: AvailableRegionsApiFixture;
+ let credentials: SinchClientParameters;
+
+ beforeEach(() => {
+ fixture = new AvailableRegionsApiFixture();
+ credentials = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+ };
+ availableRegionsApi = new AvailableRegionsApi(credentials);
+ });
+
+ describe ('listAvailableRegions', () => {
+ it('should make a GET request to list all regions for numbers type provided for the project ID', async () => {
+ // Given
+ const requestData: ListAvailableRegionsRequestData = {
+ types: 'LOCAL',
+ };
+ const expectedResponse: ListAvailableRegionsResponse = {
+ availableRegions: [
+ {
+ regionCode: 'AR',
+ regionName: 'Argentina',
+ types: [
+ 'LOCAL',
+ ],
+ },
+ {
+ regionCode: 'US',
+ regionName: 'United States',
+ types: [
+ 'LOCAL',
+ ],
+ },
+ ],
+ };
+
+ // When
+ fixture.list.mockResolvedValue(expectedResponse);
+ availableRegionsApi.list = fixture.list;
+ const response = await availableRegionsApi.list(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.list).toHaveBeenCalledWith(requestData);
+ });
+ });
+});
diff --git a/packages/numbers/tests/rest/v1/callback-configuration/callback-configuration-api.test.ts b/packages/numbers/tests/rest/v1/callback-configuration/callback-configuration-api.test.ts
new file mode 100644
index 00000000..efe5ecbf
--- /dev/null
+++ b/packages/numbers/tests/rest/v1/callback-configuration/callback-configuration-api.test.ts
@@ -0,0 +1,67 @@
+import { SinchClientParameters } from '@sinch/sdk-client';
+import {
+ CallbackConfiguration,
+ CallbackConfigurationApi,
+ CallbackConfigurationApiFixture,
+ GetCallbackConfigurationRequestData, UpdateCallbackConfigurationRequestData,
+} from '../../../../src';
+
+describe('CallbackConfigurationApi', () => {
+ let callbackConfigurationApi: CallbackConfigurationApi;
+ let fixture: CallbackConfigurationApiFixture;
+ let credentials: SinchClientParameters;
+
+ beforeEach(() => {
+ fixture = new CallbackConfigurationApiFixture();
+ credentials = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+ };
+ callbackConfigurationApi = new CallbackConfigurationApi(credentials);
+ });
+
+ describe ('getCallbackConfiguration', () => {
+ it('should make a GET request to retrieve the callbacks configuration for the specified project', async () => {
+ // Given
+ const requestData: GetCallbackConfigurationRequestData = {};
+ const expectedResponse: CallbackConfiguration = {
+ projectId: 'projectIdFromDashboard',
+ hmacSecret: 'hmacSecret',
+ };
+
+ // When
+ fixture.get.mockResolvedValue(expectedResponse);
+ callbackConfigurationApi.get = fixture.get;
+ const response = await callbackConfigurationApi.get(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.get).toHaveBeenCalledWith(requestData);
+ });
+ });
+
+ describe ('updateCallbackConfiguration', () => {
+ it('should make a PATCH request to update the callbacks configuration for the specified project', async () => {
+ // Given
+ const requestData: UpdateCallbackConfigurationRequestData = {
+ callbackConfigurationUpdateRequestBody: {
+ hmacSecret: 'newHmacSecret',
+ },
+ };
+ const expectedResponse: CallbackConfiguration = {
+ projectId: 'projectIdFromDashboard',
+ hmacSecret: 'newHmacSecret',
+ };
+
+ // When
+ fixture.update.mockResolvedValue(expectedResponse);
+ callbackConfigurationApi.update = fixture.update;
+ const response = await callbackConfigurationApi.update(requestData);
+
+ // Then
+ expect(response).toEqual(expectedResponse);
+ expect(fixture.update).toHaveBeenCalledWith(requestData);
+ });
+ });
+});
diff --git a/packages/numbers/tests/rest/v1/numbers-api.test.ts b/packages/numbers/tests/rest/v1/numbers-api.test.ts
new file mode 100644
index 00000000..a69a971c
--- /dev/null
+++ b/packages/numbers/tests/rest/v1/numbers-api.test.ts
@@ -0,0 +1,40 @@
+import { NumbersApi } from '../../../src/rest/v1/numbers-api';
+import { SinchClientParameters } from '@sinch/sdk-client';
+
+describe('Numbers API', () => {
+ let numbersApi: NumbersApi;
+ let params: SinchClientParameters;
+
+ beforeEach(() => {
+ params = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+ };
+ });
+
+ it('should initialize the client', () => {
+ numbersApi = new NumbersApi(params, 'dummy');
+ numbersApi.getSinchClient();
+ expect(numbersApi.client).toBeDefined();
+ expect(numbersApi.client?.apiClientOptions.projectId).toBe('PROJECT_ID');
+ expect(numbersApi.client?.apiClientOptions.basePath).toBe('https://numbers.api.sinch.com');
+ });
+
+ it('should update the basePath', () => {
+ const newPath = 'https://new.base.path';
+ numbersApi = new NumbersApi(params, 'dummy');
+ numbersApi.setBasePath(newPath);
+ expect(numbersApi.client?.apiClientOptions.basePath).toBe(newPath);
+ });
+
+ it('should update the credentials', () => {
+ numbersApi = new NumbersApi(params, 'dummy');
+ numbersApi.setCredentials({
+ projectId: 'NEW_PROJECT_ID',
+ keyId: 'NEW_KEY_ID',
+ keySecret: 'NEW_KEY_SECRET',
+ });
+ expect(numbersApi.client?.apiClientOptions.projectId).toBe('NEW_PROJECT_ID');
+ });
+});
diff --git a/packages/numbers/tsconfig.build.json b/packages/numbers/tsconfig.build.json
new file mode 100644
index 00000000..73f1cf60
--- /dev/null
+++ b/packages/numbers/tsconfig.build.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tsconfig.json",
+
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist"
+ },
+
+ "include": ["src/**/*.ts"],
+ "exclude": ["node_modules", "dist"],
+
+ "references": [{ "path": "../sdk-client" }],
+
+ "ts-node": {
+ "esm": true
+ }
+}
diff --git a/packages/numbers/tsconfig.json b/packages/numbers/tsconfig.json
new file mode 100644
index 00000000..2684d3e0
--- /dev/null
+++ b/packages/numbers/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../tsconfig.json",
+ "references": [
+ {
+ "path": "tsconfig.build.json"
+ },
+ {
+ "path": "tsconfig.tests.json"
+ }
+ ]
+}
diff --git a/packages/numbers/tsconfig.tests.json b/packages/numbers/tsconfig.tests.json
new file mode 100644
index 00000000..2e454981
--- /dev/null
+++ b/packages/numbers/tsconfig.tests.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tsconfig.json",
+
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "dist/tests"
+ },
+
+ "include": ["src/**/*.ts", "tests/**/*.ts"],
+ "exclude": ["node_modules", "dist"],
+
+ "references": [{ "path": "../sdk-client" }],
+
+ "ts-node": {
+ "esm": true
+ }
+}
diff --git a/packages/sdk-client/README.md b/packages/sdk-client/README.md
new file mode 100644
index 00000000..0a00939c
--- /dev/null
+++ b/packages/sdk-client/README.md
@@ -0,0 +1,109 @@
+# Sinch Http Client for Node.js
+
+This package contains the HTTP client used by the Sinch SDK client. It uses the `fetch` library to send requests. There are 3 folders in this package:
+ - api: it defines the interface for an `Api`, an `ApiClient` and for `ApiClientOptions`.
+ - client: it contains the `fetch` implementation for the `ApiClient`. This implementation handles the refresh of the JWT for the APIs which support this authentication method.
+ - plugins: calling an API can be seen as a straighforward operation as it's "just" about sending an HTTP request to a server and reading the response. And this is was the `ApiClient` does. However, all APIs don't behave the same and this is why we have introduced the request and response plugins:
+ - request plugins will modify the request: for the moment, they are all about adding some headers (for authentication, for tracking the SDK usage).
+ - response plugins will modify the response, e.g.: response content is checked and transformed into an exception if the content is empty.
+
+Warning:
+**This SDK is currently available for preview purposes only. It should not be used in production environments.**
+
+## Architecture
+TODO: schema
+
+## Installation
+
+### With NPM
+
+```bash
+npm install @sinch/sdk-client
+```
+
+### With Yarn
+
+```bash
+yarn add @sinch/sdk-client
+```
+
+## Usage
+
+In this section, we'll see how to implement the `Api` interface and how to use the `ApiFetchClient` to call the API endpoint.
+
+### Api interface
+
+```typescript
+export class MyExampleApi implements Api {
+ public readonly apiName = 'MyExampleApi';
+ public readonly client: ApiClient;
+
+ constructor(apiClient: ApiClient) {
+ this.client = apiClient;
+ }
+
+ public async myApiOperation(): Promise {
+ // Define the API endpoint
+ const url = `${this.client.apiClientOptions.basePath}/myDomain`;
+ // Build the request options: you can use the method 'prepareOptions' from the apiClient
+ // that will apply the request plugins onto the default built options
+ const requestOptions: RequestOptions = await this.client.prepareOptions(...);
+ // Send the request and apply the response plugins
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ });
+ }
+}
+```
+
+### ApiFetchClient instantiation
+```typescript
+const apiClientOptions: ApiClientOptions = {
+ basePath: 'https://my-example-api-server.com',
+ requestPlugins: [
+ // Add here the plugins that will be executed before the request is sent
+ ],
+ responsePlugins: [
+ // Add here the plugins that will be executed after the response is received and parsed
+ ]
+}
+
+// Instantiate the API Client
+const apiClient = new ApiFetchClient(apiClientOptions);
+```
+
+### API class instantiation
+
+```typescript
+// Once the API Client is intantiated, it can be given as a parameter to your API
+const myApi = new MyExampleApi(apiClient);
+
+// The API operations can now be invoked
+const myResponse = await myApi.myApiOperation();
+```
+
+
+## Plugins
+
+### Request plugins
+
+| Plugin name | Description |
+|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| additional-headers | Adds multiple headers to a request. |
+| api-token | Used for the SMS API with `servicePlanId`. It adds an `Authorization` header with the value of the API token as a `Bearer`. |
+| basic-authentication | Alternative to the `oauth2` plugin: less secure and to be used for prototyping only. It adds an `Authorization` header to the request to perform a `Basic` authentication. |
+| oauth2 | Used by all the APIs that supports the `projectId` authentication scheme. If no token is available, it will make a query to the Sinch authentication server to get a new one, valid for 1 hour. Once a token is available, it will add a `Authorization` header to the request with the value fo the token as `Bearer`. |
+| signing | Used by the `Verification` and `Voice` APIs: it adds an `Authorization` header containing the signature of the request. |
+| version | Add a `user-agent` header containing information such as the SDK version and the Node.js process version.
**Added by default to the ApiFetchClient** |
+| x-timestamp | Add the current date in ISO format in the `x-timesstamp` header (used by the `signing` plugin). |
+
+### Response plugins
+
+| Plugin name | Description |
+|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
+| exception | Check the response content and converts it into an error if empty or if the status is not `ok`.
**Added by default to the ApiFetchClient** |
+
+## Contact
+Developer Experience team: [devexp@sinch.com](mailto:devexp@sinch.com)
diff --git a/packages/sdk-client/package.json b/packages/sdk-client/package.json
new file mode 100644
index 00000000..0b687835
--- /dev/null
+++ b/packages/sdk-client/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "@sinch/sdk-client",
+ "version": "0.0.0",
+ "description": "Core services related to interacting with Sinch API",
+ "homepage": "",
+ "repository": {
+ "type": "git",
+ "url": ""
+ },
+ "license": "Apache-2.0",
+ "author": "Sinch",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": "./dist/index.js",
+ "require": "./dist/index.js"
+ },
+ "./version.ts": "./src/version.ts"
+ },
+ "directories": {
+ "src": "dist",
+ "test": "tests"
+ },
+ "files": ["/dist"],
+ "scripts": {
+ "build": "yarn run clean && yarn run compile",
+ "clean": "rimraf dist tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo",
+ "compile": "tsc -p tsconfig.build.json && tsc -p tsconfig.tests.json && rimraf dist/tests tsconfig.build.tsbuildinfo"
+ },
+ "dependencies": {
+ "node-fetch": "2.7.0"
+ },
+ "devDependencies": {
+ "@types/node-fetch": "^2.6.6",
+ "rimraf": "^5.0.5",
+ "typescript": "^5.2.2"
+ },
+ "publishConfig": {
+ "directory": "dist"
+ }
+}
diff --git a/packages/sdk-client/src/api/api-client-options-helper.ts b/packages/sdk-client/src/api/api-client-options-helper.ts
new file mode 100644
index 00000000..68c3264b
--- /dev/null
+++ b/packages/sdk-client/src/api/api-client-options-helper.ts
@@ -0,0 +1,37 @@
+// import { ApiTokenRequest, Oauth2TokenRequest, SigningRequest, XTimestampRequest } from '../plugins';
+// // import { ApiClientOptions } from './api-client-options';
+//
+// export const buildApiClientOptionsForProjectId = (
+// projectId: string,
+// keyId: string,
+// keySecret: string,
+// ) => {
+// return {
+// projectId,
+// requestPlugins: [new Oauth2TokenRequest(keyId, keySecret)],
+// useServicePlanId: false,
+// };
+// };
+//
+// export const buildApiClientOptionForServicePlanId = (
+// servicePlanId: string,
+// apiToken: string,
+// ) => {
+// return {
+// projectId: servicePlanId,
+// requestPlugins: [new ApiTokenRequest(apiToken)],
+// useServicePlanId: true,
+// };
+// };
+//
+// export const buildApiClientOptionForApplication = (
+// applicationKey: string,
+// applicationSecret: string,
+// ) => {
+// return {
+// requestPlugins: [
+// new XTimestampRequest(),
+// new SigningRequest(applicationKey, applicationSecret),
+// ],
+// };
+// };
diff --git a/packages/sdk-client/src/api/api-client-options.ts b/packages/sdk-client/src/api/api-client-options.ts
new file mode 100644
index 00000000..823aa1b9
--- /dev/null
+++ b/packages/sdk-client/src/api/api-client-options.ts
@@ -0,0 +1,32 @@
+import { RequestPlugin, ResponsePlugin } from '../plugins';
+
+interface BaseApiClientOptions {
+ /**
+ * ID of the umbrella project containing the access keys
+ * Found on your Sinch Customer Dashboard.
+ */
+ projectId: string;
+
+ /** Base path of the API server */
+ basePath: string;
+
+ /**
+ * List of plugins to apply to the request before calling the API
+ * @default [new Oauth2RequestPlugin()]
+ */
+ requestPlugins: RequestPlugin[];
+
+ /**
+ * List of plugins to apply to the response of the API call
+ * @default [new ExceptionResponse()]
+ */
+ responsePlugins: ResponsePlugin[];
+
+ /** Some APIs have not been migrated fully to the 'projectId' structure and use another URL for their authentication
+ * This flag indicates the API is not using the 'projectId'
+ * @default false
+ */
+ useServicePlanId?: boolean;
+}
+
+export interface ApiClientOptions extends Partial {}
diff --git a/packages/sdk-client/src/api/api-client.ts b/packages/sdk-client/src/api/api-client.ts
new file mode 100644
index 00000000..72ba5a7a
--- /dev/null
+++ b/packages/sdk-client/src/api/api-client.ts
@@ -0,0 +1,189 @@
+import { RequestBody, RequestOptions } from '../plugins';
+import { ApiClientOptions } from './api-client-options';
+import { Headers } from 'node-fetch';
+
+export enum PaginationEnum {
+ NONE,
+ TOKEN,
+ PAGE
+}
+export interface ApiListPromise extends Promise>, AsyncIterableIterator {
+}
+
+export type PageResult = {
+ data: Array;
+ hasNextPage: boolean;
+ nextPageValue: string;
+ nextPage: () => ApiListPromise;
+};
+
+export type AutoPaginationMethods = {
+ next: () => Promise>;
+ return: () => void;
+ [Symbol.asyncIterator]: () => AutoPaginationMethods;
+};
+
+export interface ApiCallParameters {
+ url: string,
+ requestOptions: RequestOptions,
+ apiName: string,
+ operationId: string,
+ circuitBreaker?: number,
+}
+
+export interface ApiCallParametersWithPagination extends ApiCallParameters {
+ pagination: PaginationEnum,
+ dataKey: string,
+ requestOptionsPromise?: Promise,
+}
+
+export interface PaginatedApiProperties {
+ /** Type of pagination: can be TOKEN or PAGE */
+ pagination: PaginationEnum,
+ /** Name of the API - for logging purposes */
+ apiName: string,
+ /** Operation identifier - for logging purposes */
+ operationId: string,
+ /** Name of the property holding the array of paginated data */
+ dataKey: string,
+}
+
+/**
+ * API Client used to call the server
+ */
+export class ApiClient {
+ /** Options for the API */
+ public apiClientOptions: ApiClientOptions;
+
+ constructor(options: ApiClientOptions) {
+ this.apiClientOptions = options;
+ }
+
+ /**
+ * Returns a map containing the query parameters based on the provided data and names.
+ *
+ * @param {Object} data - The data object from which to extract query parameters.
+ * @param {Array.} names - An array of keys (property names) to extract from the data object.
+ * @return {Object} A map containing the extracted query parameters.
+ */
+ extractQueryParams(
+ data: T,
+ names: (keyof T)[],
+ ): { [p in keyof T]: string } {
+ return names
+ .filter((name) => typeof data[name] !== 'undefined' && data[name] !== null)
+ .reduce(
+ (acc, name) => {
+ const prop = data[name];
+ acc[name] = typeof prop.toJSON === 'function'
+ ? prop.toJSON()
+ : Array.isArray(prop) ? prop.join(';') : prop.toString();
+ return acc;
+ },
+ {} as { [p in keyof T]: string },
+ );
+ }
+
+ /**
+ * Asynchronously prepares options for an HTTP request.
+ *
+ * @param {string} url - The URL for the HTTP request.
+ * @param {string} method - The HTTP method for the request (e.g., 'GET', 'POST').
+ * @param {Object.} queryParams - An object representing query parameters.
+ * @param {Object.} headers - An object representing headers.
+ * @param {RequestBody} [body] - The request body, if applicable.
+ * @param {string} [path] - An optional path for the request.
+ * @return {Promise} A promise that resolves to the prepared options for the HTTP request.
+ */
+ async prepareOptions(
+ url: string,
+ method: string,
+ queryParams: { [key: string]: string | undefined },
+ headers: { [key: string]: string | undefined },
+ body?: RequestBody,
+ path?: string,
+ ): Promise {
+ const options: RequestOptions = {
+ method,
+ headers: new Headers(filterUndefinedValues(headers)),
+ body,
+ queryParams: filterUndefinedValues(queryParams),
+ basePath: url,
+ path,
+ };
+
+ let opts = options;
+ if (this.apiClientOptions.requestPlugins) {
+ for (const plugin of this.apiClientOptions.requestPlugins) {
+ opts = await plugin.load().transform(opts);
+ }
+ }
+
+ return opts;
+ };
+
+ /**
+ * Prepares the url to be called by appending query parameters.
+ *
+ * @param {string} url - The base url to be used.
+ * @param {Object.} queryParameters - Key-value pair with the parameters. If the value is undefined, the key is dropped.
+ * @return {string} The prepared URL as a string.
+ */
+ prepareUrl(
+ url: string,
+ queryParameters: { [key: string]: string | undefined } = {},
+ ): string {
+ const queryPart = Object.keys(queryParameters)
+ .filter((name) => typeof queryParameters[name] !== 'undefined')
+ .map((name) => `${name}=${queryParameters[name]!}`)
+ .join('&');
+
+ const paramsPrefix = url.indexOf('?') > -1 ? '&' : '?';
+
+ return url + (!queryPart ? '' : paramsPrefix + queryPart);
+ }
+
+ /**
+ * Process HTTP call
+ * @abstract
+ * @template T
+ * @param {ApiCallParameters} _httpCallParameters - Parameters for the HTTP call.
+ * @return {Promise} A promise that resolves to the result of the HTTP call.
+ */
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ processCall(_httpCallParameters: ApiCallParameters): Promise {
+ throw new Error('Abstract method must be implemented');
+ }
+
+ /**
+ * Process HTTP call
+ * @abstract
+ * @template T
+ * @param {ApiCallParametersWithPagination} _httpCallParameters - Parameters for the HTTP call.
+ * @return {Promise} A promise that resolves to the result of the HTTP call.
+ */
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ processCallWithPagination(_httpCallParameters: ApiCallParametersWithPagination): Promise> {
+ throw new Error('Abstract method must be implemented');
+ }
+
+
+}
+
+// ----- INTERNAL ------ \\
+/**
+ * Returns a filtered JSON object, removing all the undefined values.
+ *
+ * @param {Object.} object - The JSON object to filter.
+ * @return {Object.} An object without undefined values.
+ */
+function filterUndefinedValues(object: { [key: string]: string | undefined }): {
+ [key: string]: string;
+} {
+ return Object.keys(object)
+ .filter((objectKey) => typeof object[objectKey] !== 'undefined')
+ .reduce<{ [key: string]: string }>((acc, objectKey) => {
+ acc[objectKey] = object[objectKey] as string;
+ return acc;
+ }, {});
+}
diff --git a/packages/sdk-client/src/api/api-errors.ts b/packages/sdk-client/src/api/api-errors.ts
new file mode 100644
index 00000000..3512eb6a
--- /dev/null
+++ b/packages/sdk-client/src/api/api-errors.ts
@@ -0,0 +1,94 @@
+/**
+ * Generic error context
+ */
+export interface ErrorContext {
+ /** Api name */
+ apiName?: string;
+ /** Operation ID */
+ operationId?: string;
+ /** Base URL */
+ url?: string;
+ /** Origin domain initiating the call */
+ origin?: string | null;
+}
+
+/**
+ * Generic error class
+ */
+export class GenericError extends Error {
+ constructor(message: string, errorContext: ErrorContext) {
+ const baseUrl = GenericError.formatUrl(errorContext.url);
+ const origin = GenericError.formatUrl(errorContext.origin);
+ super(
+ `[SDK] [apiName: ${errorContext.apiName || 'unknown'}]
+ [operationId: ${errorContext.operationId || 'unknown'}]
+ [baseUrl: ${baseUrl}] [origin: ${origin}] [errorType: SDK] ${message}`,
+ );
+ }
+
+ private static formatUrl(url: string | null | undefined) {
+ const httpRegexp = /^https?:\/\//;
+ return url ? url.replace(httpRegexp, '') : 'unknown';
+ }
+
+}
+
+/**
+ * Request failed error class
+ */
+export class RequestFailedError extends GenericError {
+ /**
+ * Request status code
+ */
+ public statusCode: number;
+
+ /**
+ * Data decoded from the response body
+ */
+ public data?: T;
+
+ constructor(
+ message: string,
+ statusCode: number,
+ errorContext: ErrorContext,
+ data?: T,
+ ) {
+ super(`[status: ${statusCode}] ${message}`, errorContext);
+ this.statusCode = statusCode;
+ this.data = data;
+ }
+}
+
+/**
+ * Empty response error class
+ */
+export class EmptyResponseError extends GenericError {
+ /**
+ * Data decoded from the response body
+ */
+ public data?: T;
+
+ constructor(message: string, errorContext: ErrorContext, data?: T) {
+ super(`[Empty response] ${message}`, errorContext);
+ this.data = data;
+ }
+}
+
+/**
+ * Response parse error class
+ */
+export class ResponseJSONParseError extends RequestFailedError {
+ constructor(
+ message: string,
+ httpStatus: number,
+ errorContext: ErrorContext,
+ bodyContent?: string,
+ ) {
+ super(
+ `[Response JSON parse error] ${message}`,
+ httpStatus,
+ errorContext,
+ bodyContent,
+ );
+ }
+}
diff --git a/packages/sdk-client/src/api/api-interface.ts b/packages/sdk-client/src/api/api-interface.ts
new file mode 100644
index 00000000..51d4370a
--- /dev/null
+++ b/packages/sdk-client/src/api/api-interface.ts
@@ -0,0 +1,9 @@
+import { ApiClient } from './api-client';
+
+/** API interface */
+export interface Api {
+ /** API name */
+ apiName: string;
+ /** API Client used to process the calls to the API */
+ client?: ApiClient;
+}
diff --git a/packages/sdk-client/src/api/index.ts b/packages/sdk-client/src/api/index.ts
new file mode 100644
index 00000000..07fd7ea3
--- /dev/null
+++ b/packages/sdk-client/src/api/index.ts
@@ -0,0 +1,5 @@
+export * from './api-client-options';
+// export * from './api-client-options-helper';
+export * from './api-client';
+export * from './api-errors';
+export * from './api-interface';
diff --git a/packages/sdk-client/src/client/api-client-helpers.ts b/packages/sdk-client/src/client/api-client-helpers.ts
new file mode 100644
index 00000000..ff813737
--- /dev/null
+++ b/packages/sdk-client/src/client/api-client-helpers.ts
@@ -0,0 +1,64 @@
+import {
+ Oauth2TokenRequest,
+ RequestOptions,
+ RequestPlugin,
+} from '../plugins';
+import { ApiCallParameters, ApiCallParametersWithPagination, ErrorContext, GenericError } from '../api';
+
+export const manageExpiredToken = async (
+ apiCallParameters: ApiCallParameters | ApiCallParametersWithPagination,
+ errorContext: ErrorContext,
+ requestPlugins: RequestPlugin[] | undefined,
+ requestOptions: RequestOptions,
+ callback: (props: any) => Promise,
+) => {
+ // Use the circuitBreaker variable to try to regenerate a valid JWT only 3 times
+ if (!apiCallParameters.circuitBreaker) {
+ apiCallParameters.circuitBreaker = 1;
+ } else {
+ apiCallParameters.circuitBreaker++;
+ // Check the circuitBreaker value: if greater than 3, then we stop and throw
+ if (apiCallParameters.circuitBreaker >= 3) {
+ throw new GenericError(
+ 'Tried to generate a new JWT with no success',
+ errorContext,
+ );
+ }
+ }
+ const optionsWithNewJwt = await invalidateAndRegenerateJwt(requestPlugins, requestOptions, errorContext);
+ const newApiCallParameters = {
+ ...apiCallParameters,
+ requestOptions: optionsWithNewJwt,
+ };
+ return callback(newApiCallParameters);
+};
+
+export function buildErrorContext(
+ apiCallParameters: ApiCallParameters,
+ origin: string | null,
+): ErrorContext {
+ return {
+ apiName: apiCallParameters.apiName,
+ operationId: apiCallParameters.operationId,
+ url: apiCallParameters.url,
+ origin,
+ };
+}
+
+export async function invalidateAndRegenerateJwt(
+ requestPlugins: RequestPlugin[] | undefined,
+ options: RequestOptions,
+ errorContext: ErrorContext,
+): Promise {
+ const oauth2Plugin = requestPlugins?.find(
+ (plugin) => plugin instanceof Oauth2TokenRequest,
+ ) as Oauth2TokenRequest;
+ if (oauth2Plugin) {
+ oauth2Plugin.invalidateToken();
+ return oauth2Plugin.load().transform(options);
+ } else {
+ const errorMessage
+ = 'Trying to invalidate an expired JWT while the Oauth2Token plugin is not registered to the API client';
+ throw new GenericError(errorMessage, errorContext);
+ }
+}
diff --git a/packages/sdk-client/src/client/api-client-pagination-helper.ts b/packages/sdk-client/src/client/api-client-pagination-helper.ts
new file mode 100644
index 00000000..986e23c3
--- /dev/null
+++ b/packages/sdk-client/src/client/api-client-pagination-helper.ts
@@ -0,0 +1,258 @@
+import {
+ ApiCallParametersWithPagination, ApiClient,
+ ApiListPromise,
+ AutoPaginationMethods,
+ PageResult,
+ PaginatedApiProperties,
+ PaginationEnum,
+} from '../api';
+import { RequestOptions } from '../plugins';
+
+class SinchIterator implements AsyncIterator {
+
+ private index: number;
+ private pagePromise: Promise>;
+ public requestOptionsPromise: Promise;
+ public paginatedOperationProperties: PaginatedApiProperties;
+ public apiClient: ApiClient;
+
+ constructor(
+ apiClient: ApiClient,
+ requestOptionsPromise: Promise,
+ firstPagePromise: Promise>,
+ context: PaginatedApiProperties,
+ ) {
+ this.index = 0;
+ this.apiClient = apiClient;
+ this.pagePromise = firstPagePromise;
+ this.requestOptionsPromise = requestOptionsPromise;
+ this.paginatedOperationProperties = context;
+ }
+
+ async iterate(pageResult: PageResult): Promise> {
+ // If there are more elements to return on the current page
+ if(this.index < pageResult.data.length) {
+ const value = pageResult.data[this.index];
+ this.index += 1;
+ return { value, done: false };
+ }
+ // If there are other pages to getch
+ else if (pageResult.hasNextPage) {
+ // Reset counter to the first index of the next page
+ this.index = 0;
+ // Reset the current page to the next one - 'getNextPage' has different implementation depending on the pagination type (TOKEN or PAGE)
+ this.pagePromise = this.getNextPage(pageResult);
+ // Recursively call the iterator on the next page
+ const nextPageResponse = await this.pagePromise;
+ return this.iterate(nextPageResponse);
+ }
+ // No more element on the current page and no more pages to fetch
+ return { value: undefined, done: true };
+ }
+
+ async getNextPage(pageResult: PageResult): Promise> {
+ const requestOptions = await this.requestOptionsPromise;
+ if (this.paginatedOperationProperties.pagination === PaginationEnum.TOKEN) {
+ const newParams = {
+ pageToken: pageResult.nextPageValue,
+ };
+ return updateQueryParamsAndSendRequest(
+ this.apiClient, newParams, requestOptions, this.paginatedOperationProperties);
+ }
+ if (this.paginatedOperationProperties.pagination === PaginationEnum.PAGE) {
+ const newParams = {
+ page: pageResult.nextPageValue,
+ };
+ return updateQueryParamsAndSendRequest(
+ this.apiClient,newParams, requestOptions, this.paginatedOperationProperties);
+ }
+ throw new Error(`The operationId "${this.paginatedOperationProperties.operationId}" must define a pagination model`);
+ }
+
+ next(): Promise> {
+ return (async (): Promise> => {
+ return this.iterate(await this.pagePromise);
+ })();
+ }
+
+}
+
+const updateQueryParamsAndSendRequest = (
+ apiClient: ApiClient,
+ newParams: { [key: string]: string },
+ requestOptions: RequestOptions,
+ paginatedApiProperties: PaginatedApiProperties,
+): Promise> => {
+ const newQueryParams = {
+ ...requestOptions.queryParams,
+ ...newParams,
+ };
+ const newRequestOptions: RequestOptions = {
+ ...requestOptions,
+ queryParams: newQueryParams,
+ };
+ const newUrl = apiClient.prepareUrl(
+ requestOptions.basePath,
+ newQueryParams,
+ );
+ return apiClient.processCallWithPagination({
+ url: newUrl,
+ requestOptions: newRequestOptions,
+ ...paginatedApiProperties,
+ });
+};
+
+export const createIteratorMethodsForPagination = (
+ apiClient: ApiClient,
+ requestOptionsPromise: Promise,
+ firstPagePromise: Promise>,
+ context: PaginatedApiProperties,
+): AutoPaginationMethods => {
+ const iterator = new SinchIterator(apiClient, requestOptionsPromise, firstPagePromise, context);
+ const autoPaginationMethods: AutoPaginationMethods = {
+ next: () => iterator.next(),
+ return: (): any => {
+ return {};
+ },
+ [Symbol.asyncIterator]: () => {
+ return autoPaginationMethods;
+ },
+ };
+ return autoPaginationMethods;
+};
+
+export const createNextPageMethod = (
+ apiClient: ApiClient,
+ context: PaginationContext,
+ requestOptions: RequestOptions,
+ nextPageValue: string,
+): ApiListPromise => {
+ let newParams;
+ if (context.pagination === PaginationEnum.TOKEN) {
+ newParams = {
+ pageToken: nextPageValue,
+ };
+ } else if (context.pagination === PaginationEnum.PAGE) {
+ newParams = {
+ page: nextPageValue,
+ };
+ } else {
+ throw new Error();
+ }
+ const pageResultPromise = updateQueryParamsAndSendRequest(apiClient, newParams, requestOptions, context);
+
+ const requestOptionsPromise = new Promise((resolve) => {
+ resolve(requestOptions);
+ });
+
+ // Add properties to the Promise to offer the possibility to use it as an iterator
+ Object.assign(
+ pageResultPromise,
+ createIteratorMethodsForPagination(apiClient, requestOptionsPromise, pageResultPromise, context),
+ );
+
+ return pageResultPromise as ApiListPromise;
+};
+
+export function hasMore(
+ response: any,
+ context: PaginationContext,
+): boolean {
+ if (context.pagination === PaginationEnum.TOKEN) {
+ return !!response.nextPageToken;
+ }
+ if (context.pagination === PaginationEnum.PAGE) {
+ const requestedPageSize = context.requestOptions.queryParams?.page_size;
+ const pageSize: number = requestedPageSize ? parseInt(requestedPageSize) : response.page_size;
+ return checkIfThereAreMorePages(response, pageSize);
+ }
+ throw new Error(`The operation ${context.operationId} is not meant to be paginated.`);
+}
+
+export function calculateNextPage(
+ response: any,
+ context: PaginationContext,
+): string {
+ if (context.pagination === PaginationEnum.TOKEN) {
+ return response['nextPageToken'];
+ }
+ if (context.pagination === PaginationEnum.PAGE) {
+ const currentPage: number = response.page || 0;
+ const nextPage = currentPage + 1;
+ return nextPage.toString();
+ }
+ throw new Error(`The operation ${context.operationId} is not meant to be paginated.`);
+}
+
+export interface PaginationContext {
+ pagination: PaginationEnum;
+ apiName: string;
+ operationId: string;
+ dataKey: string;
+ requestOptions: RequestOptions;
+}
+
+export function buildPaginationContext(props: ApiCallParametersWithPagination): PaginationContext {
+ return {
+ pagination: props.pagination,
+ apiName: props.apiName,
+ operationId: props.operationId,
+ dataKey: props.dataKey,
+ requestOptions: props.requestOptions!,
+ };
+}
+
+export const buildPageResultPromise = async (
+ client: ApiClient,
+ requestOptionsPromise: Promise,
+ operationProperties: PaginatedApiProperties,
+): Promise> => {
+ // Await the promise in this async method and store the result in client so that they can be reused
+ const requestOptions = await requestOptionsPromise;
+ const url = client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return client.processCallWithPagination({
+ url,
+ requestOptions,
+ ...operationProperties,
+ });
+};
+
+interface WithPagination {
+ /** The total number of entries matching the given filters. */
+ count?: number;
+ /** The requested page. */
+ page?: number;
+ /** The number of entries returned in this request. */
+ page_size?: number;
+}
+
+const checkIfThereAreMorePages = (response: WithPagination, requestedPageSize: number | undefined): boolean => {
+ const lastPageNumber = calculateLastPageValue(response, requestedPageSize);
+ return response.page! < lastPageNumber;
+};
+
+const calculateLastPageValue = (response: WithPagination, requestedPageSize: number | undefined): number => {
+ if (invalidatePaginationDataFromResponse(response)) {
+ throw new Error(`Impossible to calculate the last page value with the following parameters: count=${response.count}, page=${response.page}, page_size=${response.page_size}`);
+ }
+ if (response.page_size === 0) {
+ // If there are no elements on the current page, there are no more pages
+ return response.page!;
+ }
+ // The elements in the response are not enough to determine if the current page is the last one
+ const pageSize: number = requestedPageSize || response.page_size!;
+ const itemCount: number = response.count!;
+ return Math.ceil(itemCount / pageSize) - 1;
+};
+
+const invalidatePaginationDataFromResponse = (response: WithPagination): boolean => {
+ const currentPage = response.page;
+ const pageSize = response.page_size;
+ const itemCount = response.count;
+ return !isNumber(currentPage) || !isNumber(pageSize) || !isNumber(itemCount);
+};
+
+const isNumber = (value: any) => {
+ return typeof value === 'number' && !isNaN(value);
+};
diff --git a/packages/sdk-client/src/client/api-fetch-client.ts b/packages/sdk-client/src/client/api-fetch-client.ts
new file mode 100644
index 00000000..d1d46e82
--- /dev/null
+++ b/packages/sdk-client/src/client/api-fetch-client.ts
@@ -0,0 +1,196 @@
+import {
+ ExceptionResponse,
+ ResponsePlugin,
+ VersionRequest,
+} from '../plugins';
+import {
+ ApiClient,
+ ApiClientOptions,
+ EmptyResponseError,
+ ErrorContext,
+ GenericError,
+ ApiCallParameters,
+ ResponseJSONParseError, ApiCallParametersWithPagination, PageResult,
+} from '../api';
+import fetch, { Response, Headers } from 'node-fetch';
+import { buildErrorContext, manageExpiredToken } from './api-client-helpers';
+import {
+ buildPaginationContext,
+ calculateNextPage,
+ createNextPageMethod,
+ hasMore,
+} from './api-client-pagination-helper';
+
+/** Client to process the call to the API using Fetch API */
+export class ApiFetchClient extends ApiClient {
+
+ /**
+ * Initialize your API Client instance with the provided configuration options.
+ * Default request plugins: VersionRequest
+ * Default response plugins: ExceptionResponse
+ *
+ * @param {ApiClientOptions} options - Configuration options for the API Client.
+ */
+ constructor(options: ApiClientOptions) {
+ super({
+ ...options,
+ requestPlugins: [new VersionRequest(), ...(options.requestPlugins || [])],
+ responsePlugins: [
+ new ExceptionResponse(),
+ ...(options.responsePlugins || []),
+ ],
+ });
+ }
+
+ /** @inheritdoc */
+ public async processCall(
+ props: ApiCallParameters,
+ ): Promise {
+ // Read the "Origin" header if existing, for logging purposes
+ const origin = (props.requestOptions.headers as Headers).get('Origin');
+ const errorContext: ErrorContext = buildErrorContext(props, origin);
+
+ // Declare variables
+ let response: Response | undefined;
+ let body: string | undefined;
+ let exception: Error | undefined;
+
+ // Execute call
+ try {
+ // Send the request with the refresh token mechanism
+ response = await this.sinchFetch(props, errorContext);
+ body = await response.text();
+ } catch (error: any) {
+ this.buildFetchError(error, errorContext);
+ }
+
+ let result;
+ try {
+ // Try to parse the body if there is one
+ result = body ? JSON.parse(body) : undefined;
+ } catch (error: any) {
+ exception = new ResponseJSONParseError(
+ error.message || 'Fail to parse response body',
+ (response && response.status) || 0,
+ errorContext,
+ body,
+ );
+ }
+
+ // Load and invoke the response plugins to transform the response
+ const responsePlugins = this.loadResponsePlugins(
+ this.apiClientOptions.responsePlugins,
+ props,
+ response,
+ exception,
+ origin);
+ let transformedResponse = result;
+ for (const pluginRunner of responsePlugins) {
+ transformedResponse = await pluginRunner.transform(transformedResponse);
+ }
+
+ // If there has been an error at some point in the process, throw it
+ if (exception) {
+ throw exception;
+ }
+
+ // If everything went fine, we return the transformed API response
+ return transformedResponse;
+ }
+
+ private async sinchFetch(
+ apiCallParameters: ApiCallParameters,
+ errorContext: ErrorContext,
+ ): Promise {
+ const response = await fetch(apiCallParameters.url, apiCallParameters.requestOptions);
+ if (
+ response.status === 401
+ && response.headers.get('www-authenticate')?.includes('expired')
+ ) {
+ return manageExpiredToken(
+ apiCallParameters,
+ errorContext,
+ this.apiClientOptions.requestPlugins,
+ apiCallParameters.requestOptions,
+ this.processCall);
+ }
+ return response;
+ }
+
+ public processCallWithPagination(
+ props: ApiCallParametersWithPagination,
+ ): Promise> {
+ // Read the "Origin" header if existing, for logging purposes
+ const origin = (props.requestOptions.headers as Headers).get('Origin');
+ const errorContext: ErrorContext = buildErrorContext(props, origin);
+
+ // Execute call
+ return this.sinchFetchWithPagination(props, errorContext);
+ };
+
+ private async sinchFetchWithPagination(
+ apiCallParameters: ApiCallParametersWithPagination,
+ errorContext: ErrorContext,
+ ): Promise> {
+ const response = await fetch(apiCallParameters.url, apiCallParameters.requestOptions);
+ if (
+ response.status === 401
+ && response.headers.get('www-authenticate')?.includes('expired')
+ ) {
+ return manageExpiredToken(
+ apiCallParameters,
+ errorContext,
+ this.apiClientOptions.requestPlugins,
+ apiCallParameters.requestOptions,
+ this.processCallWithPagination);
+ }
+ // When handling pagination, we won't return the raw response but a PageResult
+ const body = await response.text();
+ const result = JSON.parse(body);
+ // Read the elements' array with its key
+ const responseData: Array = result[apiCallParameters.dataKey];
+ // Build the PageResult object
+ const nextPage = calculateNextPage(result, buildPaginationContext(apiCallParameters));
+ return {
+ data: responseData,
+ hasNextPage: hasMore(result, buildPaginationContext(apiCallParameters)),
+ nextPageValue: nextPage,
+ nextPage: () => createNextPageMethod(
+ this, buildPaginationContext(apiCallParameters), apiCallParameters.requestOptions, nextPage),
+ };
+ }
+
+ private buildFetchError(error: any, errorContext: ErrorContext): Error {
+ if (error instanceof GenericError) {
+ return new GenericError(error.message, errorContext);
+ } else {
+ return new EmptyResponseError(
+ error.message || 'Fail to fetch',
+ errorContext,
+ undefined,
+ );
+ }
+ }
+
+ private loadResponsePlugins(
+ responsePlugins: ResponsePlugin[] | undefined,
+ apiCallParameters: ApiCallParameters,
+ response: Response | undefined,
+ exception: Error | undefined,
+ origin: string | null,
+ ) {
+ return responsePlugins
+ ? responsePlugins.map((plugin) =>
+ plugin.load({
+ response,
+ exception,
+ apiName: apiCallParameters.apiName,
+ operationId: apiCallParameters.operationId,
+ url: apiCallParameters.url,
+ requestOptions: apiCallParameters.requestOptions,
+ origin,
+ }),
+ )
+ : [];
+ }
+}
diff --git a/packages/sdk-client/src/client/index.ts b/packages/sdk-client/src/client/index.ts
new file mode 100644
index 00000000..714b4dd1
--- /dev/null
+++ b/packages/sdk-client/src/client/index.ts
@@ -0,0 +1,2 @@
+export * from './api-fetch-client';
+export * from './api-client-pagination-helper';
diff --git a/packages/sdk-client/src/domain/domain-interface.ts b/packages/sdk-client/src/domain/domain-interface.ts
new file mode 100644
index 00000000..81d2d4ee
--- /dev/null
+++ b/packages/sdk-client/src/domain/domain-interface.ts
@@ -0,0 +1,68 @@
+export interface SinchClientParameters extends
+ Partial,
+ Partial,
+ Partial {}
+
+export interface UnifiedCredentials {
+ /** The project ID associated with the API Client. You can find this on your [Dashboard](https://dashboard.sinch.com/account/access-keys). */
+ projectId: string;
+ /** The client ID used for authentication. You can find this on your [Dashboard](https://dashboard.sinch.com/account/access-keys). */
+ keyId: string;
+ /** The client secret used for authentication. You can find this ONLY when creating a new key. */
+ keySecret: string;
+ /** The region for the SMS API. Default region is US */
+ region?: Region;
+}
+
+export interface ServicePlanIdCredentials {
+ /** Your service plan ID. You can find this on your [Dashboard](https://dashboard.sinch.com/sms/api/rest). */
+ servicePlanId: string;
+ /** Your API token. You can find this on your [Dashboard](https://dashboard.sinch.com/sms/api/rest). */
+ apiToken: string;
+ /** boolean to force the usage of the service plan Id + API token as credentials for the SMS API*/
+ forceServicePlanIdUsageForSmsApi?: boolean;
+ /** The region for the SMS API. Default region is US */
+ region?: Region;
+}
+
+export interface ApplicationCredentials {
+ /** Your Application key. You can find this on your [Dashboard](https://dashboard.sinch.com/verification/apps)*/
+ applicationKey: string;
+ /** Your Application secret. You can find this on your [Dashboard](https://dashboard.sinch.com/verification/apps)*/
+ applicationSecret: string;
+}
+
+export const isUnifiedCredentials = (credentials: any): credentials is UnifiedCredentials => {
+ const candidate = (credentials) as UnifiedCredentials;
+ return candidate.projectId !== undefined
+ && candidate.keyId !== undefined
+ && candidate.keySecret !== undefined;
+};
+
+export const isServicePlanIdCredentials = (credentials: any): credentials is ServicePlanIdCredentials => {
+ const candidate = (credentials) as ServicePlanIdCredentials;
+ return candidate.servicePlanId !== undefined
+ && candidate.apiToken !== undefined;
+};
+
+export enum Region {
+ UNITED_STATES = 'us',
+ EUROPE = 'eu',
+ BRAZIL = 'br',
+ CANADA = 'ca',
+ AUSTRALIA = 'au'
+}
+
+export function getRegion(value: string | undefined): Region | undefined {
+ if (!value) {
+ return undefined;
+ }
+
+ for (const region of Object.values(Region)) {
+ if (region === value.toLowerCase()) {
+ return region as Region;
+ }
+ }
+ console.error(`No region exist for the value '${value}'`);
+ return undefined;
+}
diff --git a/packages/sdk-client/src/domain/index.ts b/packages/sdk-client/src/domain/index.ts
new file mode 100644
index 00000000..e4e7e49c
--- /dev/null
+++ b/packages/sdk-client/src/domain/index.ts
@@ -0,0 +1 @@
+export * from './domain-interface';
diff --git a/packages/sdk-client/src/getVersion.ts b/packages/sdk-client/src/getVersion.ts
new file mode 100644
index 00000000..1c1381aa
--- /dev/null
+++ b/packages/sdk-client/src/getVersion.ts
@@ -0,0 +1,2 @@
+import { version as coreVersion } from '@sinch/sdk-core/package.json';
+export const sdkCoreVersion = coreVersion;
diff --git a/packages/sdk-client/src/index.ts b/packages/sdk-client/src/index.ts
new file mode 100644
index 00000000..e89ddebf
--- /dev/null
+++ b/packages/sdk-client/src/index.ts
@@ -0,0 +1,5 @@
+export * from './api';
+export * from './client';
+export * from './domain';
+export * from './plugins';
+export * from './utils';
diff --git a/packages/sdk-client/src/plugins/additional-headers/additional-headers.request.ts b/packages/sdk-client/src/plugins/additional-headers/additional-headers.request.ts
new file mode 100644
index 00000000..8e3b2f64
--- /dev/null
+++ b/packages/sdk-client/src/plugins/additional-headers/additional-headers.request.ts
@@ -0,0 +1,27 @@
+import { PluginRunner, RequestOptions, RequestPlugin } from '../core';
+
+export interface AdditionalHeaders {
+ headers: Promise<{ [key: string]: string }>;
+}
+
+export class AdditionalHeadersRequest implements RequestPlugin {
+ private readonly additionalHeaders: AdditionalHeaders;
+
+ constructor(additionalHeaders: AdditionalHeaders) {
+ this.additionalHeaders = additionalHeaders;
+ }
+
+ public load(): PluginRunner {
+ return {
+ transform: async (data: RequestOptions) => {
+ const headers = await this.additionalHeaders.headers;
+ if (headers) {
+ Object.keys(headers).forEach((key) =>
+ data.headers.set(key, headers[key]),
+ );
+ }
+ return data;
+ },
+ };
+ }
+}
diff --git a/packages/sdk-client/src/plugins/additional-headers/index.ts b/packages/sdk-client/src/plugins/additional-headers/index.ts
new file mode 100644
index 00000000..661b9a5b
--- /dev/null
+++ b/packages/sdk-client/src/plugins/additional-headers/index.ts
@@ -0,0 +1 @@
+export * from './additional-headers.request';
diff --git a/packages/sdk-client/src/plugins/api-token/api-token.request.ts b/packages/sdk-client/src/plugins/api-token/api-token.request.ts
new file mode 100644
index 00000000..06ef978f
--- /dev/null
+++ b/packages/sdk-client/src/plugins/api-token/api-token.request.ts
@@ -0,0 +1,18 @@
+import { PluginRunner, RequestOptions, RequestPlugin } from '../core';
+
+export class ApiTokenRequest implements RequestPlugin {
+ private readonly apiToken: string;
+
+ constructor(apiToken: string) {
+ this.apiToken = apiToken;
+ }
+
+ public load(): PluginRunner {
+ return {
+ transform: (data: RequestOptions) => {
+ data.headers.append('Authorization', `Bearer ${this.apiToken}`);
+ return data;
+ },
+ };
+ }
+}
diff --git a/packages/sdk-client/src/plugins/api-token/index.ts b/packages/sdk-client/src/plugins/api-token/index.ts
new file mode 100644
index 00000000..1f1dda93
--- /dev/null
+++ b/packages/sdk-client/src/plugins/api-token/index.ts
@@ -0,0 +1 @@
+export * from './api-token.request';
diff --git a/packages/sdk-client/src/plugins/basicAuthentication/basic-authentication.request.ts b/packages/sdk-client/src/plugins/basicAuthentication/basic-authentication.request.ts
new file mode 100644
index 00000000..4e7183f2
--- /dev/null
+++ b/packages/sdk-client/src/plugins/basicAuthentication/basic-authentication.request.ts
@@ -0,0 +1,23 @@
+import { PluginRunner, RequestOptions, RequestPlugin } from '../core';
+
+export class BasicAuthenticationRequest implements RequestPlugin {
+ private readonly userName: string;
+ private readonly password: string;
+
+ constructor(userName: string, password: string) {
+ this.userName = userName;
+ this.password = password;
+ }
+
+ public load(): PluginRunner {
+ return {
+ transform: (data: RequestOptions) => {
+ const basicAuth
+ = 'Basic '
+ + Buffer.from(`${this.userName}:${this.password}`).toString('base64');
+ data.headers.append('Authorization', basicAuth);
+ return data;
+ },
+ };
+ }
+}
diff --git a/packages/sdk-client/src/plugins/basicAuthentication/index.ts b/packages/sdk-client/src/plugins/basicAuthentication/index.ts
new file mode 100644
index 00000000..1f118055
--- /dev/null
+++ b/packages/sdk-client/src/plugins/basicAuthentication/index.ts
@@ -0,0 +1 @@
+export * from './basic-authentication.request';
diff --git a/packages/sdk-client/src/plugins/core/index.ts b/packages/sdk-client/src/plugins/core/index.ts
new file mode 100644
index 00000000..0cae705d
--- /dev/null
+++ b/packages/sdk-client/src/plugins/core/index.ts
@@ -0,0 +1,3 @@
+export * from './plugin';
+export * from './request-plugin';
+export * from './response-plugin';
diff --git a/packages/sdk-client/src/plugins/core/plugin.ts b/packages/sdk-client/src/plugins/core/plugin.ts
new file mode 100644
index 00000000..9418bae0
--- /dev/null
+++ b/packages/sdk-client/src/plugins/core/plugin.ts
@@ -0,0 +1,15 @@
+/**
+ * Interface of a runnable plugin
+ */
+export interface PluginRunner {
+ /** Transformation function */
+ transform(data: V): T | Promise;
+}
+
+/**
+ * Interface of an SDK plugin
+ */
+export interface Plugin {
+ /** Load the plugin with the context */
+ load(context?: Record): PluginRunner;
+}
diff --git a/packages/sdk-client/src/plugins/core/request-plugin.ts b/packages/sdk-client/src/plugins/core/request-plugin.ts
new file mode 100644
index 00000000..013d4a47
--- /dev/null
+++ b/packages/sdk-client/src/plugins/core/request-plugin.ts
@@ -0,0 +1,27 @@
+import { Plugin, PluginRunner } from './plugin';
+import { Headers, RequestInit } from 'node-fetch';
+import FormData = require('form-data');
+
+export type RequestBody = string | FormData;
+
+export interface RequestOptions extends RequestInit {
+ /** Query Parameters */
+ queryParams?: { [key: string]: string };
+ /** Force body to string */
+ body?: RequestBody;
+ /** Force headers to Headers type */
+ headers: Headers;
+ /** URL targeted without the query parameters */
+ basePath: string;
+ /** Path of the API*/
+ path?: string;
+}
+
+/**
+ * Interface of an SDK request plugin.
+ * The plugin will be run on the request of a call
+ */
+export interface RequestPlugin extends Plugin {
+ /** Load the plugin with the context */
+ load(): PluginRunner;
+}
diff --git a/packages/sdk-client/src/plugins/core/response-plugin.ts b/packages/sdk-client/src/plugins/core/response-plugin.ts
new file mode 100644
index 00000000..32818d8c
--- /dev/null
+++ b/packages/sdk-client/src/plugins/core/response-plugin.ts
@@ -0,0 +1,40 @@
+import { Plugin, PluginRunner } from './plugin';
+import { Response } from 'node-fetch';
+import { RequestOptions } from './request-plugin';
+
+/**
+ * Interface of an SDK response plugin.
+ * The plugin will be run on the response of a call
+ */
+export interface ResponsePluginContext {
+ /** Response from Fetch call */
+ response?: Response;
+
+ /** Name of the API */
+ apiName: string;
+
+ /** Exception thrown during call/parse of the response */
+ exception?: Error;
+
+ /** Operation ID */
+ operationId: string;
+
+ /** Base url */
+ url: string;
+
+ /** Origin domain initiating the call */
+ origin?: string | null;
+
+ /** Request parameters */
+ requestOptions: RequestOptions;
+}
+
+/**
+ * Interface of an SDK response plugin.
+ * The plugin will be run on the response of a call
+ */
+export interface ResponsePlugin
+ extends Plugin {
+ /** Load the plugin with the context */
+ load(context: ResponsePluginContext): PluginRunner;
+}
diff --git a/packages/sdk-client/src/plugins/exception/exception.response.ts b/packages/sdk-client/src/plugins/exception/exception.response.ts
new file mode 100644
index 00000000..38b86c92
--- /dev/null
+++ b/packages/sdk-client/src/plugins/exception/exception.response.ts
@@ -0,0 +1,71 @@
+import { EmptyResponseError, RequestFailedError } from '../../api';
+import { PluginRunner, ResponsePlugin, ResponsePluginContext } from '../core';
+
+/**
+ * Plugin to fire an exception on wrong response / data
+ */
+export class ExceptionResponse<
+ V extends Record | undefined = Record,
+> implements ResponsePlugin, V>
+{
+/**
+ * Initialize an instance of the class, with an optional callback function for exception handling.
+ *
+ * @param {Function} [callback] - A function called in case of an exception. If provided, this function is responsible for throwing the exception or not.
+ */
+ constructor(private callback?: (res: V, error: Error | undefined) => V) {}
+
+ public load(
+ context: ResponsePluginContext,
+ ): PluginRunner, V> {
+ return {
+ transform: (res: V) => {
+ if (context.exception) {
+ return res;
+ }
+
+ const errorContext = {
+ apiName: context.apiName,
+ operationId: context.operationId,
+ url: context.url,
+ origin: context.origin,
+ };
+ let error: Error | undefined;
+
+ if (!context.response) {
+ error = new EmptyResponseError(
+ 'Fail to Fetch',
+ errorContext,
+ undefined,
+ );
+ } else if (!context.response.ok) {
+ error = new RequestFailedError(
+ context.response.statusText,
+ context.response.status,
+ errorContext,
+ res,
+ );
+ } else if (!res) {
+ res = {} as V;
+ if (context.response.status !== 204 && context.response.status !== 200) {
+ res = {} as V;
+ error = new EmptyResponseError(
+ context.response.statusText,
+ errorContext,
+ res,
+ );
+ }
+ }
+
+ if (error) {
+ if (this.callback) {
+ return this.callback(res, error);
+ } else {
+ throw error;
+ }
+ }
+ return res;
+ },
+ };
+ }
+}
diff --git a/packages/sdk-client/src/plugins/exception/index.ts b/packages/sdk-client/src/plugins/exception/index.ts
new file mode 100644
index 00000000..2cab08c7
--- /dev/null
+++ b/packages/sdk-client/src/plugins/exception/index.ts
@@ -0,0 +1 @@
+export * from './exception.response';
diff --git a/packages/sdk-client/src/plugins/exception/readme.md b/packages/sdk-client/src/plugins/exception/readme.md
new file mode 100644
index 00000000..ed0eaa5d
--- /dev/null
+++ b/packages/sdk-client/src/plugins/exception/readme.md
@@ -0,0 +1,7 @@
+## Exception
+
+Plugin to trigger an exception in case of wrong response / data based on the response status or custom criteria.
+
+### Type of plugins
+
+- Response plugin: [ExceptionResponse](./exception.response.ts);
diff --git a/packages/sdk-client/src/plugins/index.ts b/packages/sdk-client/src/plugins/index.ts
new file mode 100644
index 00000000..ca15aa77
--- /dev/null
+++ b/packages/sdk-client/src/plugins/index.ts
@@ -0,0 +1,8 @@
+export * from './core';
+export * from './api-token';
+export * from './basicAuthentication';
+export * from './exception';
+export * from './oauth2';
+export * from './signing';
+export * from './version';
+export * from './x-timestamp';
diff --git a/packages/sdk-client/src/plugins/oauth2/index.ts b/packages/sdk-client/src/plugins/oauth2/index.ts
new file mode 100644
index 00000000..ef28300a
--- /dev/null
+++ b/packages/sdk-client/src/plugins/oauth2/index.ts
@@ -0,0 +1,2 @@
+export * from './oauth2-api';
+export * from './oauth2-token.request';
diff --git a/packages/sdk-client/src/plugins/oauth2/oauth2-api.ts b/packages/sdk-client/src/plugins/oauth2/oauth2-api.ts
new file mode 100644
index 00000000..f7df9d9c
--- /dev/null
+++ b/packages/sdk-client/src/plugins/oauth2/oauth2-api.ts
@@ -0,0 +1,43 @@
+import { Api, ApiClient } from '../../api';
+
+export interface Response {
+ access_token: string;
+ expires_in: number;
+ scope: string;
+ token_type: string;
+}
+
+export class OAuth2Api implements Api {
+ /** @inheritDoc */
+ public readonly apiName = 'OAuth2Api';
+
+ /** @inheritDoc */
+ public readonly client: ApiClient;
+
+ constructor(apiClient: ApiClient) {
+ this.client = apiClient;
+ }
+
+ public async postAccessToken(): Promise {
+ const headers: { [key: string]: string } = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ };
+ const body = `${encodeURIComponent('grant_type')}=${encodeURIComponent(
+ 'client_credentials',
+ )}`;
+ const url = `${this.client.apiClientOptions.basePath}/oauth2/token`;
+ const requestOptions = await this.client.prepareOptions(
+ url,
+ 'POST',
+ {},
+ headers,
+ body,
+ );
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'OAuth2Token',
+ });
+ }
+}
diff --git a/packages/sdk-client/src/plugins/oauth2/oauth2-token.request.ts b/packages/sdk-client/src/plugins/oauth2/oauth2-token.request.ts
new file mode 100644
index 00000000..2051462d
--- /dev/null
+++ b/packages/sdk-client/src/plugins/oauth2/oauth2-token.request.ts
@@ -0,0 +1,96 @@
+import { PluginRunner, RequestOptions, RequestPlugin } from '../core';
+import { AdditionalHeadersRequest } from '../additional-headers';
+import { ApiClient } from '../../api';
+import { OAuth2Api } from './oauth2-api';
+import { BasicAuthenticationRequest } from '../basicAuthentication';
+import { ApiFetchClient } from '../../client';
+
+export class Oauth2TokenRequest implements RequestPlugin {
+ private readonly apiClient: ApiClient;
+
+ private token: AccessToken | undefined;
+
+ constructor(
+ clientId: string,
+ clientSecret: string,
+ authenticationUrl?: string,
+ ) {
+ const basicAuthenticationPlugin = new BasicAuthenticationRequest(
+ clientId,
+ clientSecret,
+ );
+ if (!authenticationUrl) {
+ authenticationUrl = 'https://auth.sinch.com';
+ }
+ this.apiClient = new ApiFetchClient({
+ basePath: authenticationUrl,
+ requestPlugins: [basicAuthenticationPlugin],
+ });
+ }
+
+ private async getOAuth2Token(): Promise<{ [key: string]: string }> {
+ if (this.isTokenValid()) {
+ return this.buildAuthorizationHeader();
+ }
+ const oauth2Api = new OAuth2Api(this.apiClient);
+ try {
+ const response = await oauth2Api.postAccessToken();
+ if (response.access_token) {
+ this.token = {
+ value: response.access_token,
+ status: TokenStatus.VALID,
+ };
+ return this.buildAuthorizationHeader();
+ } else {
+ this.token = {
+ value: '',
+ status: TokenStatus.INVALID,
+ };
+ console.error('No access_token has been returned. Response = ' + JSON.stringify(response));
+ return {};
+ }
+ } catch (e) {
+ this.token = {
+ value: '',
+ status: TokenStatus.INVALID,
+ };
+ console.error('An error occurred when trying to get the authentication token - ' + e);
+ return {};
+ }
+ }
+
+
+ private buildAuthorizationHeader() {
+ return { Authorization: `Bearer ${this.token!.value}` };
+ }
+
+ private isTokenValid(): boolean | undefined {
+ return (
+ this.token
+ && this.token.status === TokenStatus.VALID
+ && this.token.value.trim().length > 0
+ );
+ }
+
+ public load(): PluginRunner {
+ return {
+ transform: new AdditionalHeadersRequest({
+ headers: this.getOAuth2Token(),
+ }).load().transform,
+ };
+ }
+
+ public invalidateToken() {
+ this.token = undefined;
+ }
+}
+
+interface AccessToken {
+ value: string;
+ status: TokenStatus;
+}
+
+export enum TokenStatus {
+ INVALID,
+ VALID,
+}
diff --git a/packages/sdk-client/src/plugins/signing/index.ts b/packages/sdk-client/src/plugins/signing/index.ts
new file mode 100644
index 00000000..ee6a8288
--- /dev/null
+++ b/packages/sdk-client/src/plugins/signing/index.ts
@@ -0,0 +1 @@
+export * from './signing.request';
diff --git a/packages/sdk-client/src/plugins/signing/signing.request.ts b/packages/sdk-client/src/plugins/signing/signing.request.ts
new file mode 100644
index 00000000..448c958f
--- /dev/null
+++ b/packages/sdk-client/src/plugins/signing/signing.request.ts
@@ -0,0 +1,66 @@
+import { PluginRunner, RequestOptions, RequestPlugin } from '../core';
+import * as crypto from 'crypto';
+
+export const calculateMD5 = (body: string): string => {
+ // Content-MD5 = Base64 ( MD5 ( UTF8 ( [BODY] ) ) )
+ return crypto.createHash('md5').update(Buffer.from(body, 'utf-8')).digest('base64');
+};
+
+export const calculateHMACSHA256 = (secret: string, stringToSign: string): string => {
+ // Signature = Base64 ( HMAC-SHA256 ( Base64-Decode ( ApplicationSecret ), UTF8 ( StringToSign ) ) );
+ return crypto.createHmac('sha256', Buffer.from(secret, 'base64'))
+ .update(Buffer.from(stringToSign, 'utf-8'))
+ .digest('base64');
+};
+
+export const generateAuthorizationHeader = (
+ httpVerb: string,
+ contentMD5: string,
+ contentType: string,
+ canonicalizedHeaders: string,
+ canonicalizedResource: string,
+ applicationKey: string,
+ applicationSecret: string,
+): string => {
+ const stringToSign
+ = `${httpVerb}\n${contentMD5}\n${contentType}\n${canonicalizedHeaders}\n${canonicalizedResource}`;
+
+ const signature = calculateHMACSHA256(applicationSecret, stringToSign);
+ return `Application ${applicationKey}:${signature}`;
+};
+
+export class SigningRequest implements RequestPlugin {
+ private readonly applicationId: string;
+ private readonly applicationSecret: string;
+
+ constructor(applicationId: string, applicationSecret: string) {
+ this.applicationId = applicationId;
+ this.applicationSecret = applicationSecret;
+ }
+
+ public load(): PluginRunner {
+ return {
+ transform: (data: RequestOptions) => {
+ if (!data.method) {
+ throw new Error('The HTTP method must be defined.');
+ }
+ if (!data.path) {
+ throw new Error('The URL path must be defined.');
+ }
+ const hasBody = !!data.body;
+ const contentMD5 = hasBody ? calculateMD5(data.body as string) : '';
+ const authorizationHeader = generateAuthorizationHeader(
+ data.method.toUpperCase(),
+ contentMD5,
+ data.headers.get('Content-Type')!,
+ `x-timestamp:${data.headers.get('x-timestamp')}`,
+ data.path,
+ this.applicationId,
+ this.applicationSecret,
+ );
+ data.headers.append('Authorization', authorizationHeader);
+ return data;
+ },
+ };
+ }
+}
diff --git a/packages/sdk-client/src/plugins/version/index.ts b/packages/sdk-client/src/plugins/version/index.ts
new file mode 100644
index 00000000..94c0043c
--- /dev/null
+++ b/packages/sdk-client/src/plugins/version/index.ts
@@ -0,0 +1 @@
+export * from './version.request';
diff --git a/packages/sdk-client/src/plugins/version/version.request.ts b/packages/sdk-client/src/plugins/version/version.request.ts
new file mode 100644
index 00000000..90f18efd
--- /dev/null
+++ b/packages/sdk-client/src/plugins/version/version.request.ts
@@ -0,0 +1,22 @@
+import { PluginRunner, RequestOptions, RequestPlugin } from '../core';
+import * as process from 'process';
+// import version from '../../getVersion';
+import { sdkCoreVersion } from '../../getVersion';
+
+export class VersionRequest implements RequestPlugin {
+ public load(): PluginRunner {
+ const sdkVersion = sdkCoreVersion;
+ const languageVersion = process.version;
+ const implementationType = 'default';
+ const auxiliaryFlag = 'none';
+ return {
+ transform: (data: RequestOptions) => {
+ data.headers.append(
+ 'User-Agent',
+ `sinch-sdk/${sdkVersion} (JavaScript/${languageVersion}; ${implementationType}; ${auxiliaryFlag})`,
+ );
+ return data;
+ },
+ };
+ }
+}
diff --git a/packages/sdk-client/src/plugins/x-timestamp/index.ts b/packages/sdk-client/src/plugins/x-timestamp/index.ts
new file mode 100644
index 00000000..a809820c
--- /dev/null
+++ b/packages/sdk-client/src/plugins/x-timestamp/index.ts
@@ -0,0 +1 @@
+export * from './x-timestamp.request';
diff --git a/packages/sdk-client/src/plugins/x-timestamp/x-timestamp.request.ts b/packages/sdk-client/src/plugins/x-timestamp/x-timestamp.request.ts
new file mode 100644
index 00000000..7b21c86b
--- /dev/null
+++ b/packages/sdk-client/src/plugins/x-timestamp/x-timestamp.request.ts
@@ -0,0 +1,14 @@
+import { PluginRunner, RequestOptions, RequestPlugin } from '../core';
+
+export class XTimestampRequest implements RequestPlugin {
+
+ public load(): PluginRunner {
+ return {
+ transform: (data: RequestOptions) => {
+ data.headers.append('x-timestamp', new Date().toISOString());
+ return data;
+ },
+ };
+ }
+
+}
diff --git a/packages/sdk-client/src/utils/index.ts b/packages/sdk-client/src/utils/index.ts
new file mode 100644
index 00000000..fb3588ef
--- /dev/null
+++ b/packages/sdk-client/src/utils/index.ts
@@ -0,0 +1 @@
+export * from './text-to-hex';
diff --git a/packages/sdk-client/src/utils/text-to-hex.ts b/packages/sdk-client/src/utils/text-to-hex.ts
new file mode 100644
index 00000000..5c457b00
--- /dev/null
+++ b/packages/sdk-client/src/utils/text-to-hex.ts
@@ -0,0 +1,8 @@
+export const textToHex = (inputText: string) => {
+ let hexString = '';
+ for (let i = 0; i < inputText.length; i++) {
+ const hex = inputText.charCodeAt(i).toString(16);
+ hexString += hex.padStart(2, '0'); // Ensure each byte is represented by two hexadecimal digits
+ }
+ return hexString;
+};
diff --git a/packages/sdk-client/tests/plugins/pagination/test.ts b/packages/sdk-client/tests/plugins/pagination/test.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/sdk-client/tests/plugins/signing/signing.request.test.ts b/packages/sdk-client/tests/plugins/signing/signing.request.test.ts
new file mode 100644
index 00000000..0af7a8b9
--- /dev/null
+++ b/packages/sdk-client/tests/plugins/signing/signing.request.test.ts
@@ -0,0 +1,70 @@
+import { calculateHMACSHA256, calculateMD5, RequestOptions, SigningRequest } from '../../../src';
+import { Headers } from 'node-fetch';
+
+describe('Signed request plugin', () => {
+
+ it('should calculate the content-MD5 for the stringified JSON', () => {
+ const body = {
+ identity: {
+ type: 'number',
+ endpoint: '+33444555666',
+ },
+ method: 'sms',
+ };
+ expect(calculateMD5(JSON.stringify(body))).toBe('RkD29EocJh6t7zr5QfKM4g==');
+ });
+
+ it('should calculate the signature', () => {
+ const secret = btoa("my-secret");
+ const stringToSign = 'pKXhl9sOsUjClws1oANArA==';
+ expect(calculateHMACSHA256(secret, stringToSign)).toBe('1vZeB9AYiJthOvaZeZFhOxZWLSqHHFWzFw7AGjrTtmk=');
+ });
+
+ it('should create the authentication header for a request with a body', async () => {
+ const headers = new Headers();
+ headers.set('Content-Type', 'application/json; charset=UTF-8');
+ headers.set('x-timestamp', '2023-11-22T09:10:11.999Z');
+ const requestData = {
+ identity: {
+ type: 'number',
+ endpoint: '+33444555666',
+ },
+ method: 'sms',
+ };
+ const options: RequestOptions = {
+ method: 'post',
+ headers: headers,
+ body: JSON.stringify(requestData),
+ basePath: 'https://test.com/path/pathParamValue',
+ path: '/path/pathParamValue',
+ };
+ const plugin = new SigningRequest('my-key-id', btoa('my-key-secret'));
+ const runner = plugin.load();
+ const result = await runner.transform(options);
+
+ expect(result.headers.get('Content-Type')).toBe('application/json; charset=UTF-8');
+ expect(result.headers.get('Authorization'))
+ .toBe('Application my-key-id:QP3OzQZVzRZAEev6DBLvJkgpiqyZPuXYsc7oyjUV0K8=');
+ });
+
+ it('should create the authentication header for a request with no body', async () => {
+ const headers = new Headers();
+ headers.set('Content-Type', 'application/json');
+ headers.set('x-timestamp', '2023-11-22T09:10:11.999Z');
+ const options: RequestOptions = {
+ method: 'get',
+ headers: headers,
+ body: '',
+ basePath: 'https://test.com/path/pathParamValue',
+ path: '/path/pathParamValue',
+ };
+ const plugin = new SigningRequest('my-key-id', btoa('my-key-secret'));
+ const runner = plugin.load();
+ const result = await runner.transform(options);
+
+ expect(result.headers.get('Content-Type')).toBe('application/json');
+ expect(result.headers.get('Authorization'))
+ .toBe('Application my-key-id:nsrLDvP6KVD/dAxb3IfAncdwjPFJVWSrseEFOcZge+A=');
+ });
+
+});
diff --git a/packages/sdk-client/tsconfig.build.json b/packages/sdk-client/tsconfig.build.json
new file mode 100644
index 00000000..1130bcf1
--- /dev/null
+++ b/packages/sdk-client/tsconfig.build.json
@@ -0,0 +1,15 @@
+{
+ "extends": "../../tsconfig.json",
+
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist"
+ },
+
+ "include": ["src/**/*.ts"],
+ "exclude": ["node_modules", "dist"],
+
+ "ts-node": {
+ "esm": true
+ }
+}
diff --git a/packages/sdk-client/tsconfig.json b/packages/sdk-client/tsconfig.json
new file mode 100644
index 00000000..2684d3e0
--- /dev/null
+++ b/packages/sdk-client/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../tsconfig.json",
+ "references": [
+ {
+ "path": "tsconfig.build.json"
+ },
+ {
+ "path": "tsconfig.tests.json"
+ }
+ ]
+}
diff --git a/packages/sdk-client/tsconfig.tests.json b/packages/sdk-client/tsconfig.tests.json
new file mode 100644
index 00000000..d17c27ee
--- /dev/null
+++ b/packages/sdk-client/tsconfig.tests.json
@@ -0,0 +1,15 @@
+{
+ "extends": "../../tsconfig.json",
+
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "dist/tests"
+ },
+
+ "include": ["src/**/*.ts", "tests/**/*.ts"],
+ "exclude": ["node_modules", "dist"],
+
+ "ts-node": {
+ "esm": true
+ }
+}
diff --git a/packages/sdk-client/tt/itherTest.ts b/packages/sdk-client/tt/itherTest.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/sdk-client/tt/test.ts b/packages/sdk-client/tt/test.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/sdk-core/README.md b/packages/sdk-core/README.md
new file mode 100644
index 00000000..1d2186e7
--- /dev/null
+++ b/packages/sdk-core/README.md
@@ -0,0 +1,107 @@
+# Sinch server SDK for Node.js
+
+This package contains the Sinch Client SDK for Node.js. To use it, you will need a Sinch account. Please [sign up](https://dashboard.sinch.com/signup) or [log in](https://dashboard.sinch.com/login) if you already have one.
+
+Warning:
+**This SDK is currently available for preview purposes only. It should not be used in production environments.**
+
+## Installation
+
+### With NPM
+
+```bash
+npm install @sinch/sdk-core
+```
+
+### With Yarn
+
+```bash
+yarn add @sinch/sdk-core
+```
+
+## Usage
+
+The `@sinch/sdk-core` package contains the entry point for a SDK user: the `SinchClient` class. It will use the information given in parameters to initialize the right plugins for the right APIs.
+
+As there are different authentication schemes, the initialization method will depend on which one is used by the API.
+
+### OAuth2 Authentication
+
+```typescript
+import { SinchClient } from '@sinch/sdk-core';
+
+// The credentials can be found on the Account dashboard: https://dashboard.sinch.com/account/access-keys
+const sinch = new SinchClient({
+ projectId: 'my-project-id',
+ keyId: 'my-key-id',
+ keySecret: 'my-key-secret',
+});
+
+const response = await sinch.numbers.availableRegions.list({
+ types: 'LOCAL',
+});
+```
+The initialization method above will work for the APIs that supports the authentication with OAuth2 (Numbers and SMS on US and EU regions).
+
+### API Token authentication
+
+If you want to use the SMS API on the other regions (or US and EU too, it will work), you'll need other credentials in order to give to the Client the `servicePlanId` and the associated `apiToken`.
+
+```typescript
+import { SinchSmsClient } from '@sinch/sdk-core';
+
+// The credentials can be found on the Service APIs dashboard: https://dashboard.sinch.com/sms/api/services
+const sinch = new SinchClient({
+ servicePlanId: 'my-service-plan-id',
+ apiToken: 'my-key-id',
+ region: 'my-region', // Optional, can be 'us', 'eu', 'br', 'au', 'ca'. Default is 'us'
+});
+
+const response = await sinch.sms.batches.get({
+ batch_id: '01HF28S9AABBBCCCCY92BJB569',
+});
+```
+
+### Signed application authentication
+
+Both `Verification` and `Voice` APIs are using this authentication method: the request is encoded using the `Application Secret` and identified with the `Application Key`.
+
+```typescript
+import { SinchClient } from '@sinch/sdk-core';
+
+// The credentials can be found on the Verification or Voice dashboard:
+// https://dashboard.sinch.com/verification/apps or
+// https://dashboard.sinch.com/voice/apps
+const sinch = new SinchClient({
+ applicationId: 'my-application-key',
+ applicationSecret: 'my-application-secret',
+});
+
+const response = await sinch.verification.verificationStatus.getById({
+ id: '018bfc3e-1234-5678-1234-ebdb3fd6d30f',
+});
+```
+
+## Examples
+You can find an example of each request in the [../../examples/simple-examples](../../examples/simple-examples/) folder.
+
+## Contact
+Developer Experience team: [devexp@sinch.com](mailto:devexp@sinch.com)
+
+## Supported APIs
+
+Here is the list of the Sinch API and there level of support by the Node.js SDK:
+
+| API Category | API Name | Status |
+|------------------------|-------------------------------------|:------:|
+| Messaging | SMS API | ✅ |
+| | Conversation API | ❌ |
+| | RCS API | ❌ |
+| | MMS API | ❌ |
+| | Provisioning API | ❌ |
+| Voice and Video | Voice API | ❌ |
+| | Elastic SIP Trunking | ❌ |
+| Numbers & Connectivity | Numbers API | ✅ |
+| | Brand and Campaign Registration API | ❌ |
+| | Number Lookup API | ❌ |
+| Verification | Verification API | ✅ |
diff --git a/packages/sdk-core/package.json b/packages/sdk-core/package.json
new file mode 100644
index 00000000..4d71edf7
--- /dev/null
+++ b/packages/sdk-core/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "@sinch/sdk-core",
+ "version": "0.0.0",
+ "description": "Node.js client for the Sinch API platform",
+ "homepage": "",
+ "repository": {
+ "type": "git",
+ "url": ""
+ },
+ "license": "Apache-2.0",
+ "author": "Sinch",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": "./dist/index.js",
+ "require": "./dist/index.js"
+ },
+ "./package.json": "./package.json"
+ },
+ "directories": {
+ "src": "dist",
+ "test": "tests"
+ },
+ "files": ["/dist"],
+ "scripts": {
+ "build": "yarn run clean && yarn run compile",
+ "clean": "rimraf dist tsconfig.tsbuildinfo",
+ "compile": "tsc --build --verbose"
+ },
+ "dependencies": {
+ "@sinch/numbers": "^0.0.0",
+ "@sinch/sms": "^0.0.0",
+ "@sinch/verification": "^0.0.0"
+ },
+ "devDependencies": {},
+ "publishConfig": {
+ "directory": "dist"
+ }
+}
diff --git a/packages/sdk-core/src/index.ts b/packages/sdk-core/src/index.ts
new file mode 100644
index 00000000..7a3f9336
--- /dev/null
+++ b/packages/sdk-core/src/index.ts
@@ -0,0 +1,4 @@
+export * from './sinch-client';
+export * from '@sinch/numbers';
+export * from '@sinch/sms';
+export * from '@sinch/verification';
diff --git a/packages/sdk-core/src/sinch-client.ts b/packages/sdk-core/src/sinch-client.ts
new file mode 100644
index 00000000..75cdc783
--- /dev/null
+++ b/packages/sdk-core/src/sinch-client.ts
@@ -0,0 +1,28 @@
+import { Numbers } from '@sinch/numbers';
+import { Sms } from '@sinch/sms';
+import { Verification } from '@sinch/verification';
+import { SinchClientParameters } from '@sinch/sdk-client';
+
+/** Sinch Client to declare and initialize the supported APIs */
+export class SinchClient {
+
+ public readonly numbers: Numbers;
+ public readonly sms: Sms;
+ public readonly verification: Verification;
+
+ /**
+ * Initialize your API Client instance with the provided credentials.
+ *
+ * @param {SinchClientParameters} params - The object containing the Sinch credentials.
+ */
+ constructor(params: SinchClientParameters) {
+ // Initialize the "Numbers" API
+ this.numbers = new Numbers(params);
+
+ // Initialize the "SMS" API.
+ this.sms = new Sms(params);
+
+ // Initialize the "Verification" API
+ this.verification = new Verification(params);
+ }
+}
diff --git a/packages/sdk-core/tsconfig.json b/packages/sdk-core/tsconfig.json
new file mode 100644
index 00000000..ad5958b7
--- /dev/null
+++ b/packages/sdk-core/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "extends": "../../tsconfig.json",
+
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist"
+ },
+
+ "exclude": ["tests", "jest.config.js", "dist"],
+
+ "ts-node": {
+ "esm": true
+ }
+}
diff --git a/packages/sms/README.md b/packages/sms/README.md
new file mode 100644
index 00000000..f4e47666
--- /dev/null
+++ b/packages/sms/README.md
@@ -0,0 +1,166 @@
+# Sinch SMS SDK for Node.js
+
+This package contains the Sinch SMS SDK for Node.js for use with [Sinch APIs](https://developers.sinch.com/). To use it, you will need a Sinch account. Please [sign up](https://dashboard.sinch.com/signup) or [log in](https://dashboard.sinch.com/login) if you already have one.
+
+Warning:
+**This SDK is currently available for preview purposes only. It should not be used in production environments.**
+
+## Installation
+
+We recommend to use this SDK as part of the `@sinch/sdk-core` package as it will take care about the authentication plugins to use.
+
+However, it's still possible to use this SDK standalone is you need to access the SMS API only.
+
+### With NPM
+
+```bash
+npm install @sinch/sms
+```
+
+### With Yarn
+
+```bash
+yarn add @sinch/sms
+```
+
+## Usage
+
+### Credentials
+
+The `SMS` API uses the Sinch unified authentication with OAuth2 **for the US and EU regions only**. You will need to provide the following credentials:
+- projectId: can be found in the [Account Dashboard](https://dashboard.sinch.com/settings/access-keys)
+- keyId:: can be found in your Access key list in the [Account Dashboard](https://dashboard.sinch.com/settings/access-keys)
+- keySecret: can be found **ONLY** when generating a new access key: keep it safe!
+
+If you want to use the other regions (BR, AU or CA) or if you prefer to use this type of credential for US or EU, you can use the API Token authentication. You will need to provide the following credentials:
+- servicePlanId: can be found in the SMS dashboard, under [Services Apis](https://dashboard.sinch.com/sms/api/services)
+- apiToken: can be found in the SMS dashboard, under [Services Apis](https://dashboard.sinch.com/sms/api/services)
+
+
+### As part of the Sinch SDK
+
+If you are using this SDK as part of the Sinch SDK (`@sinch/sdk-core`) you can access it as the `sms` property of the client that you would have instantiated.
+
+```typescript
+import {
+ SendSMSRequestData,
+ SendSMSResponse,
+ SinchClient,
+ SinchSmsClient,
+ SinchClientParameters,
+ Region,
+} from '@sinch/sdk-core';
+
+const credentialsWithProjectId: SinchClientParameters = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+ region: Region.UNITED_STATES, // Optional, default is 'us'. Only other possibility is 'eu'
+};
+const sinchWithProjectId = new SinchClient(credentialsWithProjectId);
+
+const credentialsWithServicePlanId: SinchClientParameters = {
+ servicePlanId: 'SERVICE_PLAN_ID',
+ apiToken: 'API_TOKEN',
+ region: Region.UNITED_STATES, // Optional, default is 'us'. Other possibilities are 'eu', 'br', 'au' and 'ca'
+};
+const sinchWithServicePlanId = new SinchClient(credentialsWithServicePlanId);
+
+const requestData: SendSMSRequestData = {
+ SendSMSRequest: {
+ to: [
+ '+12223334444',
+ '+12223335555'
+ ],
+ from: '+12228889999',
+ parameters: {
+ name: {
+ '+12223334444': 'John',
+ default: 'there',
+ }
+ },
+ body: 'Hi ${name}',
+ type: 'mt_text',
+ },
+};
+
+// Access the 'sms' domain registered on the Sinch Client
+// The request will be authenticated with OAuth2 and sent to https://zt.us.sms.api.sinch.com/xms/v1
+const availabilityResult_1: SendSMSResponse
+ = await sinchWithProjectId.sms.batches.send(requestData);
+
+// Access the 'sms' domain registered on the Sinch Client
+// The request will be authenticated with the API Token and sent to https://us.sms.api.sinch.com/xms/v1
+const availabilityResult_2: SendSMSResponse
+ = await sinchWithServicePlanId.sms.batches.send(requestData);
+```
+
+### Standalone
+
+The SDK can be used standalone if you need to use only the SMS APIs. As for a usage with the Sinch Client, you can choose to use the `projectId` or `servicePlanId` credentials.
+
+#### With the Oauth2TokenRequest plugin
+
+```typescript
+import {
+ Region,
+ SinchClientParameters,
+ } from '@sinch/sdk-client';
+import {
+ SendSMSRequestData,
+ SendSMSResponse,
+ Sms,
+} from '@sinch/sms';
+
+const credentialsWithProjectId: SinchClientParameters = {
+ projectId: 'PROJECT_ID',
+ keyId: 'KEY_ID',
+ keySecret: 'KEY_SECRET',
+ region: Region.UNITED_STATES, // Optional, default is 'us'. Only other possibility is 'eu'
+};
+// Declare the 'sms' in a standalone way
+const smsWithProjectId = new Sms(credentialsWithProjectId);
+
+const credentialsWithServicePlanId: SinchClientParameters = {
+ servicePlanId: 'SERVICE_PLAN_ID',
+ apiToken: 'API_TOKEN',
+ region: Region.UNITED_STATES, // Optional, default is 'us'. Other possibilities are 'eu', 'br', 'au' and 'ca'
+};
+// Declare the 'sms' in a standalone way
+const smsWithServicePlanId = new Sms(credentialsWithServicePlanId);
+
+const requestData: SendSMSRequestData = {
+ // some request parameters
+};
+
+// Use the standalone declaration of the 'sms' domain
+// The request will be authenticated with OAuth2 and sent to https://zt.us.sms.api.sinch.com/xms/v1
+const response_1: SendSMSResponse = await smsWithProjectId.batches.send(requestData);
+
+// Use the standalone declaration of the 'sms' domain
+// The request will be authenticated with the API Token and sent to https://us.sms.api.sinch.com/xms/v1
+const response_2: SendSMSResponse = await smsWithServicePlanId.batches.send(requestData);
+```
+
+## Promises
+
+All the methods that interact with the Sinch APIs use Promises. You can use `await` in an `async` method to wait for the response or you can resolve them yourself with `then()` / `catch()`.
+
+```typescript
+// Method 1: Wait for the Promise to complete
+let response: SendSMSResponse;
+try {
+ response = await sinch.sms.batches.send(requestData);
+ console.log(`The SMS has been sent successfully: batch id = ${response.id}`);
+} catch (error: any) {
+ console.error(`ERROR ${error.statusCode}: the SMS could not be sent`);
+}
+
+// Method 2: Resolve the promise
+sinch.sms.batches.send(requestData)
+ .then(response => console.log(`The SMS has been sent successfully: batch id = ${response.id}`))
+ .catch(error => console.error(`ERROR ${error.statusCode}: the SMS could not be sent`));
+```
+
+## Contact
+Developer Experience team: [devexp@sinch.com](mailto:devexp@sinch.com)
diff --git a/packages/sms/package.json b/packages/sms/package.json
new file mode 100644
index 00000000..56254773
--- /dev/null
+++ b/packages/sms/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "@sinch/sms",
+ "version": "0.0.0",
+ "description": "Sinch SMS API",
+ "homepage": "",
+ "repository": {
+ "type": "git",
+ "url": ""
+ },
+ "license": "Apache-2.0",
+ "author": "Sinch",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": "./dist/index.js",
+ "require": "./dist/index.js"
+ }
+ },
+ "directories": {
+ "src": "dist",
+ "test": "tests"
+ },
+ "files": ["/dist"],
+ "scripts": {
+ "build": "yarn run clean && yarn run compile",
+ "clean": "rimraf dist tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo",
+ "compile": "tsc -p tsconfig.build.json && tsc -p tsconfig.tests.json && rimraf dist/tests tsconfig.build.tsbuildinfo"
+ },
+ "dependencies": {
+ "@sinch/sdk-client": "^0.0.0"
+ },
+ "devDependencies": {},
+ "publishConfig": {
+ "directory": "dist"
+ }
+}
diff --git a/packages/sms/src/index.ts b/packages/sms/src/index.ts
new file mode 100644
index 00000000..20936a85
--- /dev/null
+++ b/packages/sms/src/index.ts
@@ -0,0 +1,3 @@
+export * from './models';
+export * from './rest';
+export * from '@sinch/sdk-client';
diff --git a/packages/sms/src/models/index.ts b/packages/sms/src/models/index.ts
new file mode 100644
index 00000000..5b98253d
--- /dev/null
+++ b/packages/sms/src/models/index.ts
@@ -0,0 +1 @@
+export * from './v1';
diff --git a/packages/sms/src/models/v1/api-batch-list-batches-inner/api-batch-list-batches-inner.ts b/packages/sms/src/models/v1/api-batch-list-batches-inner/api-batch-list-batches-inner.ts
new file mode 100644
index 00000000..886cc561
--- /dev/null
+++ b/packages/sms/src/models/v1/api-batch-list-batches-inner/api-batch-list-batches-inner.ts
@@ -0,0 +1,12 @@
+/**
+ * Model: ApiBatchListBatchesInner
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { BinaryResponse } from '../binary-response';
+import { MediaResponse } from '../media-response';
+import { TextResponse } from '../text-response';
+
+export type ApiBatchListBatchesInner = BinaryResponse | MediaResponse | TextResponse;
diff --git a/packages/sms/src/models/v1/api-batch-list-batches-inner/index.ts b/packages/sms/src/models/v1/api-batch-list-batches-inner/index.ts
new file mode 100644
index 00000000..382a1eef
--- /dev/null
+++ b/packages/sms/src/models/v1/api-batch-list-batches-inner/index.ts
@@ -0,0 +1 @@
+export type { ApiBatchListBatchesInner } from './api-batch-list-batches-inner';
diff --git a/packages/sms/src/models/v1/api-batch-list/api-batch-list.ts b/packages/sms/src/models/v1/api-batch-list/api-batch-list.ts
new file mode 100644
index 00000000..9b56d4f8
--- /dev/null
+++ b/packages/sms/src/models/v1/api-batch-list/api-batch-list.ts
@@ -0,0 +1,22 @@
+/**
+ * Model: ApiBatchList
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ApiBatchListBatchesInner } from '../api-batch-list-batches-inner';
+
+export interface ApiBatchList {
+
+ /** The total number of entries matching the given filters. */
+ count?: number;
+ /** The requested page. */
+ page?: number;
+ /** The page of batches matching the given filters. */
+ batches?: ApiBatchListBatchesInner[];
+ /** The number of entries returned in this request. */
+ page_size?: number;
+}
+
+
diff --git a/packages/sms/src/models/v1/api-batch-list/index.ts b/packages/sms/src/models/v1/api-batch-list/index.ts
new file mode 100644
index 00000000..958333df
--- /dev/null
+++ b/packages/sms/src/models/v1/api-batch-list/index.ts
@@ -0,0 +1 @@
+export type { ApiBatchList } from './api-batch-list';
diff --git a/packages/sms/src/models/v1/api-inbound-list/api-inbound-list.ts b/packages/sms/src/models/v1/api-inbound-list/api-inbound-list.ts
new file mode 100644
index 00000000..de254143
--- /dev/null
+++ b/packages/sms/src/models/v1/api-inbound-list/api-inbound-list.ts
@@ -0,0 +1,22 @@
+/**
+ * Model: ApiInboundList
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { InboundMessageResponse } from '../inbound-message-response';
+
+export interface ApiInboundList {
+
+ /** The total number of inbounds matching the given filters */
+ count?: number;
+ /** The requested page. */
+ page?: number;
+ /** The page of inbounds matching the given filters. */
+ inbounds?: InboundMessageResponse[];
+ /** The number of inbounds returned in this request. */
+ page_size?: number;
+}
+
+
diff --git a/packages/sms/src/models/v1/api-inbound-list/index.ts b/packages/sms/src/models/v1/api-inbound-list/index.ts
new file mode 100644
index 00000000..c87c408b
--- /dev/null
+++ b/packages/sms/src/models/v1/api-inbound-list/index.ts
@@ -0,0 +1 @@
+export type { ApiInboundList } from './api-inbound-list';
diff --git a/packages/sms/src/models/v1/api-mo-message/api-mo-message.ts b/packages/sms/src/models/v1/api-mo-message/api-mo-message.ts
new file mode 100644
index 00000000..42a14783
--- /dev/null
+++ b/packages/sms/src/models/v1/api-mo-message/api-mo-message.ts
@@ -0,0 +1,32 @@
+/**
+ * Model: ApiMoMessage
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+/**
+ * The page of inbounds matching the given filters.
+ */
+export interface ApiMoMessage {
+
+ body?: string;
+ /** If this inbound message is in response to a previously sent message that contained a client reference, then this field contains *that* client reference. Utilizing this feature requires additional setup on your account. Contact your account manager to enable this feature. */
+ client_reference?: string;
+ /** The phone number that sent the message. More info */
+ from: string;
+ /** The ID of this inbound message. */
+ id: string;
+ /** The MCC/MNC of the sender\'s operator if known. */
+ operator_id?: string;
+ /** When the system received the message. Formatted as ISO-8601: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ received_at: Date;
+ /** When the message left the originating device. Only available if provided by operator. Formatted as ISO-8601: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ sent_at?: Date;
+ /** The Sinch phone number or short code to which the message was sent. */
+ to: string;
+ type: string;
+}
+
+
diff --git a/packages/sms/src/models/v1/api-mo-message/index.ts b/packages/sms/src/models/v1/api-mo-message/index.ts
new file mode 100644
index 00000000..227082df
--- /dev/null
+++ b/packages/sms/src/models/v1/api-mo-message/index.ts
@@ -0,0 +1 @@
+export type { ApiMoMessage } from './api-mo-message';
diff --git a/packages/sms/src/models/v1/api-update-binary-mt-message/api-update-binary-mt-message.ts b/packages/sms/src/models/v1/api-update-binary-mt-message/api-update-binary-mt-message.ts
new file mode 100644
index 00000000..5d6f6d2a
--- /dev/null
+++ b/packages/sms/src/models/v1/api-update-binary-mt-message/api-update-binary-mt-message.ts
@@ -0,0 +1,35 @@
+/**
+ * Model: ApiUpdateBinaryMtMessage
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+import { DeliveryReportEnum } from '../enums';
+
+
+export interface ApiUpdateBinaryMtMessage {
+
+ /** Sender number. Must be valid phone number, short code or alphanumeric. */
+ from?: string;
+ /** SMS in binary format */
+ type?: TypeEnum;
+ /** List of phone numbers and group IDs to add to the batch. */
+ to_add?: string[];
+ /** List of phone numbers and group IDs to remove from the batch. */
+ to_remove?: string[];
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set, in the future the message will be delayed until `send_at` occurs. Formatted as ISO-8601: `YYYY-MM-DDThh:mm:ss.SSSZ`. Constraints: Must be before expire_at. If set in the past, messages will be sent immediately. */
+ send_at?: Date;
+ /** If set, the system will stop trying to deliver the message at this point. Constraints: Must be after `send_at` Default: 3 days after `send_at` */
+ expire_at?: Date;
+ /** Override the default callback URL for this batch. Constraints: Must be valid URL. */
+ callback_url?: string;
+ /** The message content Base64 encoded. Max 140 bytes together with udh. */
+ body?: string;
+ /** The UDH header of a binary message HEX encoded. Max 140 bytes together with body. */
+ udh?: string;
+}
+
+export type TypeEnum = 'mt_binary';
+
diff --git a/packages/sms/src/models/v1/api-update-binary-mt-message/index.ts b/packages/sms/src/models/v1/api-update-binary-mt-message/index.ts
new file mode 100644
index 00000000..999a65a5
--- /dev/null
+++ b/packages/sms/src/models/v1/api-update-binary-mt-message/index.ts
@@ -0,0 +1 @@
+export type { ApiUpdateBinaryMtMessage } from './api-update-binary-mt-message';
diff --git a/packages/sms/src/models/v1/api-update-mms-mt-message/api-update-mms-mt-message.ts b/packages/sms/src/models/v1/api-update-mms-mt-message/api-update-mms-mt-message.ts
new file mode 100644
index 00000000..164d2611
--- /dev/null
+++ b/packages/sms/src/models/v1/api-update-mms-mt-message/api-update-mms-mt-message.ts
@@ -0,0 +1,39 @@
+/**
+ * Model: ApiUpdateMmsMtMessage
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { MediaBody } from '../media-body';
+import { ParameterObj } from '../parameter-obj';
+import { DeliveryReportEnum } from '../enums';
+
+export interface ApiUpdateMmsMtMessage {
+
+ /** Sender number. Must be valid phone number, short code or alphanumeric. */
+ from?: string;
+ /** MMS */
+ type?: TypeEnum;
+ /** List of phone numbers and group IDs to add to the batch. */
+ to_add?: string[];
+ /** List of phone numbers and group IDs to remove from the batch. */
+ to_remove?: string[];
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set, in the future the message will be delayed until `send_at` occurs. Formatted as ISO-8601: `YYYY-MM-DDThh:mm:ss.SSSZ`. Constraints: Must be before expire_at. If set in the past, messages will be sent immediately. */
+ send_at?: Date;
+ /** If set, the system will stop trying to deliver the message at this point. Constraints: Must be after `send_at` Default: 3 days after `send_at` */
+ expire_at?: Date;
+ /** Override the default callback URL for this batch. Constraints: Must be valid URL. */
+ callback_url?: string;
+ /** @see MediaBody */
+ body?: MediaBody;
+ /** @see ParameterObj */
+ parameters?: ParameterObj;
+ /** Whether or not you want the media included in your message to be checked against [Sinch MMS channel best practices](/docs/mms/bestpractices/). If set to true, your message will be rejected if it doesn\'t conform to the listed recommendations, otherwise no validation will be performed. */
+ strict_validation?: boolean;
+}
+
+export type TypeEnum = 'mt_media';
+
diff --git a/packages/sms/src/models/v1/api-update-mms-mt-message/index.ts b/packages/sms/src/models/v1/api-update-mms-mt-message/index.ts
new file mode 100644
index 00000000..eeede3b7
--- /dev/null
+++ b/packages/sms/src/models/v1/api-update-mms-mt-message/index.ts
@@ -0,0 +1 @@
+export type { ApiUpdateMmsMtMessage } from './api-update-mms-mt-message';
diff --git a/packages/sms/src/models/v1/api-update-mt-message/api-update-mt-message.ts b/packages/sms/src/models/v1/api-update-mt-message/api-update-mt-message.ts
new file mode 100644
index 00000000..afbba270
--- /dev/null
+++ b/packages/sms/src/models/v1/api-update-mt-message/api-update-mt-message.ts
@@ -0,0 +1,29 @@
+/**
+ * Model: ApiUpdateMtMessage
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+import { DeliveryReportEnum } from '../enums';
+
+
+export interface ApiUpdateMtMessage {
+
+ /** Sender number. Must be valid phone number, short code or alphanumeric. */
+ from?: string;
+ type?: string;
+ /** List of phone numbers and group IDs to add to the batch. */
+ to_add?: string[];
+ /** List of phone numbers and group IDs to remove from the batch. */
+ to_remove?: string[];
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set, in the future the message will be delayed until `send_at` occurs. Formatted as ISO-8601: `YYYY-MM-DDThh:mm:ss.SSSZ`. Constraints: Must be before expire_at. If set in the past, messages will be sent immediately. */
+ send_at?: Date;
+ /** If set, the system will stop trying to deliver the message at this point. Constraints: Must be after `send_at` Default: 3 days after `send_at` */
+ expire_at?: Date;
+ /** Override the default callback URL for this batch. Constraints: Must be valid URL. */
+ callback_url?: string;
+}
+
+
diff --git a/packages/sms/src/models/v1/api-update-mt-message/index.ts b/packages/sms/src/models/v1/api-update-mt-message/index.ts
new file mode 100644
index 00000000..57519bd6
--- /dev/null
+++ b/packages/sms/src/models/v1/api-update-mt-message/index.ts
@@ -0,0 +1 @@
+export type { ApiUpdateMtMessage } from './api-update-mt-message';
diff --git a/packages/sms/src/models/v1/api-update-text-mt-message/api-update-text-mt-message.ts b/packages/sms/src/models/v1/api-update-text-mt-message/api-update-text-mt-message.ts
new file mode 100644
index 00000000..34986eb9
--- /dev/null
+++ b/packages/sms/src/models/v1/api-update-text-mt-message/api-update-text-mt-message.ts
@@ -0,0 +1,36 @@
+/**
+ * Model: ApiUpdateTextMtMessage
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ParameterObj } from '../parameter-obj';
+import { DeliveryReportEnum } from '../enums';
+
+export interface ApiUpdateTextMtMessage {
+
+ /** Sender number. Must be valid phone number, short code or alphanumeric. */
+ from?: string;
+ /** Regular SMS */
+ type?: TypeEnum;
+ /** List of phone numbers and group IDs to add to the batch. */
+ to_add?: string[];
+ /** List of phone numbers and group IDs to remove from the batch. */
+ to_remove?: string[];
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set, in the future the message will be delayed until `send_at` occurs. Formatted as ISO-8601: `YYYY-MM-DDThh:mm:ss.SSSZ`. Constraints: Must be before expire_at. If set in the past, messages will be sent immediately. */
+ send_at?: Date;
+ /** If set, the system will stop trying to deliver the message at this point. Constraints: Must be after `send_at` Default: 3 days after `send_at` */
+ expire_at?: Date;
+ /** Override the default callback URL for this batch. Constraints: Must be valid URL. */
+ callback_url?: string;
+ /** @see ParameterObj */
+ parameters?: ParameterObj;
+ /** The message content */
+ body?: string;
+}
+
+export type TypeEnum = 'mt_text' | 'mt_binary' | 'mt_media';
+
diff --git a/packages/sms/src/models/v1/api-update-text-mt-message/index.ts b/packages/sms/src/models/v1/api-update-text-mt-message/index.ts
new file mode 100644
index 00000000..0f57af19
--- /dev/null
+++ b/packages/sms/src/models/v1/api-update-text-mt-message/index.ts
@@ -0,0 +1 @@
+export type { ApiUpdateTextMtMessage } from './api-update-text-mt-message';
diff --git a/packages/sms/src/models/v1/binary-request/binary-request.ts b/packages/sms/src/models/v1/binary-request/binary-request.ts
new file mode 100644
index 00000000..a9352465
--- /dev/null
+++ b/packages/sms/src/models/v1/binary-request/binary-request.ts
@@ -0,0 +1,47 @@
+/**
+ * Model: BinaryRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+import { DeliveryReportEnum } from '../enums';
+
+
+export interface BinaryRequest {
+
+ /** A list of phone numbers and group IDs that will receive the batch. [More info](https://community.sinch.com/t5/Glossary/MSISDN/ta-p/7628). */
+ to: string[];
+ /** Sender number. Must be valid phone number, short code or alphanumeric. Required if Automatic Default Originator not configured. */
+ from?: string;
+ /** The message content Base64 encoded. Max 140 bytes including `udh`. */
+ body: string;
+ /** The UDH header of a binary message HEX encoded. Max 140 bytes including the `body`. */
+ udh: string;
+ /** SMS in binary format. */
+ type?: TypeEnum;
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set in the future the message will be delayed until `send_at` occurs. Must be before `expire_at`. If set in the past, messages will be sent immediately. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601). For example: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ send_at?: Date;
+ /** If set, the system will stop trying to deliver the message at this point. Must be after `send_at`. Default and max is 3 days after `send_at`. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601). For example: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ expire_at?: Date;
+ /** Override the *default* callback URL for this batch. Must be a valid URL. Learn how to set a default callback URL here. */
+ callback_url?: string;
+ /** The client identifier of a batch message. If set, the identifier will be added in the delivery report/callback of this batch. */
+ client_reference?: string;
+ /** If set to true then [feedback](/docs/sms/api-reference/sms/tag/Batches/#tag/Batches/operation/deliveryFeedback) is expected after successful delivery. */
+ feedback_enabled?: boolean;
+ /** Shows message on screen without user interaction while not saving the message to the inbox. */
+ flash_message?: boolean;
+ /** If set to `true`, the message will be shortened when exceeding one part. */
+ truncate_concat?: boolean;
+ /** Message will be dispatched only if it is not split to more parts than the maximum number of message parts. */
+ max_number_of_message_parts?: number;
+ /** The type of number for the sender number. Use to override the automatic detection. */
+ from_ton?: number;
+ /** Number Plan Indicator for the sender number. Use to override the automatic detection. */
+ from_npi?: number;
+}
+
+export type TypeEnum = 'mt_binary';
+
diff --git a/packages/sms/src/models/v1/binary-request/index.ts b/packages/sms/src/models/v1/binary-request/index.ts
new file mode 100644
index 00000000..7888e4ec
--- /dev/null
+++ b/packages/sms/src/models/v1/binary-request/index.ts
@@ -0,0 +1 @@
+export type { BinaryRequest } from './binary-request';
diff --git a/packages/sms/src/models/v1/binary-response/binary-response.ts b/packages/sms/src/models/v1/binary-response/binary-response.ts
new file mode 100644
index 00000000..5b287efe
--- /dev/null
+++ b/packages/sms/src/models/v1/binary-response/binary-response.ts
@@ -0,0 +1,55 @@
+/**
+ * Model: BinaryResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+import { DeliveryReportEnum } from '../enums';
+
+
+export interface BinaryResponse {
+
+ /** Unique identifier for batch. */
+ id?: string;
+ /** A list of phone numbers and group IDs that have received the batch. [More info](https://community.sinch.com/t5/Glossary/MSISDN/ta-p/7628). */
+ to?: string[];
+ /** The sender number provided. Required if the Automatic Default Originator is not configured. */
+ from?: string;
+ /** Indicates whether or not the batch has been canceled. */
+ canceled?: boolean;
+ /** The message content provided. Base64 encoded. */
+ body?: string;
+ /** The UDH header of a binary message HEX encoded. Max 140 bytes including the `body`. */
+ udh?: string;
+ /** SMS in binary format. */
+ type?: TypeEnum;
+ /** Timestamp for when batch was created. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601). For example: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ created_at?: Date;
+ /** Timestamp for when batch was last updated. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601). For example: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ modified_at?: Date;
+ /** The delivery report callback option selected. Will be either `none`, `summary`, `full`, `per_recipient`, or `per_recipient_final`. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set, the date and time the message should be delivered. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601). For example: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ send_at?: Date;
+ /** If set, the date and time the message will expire. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601). For example: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ expire_at?: Date;
+ /** The callback URL provided in the request. */
+ callback_url?: string;
+ /** The string input to identify this batch message. If set, the identifier will be added in the delivery report/callback of this batch. */
+ client_reference?: string;
+ /** If set to true, then [feedback](/docs/sms/api-reference/sms/tag/Batches/#tag/Batches/operation/deliveryFeedback) is expected after successful delivery. */
+ feedback_enabled?: boolean;
+ /** If sent as a flash message, displays `true`. */
+ flash_message?: boolean;
+ /** If set to `true`, the message was shortened when exceeding one part. */
+ truncate_concat?: boolean;
+ /** Displays the number of message parts set in the request. */
+ max_number_of_message_parts?: number;
+ /** The type of number for the sender number. */
+ from_ton?: number;
+ /** Number Plan Indicator for the sender number. */
+ from_npi?: number;
+}
+
+export type TypeEnum = 'mt_binary';
+
diff --git a/packages/sms/src/models/v1/binary-response/index.ts b/packages/sms/src/models/v1/binary-response/index.ts
new file mode 100644
index 00000000..1edfd839
--- /dev/null
+++ b/packages/sms/src/models/v1/binary-response/index.ts
@@ -0,0 +1 @@
+export type { BinaryResponse } from './binary-response';
diff --git a/packages/sms/src/models/v1/create-group-request/create-group-request.ts b/packages/sms/src/models/v1/create-group-request/create-group-request.ts
new file mode 100644
index 00000000..113f85f0
--- /dev/null
+++ b/packages/sms/src/models/v1/create-group-request/create-group-request.ts
@@ -0,0 +1,22 @@
+/**
+ * Model: CreateGroupRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { GroupObjectAutoUpdate } from '../group-object-auto-update';
+
+export interface CreateGroupRequest {
+
+ /** Name of the group */
+ name?: string;
+ /** \"Initial list of phone numbers in E.164 format MSISDNs for the group.\" */
+ members?: string[];
+ /** Phone numbers (MSISDNs) of child group will be included in this group. If present then this group will be auto populated. Constraints: Elements must be group IDs. */
+ child_groups?: string[];
+ /** @see GroupObjectAutoUpdate */
+ auto_update?: GroupObjectAutoUpdate;
+}
+
+
diff --git a/packages/sms/src/models/v1/create-group-request/index.ts b/packages/sms/src/models/v1/create-group-request/index.ts
new file mode 100644
index 00000000..6bc4ea0d
--- /dev/null
+++ b/packages/sms/src/models/v1/create-group-request/index.ts
@@ -0,0 +1 @@
+export type { CreateGroupRequest } from './create-group-request';
diff --git a/packages/sms/src/models/v1/create-group-response/create-group-response.ts b/packages/sms/src/models/v1/create-group-response/create-group-response.ts
new file mode 100644
index 00000000..d4729737
--- /dev/null
+++ b/packages/sms/src/models/v1/create-group-response/create-group-response.ts
@@ -0,0 +1,28 @@
+/**
+ * Model: CreateGroupResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { GroupAutoUpdate } from '../group-auto-update';
+
+export interface CreateGroupResponse {
+
+ /** The ID used to reference this group. */
+ id?: string;
+ /** Name of group, if set. */
+ name?: string;
+ /** The number of members currently in the group. */
+ size?: number;
+ /** Timestamp for group creation. Format: YYYY-MM-DDThh:mm:ss.SSSZ */
+ created_at?: Date;
+ /** Timestamp for when the group was last updated. Format: YYYY-MM-DDThh:mm:ss.SSSZ */
+ modified_at?: Date;
+ /** Phone numbers (MSISDNs) of child group will be included in this group. If present, this group will be auto populated. Constraints: Elements must be group IDs. */
+ child_groups?: object[];
+ /** @see GroupAutoUpdate */
+ auto_update?: GroupAutoUpdate;
+}
+
+
diff --git a/packages/sms/src/models/v1/create-group-response/index.ts b/packages/sms/src/models/v1/create-group-response/index.ts
new file mode 100644
index 00000000..6757713b
--- /dev/null
+++ b/packages/sms/src/models/v1/create-group-response/index.ts
@@ -0,0 +1,4 @@
+export type { CreateGroupResponse } from './create-group-response';
+export type { CreateGroupResponse as GroupResponse } from './create-group-response';
+export type { CreateGroupResponse as ReplaceGroupResponse } from './create-group-response';
+export type { CreateGroupResponse as UpdateGroupResponse } from './create-group-response';
diff --git a/packages/sms/src/models/v1/delivery-feedback-request/delivery-feedback-request.ts b/packages/sms/src/models/v1/delivery-feedback-request/delivery-feedback-request.ts
new file mode 100644
index 00000000..5afd8601
--- /dev/null
+++ b/packages/sms/src/models/v1/delivery-feedback-request/delivery-feedback-request.ts
@@ -0,0 +1,15 @@
+/**
+ * Model: DeliveryFeedbackRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+export interface DeliveryFeedbackRequest {
+
+ /** A list of phone numbers (MSISDNs) that have successfully received the message. The key is required, however, the value can be an empty array (`[]`) for *a batch*. If the feedback was enabled for *a group*, at least one phone number is required. */
+ recipients: string[];
+}
+
+
diff --git a/packages/sms/src/models/v1/delivery-feedback-request/index.ts b/packages/sms/src/models/v1/delivery-feedback-request/index.ts
new file mode 100644
index 00000000..f7c28e96
--- /dev/null
+++ b/packages/sms/src/models/v1/delivery-feedback-request/index.ts
@@ -0,0 +1 @@
+export type { DeliveryFeedbackRequest } from './delivery-feedback-request';
diff --git a/packages/sms/src/models/v1/delivery-report-list/delivery-report-list.ts b/packages/sms/src/models/v1/delivery-report-list/delivery-report-list.ts
new file mode 100644
index 00000000..08fc052c
--- /dev/null
+++ b/packages/sms/src/models/v1/delivery-report-list/delivery-report-list.ts
@@ -0,0 +1,22 @@
+/**
+ * Model: DeliveryReportList
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { RecipientDeliveryReport } from '../recipient-delivery-report';
+
+export interface DeliveryReportList {
+
+ /** The total number of entries matching the given filters. */
+ count?: number;
+ /** The requested page. */
+ page?: number;
+ /** The number of entries returned in this request. */
+ page_size?: number;
+ /** The page of delivery reports matching the given filters. */
+ delivery_reports?: RecipientDeliveryReport[];
+}
+
+
diff --git a/packages/sms/src/models/v1/delivery-report-list/index.ts b/packages/sms/src/models/v1/delivery-report-list/index.ts
new file mode 100644
index 00000000..6d0712f6
--- /dev/null
+++ b/packages/sms/src/models/v1/delivery-report-list/index.ts
@@ -0,0 +1 @@
+export type { DeliveryReportList } from './delivery-report-list';
diff --git a/packages/sms/src/models/v1/delivery-report/delivery-report.ts b/packages/sms/src/models/v1/delivery-report/delivery-report.ts
new file mode 100644
index 00000000..b4296611
--- /dev/null
+++ b/packages/sms/src/models/v1/delivery-report/delivery-report.ts
@@ -0,0 +1,25 @@
+/**
+ * Model: DeliveryReport
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { MessageDeliveryStatus } from '../message-delivery-status';
+
+export interface DeliveryReport {
+
+ /** The ID of the batch this delivery report belongs to. */
+ batch_id: string;
+ /** The client identifier of the batch this delivery report belongs to, if set when submitting batch. */
+ client_reference?: string;
+ /** Array with status objects. Only status codes with at least one recipient will be listed. */
+ statuses: MessageDeliveryStatus[];
+ /** The total number of messages in the batch. */
+ total_message_count: number;
+ /** The delivery report type. */
+ type: TypeEnum;
+}
+
+export type TypeEnum = 'delivery_report_sms' | 'delivery_report_mms';
+
diff --git a/packages/sms/src/models/v1/delivery-report/index.ts b/packages/sms/src/models/v1/delivery-report/index.ts
new file mode 100644
index 00000000..ddfae27b
--- /dev/null
+++ b/packages/sms/src/models/v1/delivery-report/index.ts
@@ -0,0 +1 @@
+export type { DeliveryReport } from './delivery-report';
diff --git a/packages/sms/src/models/v1/dry-run-request/dry-run-request.ts b/packages/sms/src/models/v1/dry-run-request/dry-run-request.ts
new file mode 100644
index 00000000..82ece021
--- /dev/null
+++ b/packages/sms/src/models/v1/dry-run-request/dry-run-request.ts
@@ -0,0 +1,14 @@
+/**
+ * Model: DryRunRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { BinaryRequest } from '../binary-request';
+import { MediaRequest } from '../media-request';
+import { TextRequest } from '../text-request';
+
+export type DryRunRequest = TextRequest | BinaryRequest | MediaRequest;
+
+export type ReplaceBatchMessageRequest = DryRunRequest;
diff --git a/packages/sms/src/models/v1/dry-run-request/index.ts b/packages/sms/src/models/v1/dry-run-request/index.ts
new file mode 100644
index 00000000..90527b0d
--- /dev/null
+++ b/packages/sms/src/models/v1/dry-run-request/index.ts
@@ -0,0 +1 @@
+export type { DryRunRequest, ReplaceBatchMessageRequest } from './dry-run-request';
diff --git a/packages/sms/src/models/v1/dry-run-response-per-recipient-inner/dry-run-response-per-recipient-inner.ts b/packages/sms/src/models/v1/dry-run-response-per-recipient-inner/dry-run-response-per-recipient-inner.ts
new file mode 100644
index 00000000..70e96cbb
--- /dev/null
+++ b/packages/sms/src/models/v1/dry-run-response-per-recipient-inner/dry-run-response-per-recipient-inner.ts
@@ -0,0 +1,17 @@
+/**
+ * Model: DryRunResponsePerRecipientInner
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+export interface DryRunResponsePerRecipientInner {
+
+ recipient?: string;
+ message_part?: string;
+ body?: string;
+ encoding?: string;
+}
+
+
diff --git a/packages/sms/src/models/v1/dry-run-response-per-recipient-inner/index.ts b/packages/sms/src/models/v1/dry-run-response-per-recipient-inner/index.ts
new file mode 100644
index 00000000..5565940f
--- /dev/null
+++ b/packages/sms/src/models/v1/dry-run-response-per-recipient-inner/index.ts
@@ -0,0 +1 @@
+export type { DryRunResponsePerRecipientInner } from './dry-run-response-per-recipient-inner';
diff --git a/packages/sms/src/models/v1/dry-run-response/dry-run-response.ts b/packages/sms/src/models/v1/dry-run-response/dry-run-response.ts
new file mode 100644
index 00000000..e0a7a8ca
--- /dev/null
+++ b/packages/sms/src/models/v1/dry-run-response/dry-run-response.ts
@@ -0,0 +1,20 @@
+/**
+ * Model: DryRunResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { DryRunResponsePerRecipientInner } from '../dry-run-response-per-recipient-inner';
+
+export interface DryRunResponse {
+
+ /** The number of recipients in the batch */
+ number_of_recipients?: number;
+ /** The total number of SMS message parts to be sent in the batch */
+ number_of_messages?: number;
+ /** The recipient, the number of message parts to this recipient, the body of the message, and the encoding type of each message */
+ per_recipient?: DryRunResponsePerRecipientInner[];
+}
+
+
diff --git a/packages/sms/src/models/v1/dry-run-response/index.ts b/packages/sms/src/models/v1/dry-run-response/index.ts
new file mode 100644
index 00000000..2ba6e1be
--- /dev/null
+++ b/packages/sms/src/models/v1/dry-run-response/index.ts
@@ -0,0 +1 @@
+export type { DryRunResponse } from './dry-run-response';
diff --git a/packages/sms/src/models/v1/enums.ts b/packages/sms/src/models/v1/enums.ts
new file mode 100644
index 00000000..378a0a9f
--- /dev/null
+++ b/packages/sms/src/models/v1/enums.ts
@@ -0,0 +1,41 @@
+export type {
+ TypeEnum as ApiUpdateBinaryMtMessageTypeEnum,
+} from './api-update-binary-mt-message/api-update-binary-mt-message';
+export type {
+ TypeEnum as ApiUpdateMmsMtMessageTypeEnum,
+} from './api-update-mms-mt-message/api-update-mms-mt-message';
+export type {
+ TypeEnum as ApiUpdateTextMtMessageTypeEnum,
+} from './api-update-text-mt-message/api-update-text-mt-message';
+export type { TypeEnum as BinaryRequestTypeEnum } from './binary-request/binary-request';
+export type { TypeEnum as BinaryResponseTypeEnum } from './binary-response/binary-response';
+export type { TypeEnum as DeliveryReportTypeEnum } from './delivery-report/delivery-report';
+export type { TypeEnum as MOBinaryTypeEnum } from './mo-binary/mo-binary';
+export type { TypeEnum as MOTextTypeEnum } from './mo-text/mo-text';
+export type { TypeEnum as MediaRequestTypeEnum } from './media-request/media-request';
+export type { TypeEnum as MediaResponseTypeEnum } from './media-response/media-response';
+export type {
+ EncodingEnum as RecipientDeliveryReportEncodingEnum,
+ TypeEnum as RecipientDeliveryReportTypeEnum,
+} from './recipient-delivery-report/recipient-delivery-report';
+export type { TypeEnum as TextRequestTypeEnum } from './text-request/text-request';
+export type { TypeEnum as TextResponseTypeEnum } from './text-response/text-response';
+
+export type DeliveryReportEnum =
+ 'none'
+ | 'summary'
+ | 'full'
+ | 'per_recipient'
+ | 'per_recipient_final';
+
+export type DeliveryReportStatusEnum =
+ 'Queued'
+ | 'Dispatched'
+ | 'Aborted'
+ | 'Cancelled'
+ | 'Rejected'
+ | 'Deleted'
+ | 'Delivered'
+ | 'Failed'
+ | 'Expired'
+ | 'Unknown';
diff --git a/packages/sms/src/models/v1/error-response-obj/error-response-obj.ts b/packages/sms/src/models/v1/error-response-obj/error-response-obj.ts
new file mode 100644
index 00000000..acbf474b
--- /dev/null
+++ b/packages/sms/src/models/v1/error-response-obj/error-response-obj.ts
@@ -0,0 +1,17 @@
+/**
+ * Model: ErrorResponseObj
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+export interface ErrorResponseObj {
+
+ /** The error code. See [error codes](/docs/sms/api-reference/#error-codes). */
+ code?: string;
+ /** The human readable description of the error. */
+ text?: string;
+}
+
+
diff --git a/packages/sms/src/models/v1/error-response-obj/index.ts b/packages/sms/src/models/v1/error-response-obj/index.ts
new file mode 100644
index 00000000..2b109ab6
--- /dev/null
+++ b/packages/sms/src/models/v1/error-response-obj/index.ts
@@ -0,0 +1 @@
+export type { ErrorResponseObj } from './error-response-obj';
diff --git a/packages/sms/src/models/v1/group-auto-update/group-auto-update.ts b/packages/sms/src/models/v1/group-auto-update/group-auto-update.ts
new file mode 100644
index 00000000..20f78809
--- /dev/null
+++ b/packages/sms/src/models/v1/group-auto-update/group-auto-update.ts
@@ -0,0 +1,17 @@
+/**
+ * Model: GroupAutoUpdate
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+export interface GroupAutoUpdate {
+
+ /** Short code or long number addressed in MO. Constraints: Must be valid MSISDN or short code. */
+ to: string;
+ add?: string;
+ remove?: string;
+}
+
+
diff --git a/packages/sms/src/models/v1/group-auto-update/index.ts b/packages/sms/src/models/v1/group-auto-update/index.ts
new file mode 100644
index 00000000..802ba005
--- /dev/null
+++ b/packages/sms/src/models/v1/group-auto-update/index.ts
@@ -0,0 +1 @@
+export type { GroupAutoUpdate } from './group-auto-update';
diff --git a/packages/sms/src/models/v1/group-object-auto-update-remove/group-object-auto-update-remove.ts b/packages/sms/src/models/v1/group-object-auto-update-remove/group-object-auto-update-remove.ts
new file mode 100644
index 00000000..0e4ff224
--- /dev/null
+++ b/packages/sms/src/models/v1/group-object-auto-update-remove/group-object-auto-update-remove.ts
@@ -0,0 +1,24 @@
+/**
+ * Model: GroupObjectAutoUpdateRemove
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+/**
+ * Keyword to be sent in MO to remove from a group.
+ */
+export interface GroupObjectAutoUpdateRemove {
+
+ /** Opt-out keyword like \"LEAVE\" If auto_update.to is dedicated long/short number or unique brand keyword like \"Sinch\" if it is a shared short code. Constraints: Must be one word. */
+ first_word?: string;
+ /** Opt-out keyword like \"LEAVE\" if auto_update.to is shared short code. Constraints: Must be one word. */
+ second_word?: string;
+}
+
+
+/** Validation regex for first_word */
+export const firstWordPattern = /^\w+$/;
+/** Validation regex for second_word */
+export const secondWordPattern = /^\w+$/;
diff --git a/packages/sms/src/models/v1/group-object-auto-update-remove/index.ts b/packages/sms/src/models/v1/group-object-auto-update-remove/index.ts
new file mode 100644
index 00000000..c58c310f
--- /dev/null
+++ b/packages/sms/src/models/v1/group-object-auto-update-remove/index.ts
@@ -0,0 +1 @@
+export type { GroupObjectAutoUpdateRemove } from './group-object-auto-update-remove';
diff --git a/packages/sms/src/models/v1/group-object-auto-update/group-object-auto-update.ts b/packages/sms/src/models/v1/group-object-auto-update/group-object-auto-update.ts
new file mode 100644
index 00000000..ae3babff
--- /dev/null
+++ b/packages/sms/src/models/v1/group-object-auto-update/group-object-auto-update.ts
@@ -0,0 +1,21 @@
+/**
+ * Model: GroupObjectAutoUpdate
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { GroupObjectAutoUpdateRemove } from '../group-object-auto-update-remove';
+import { UpdateGroupRequestAutoUpdateAdd } from '../update-group-request-auto-update-add';
+
+export interface GroupObjectAutoUpdate {
+
+ /** Short code or long number addressed in MO. Constraints: Must be valid phone number or short code. */
+ to?: string;
+ /** @see UpdateGroupRequestAutoUpdateAdd */
+ add?: UpdateGroupRequestAutoUpdateAdd;
+ /** @see GroupObjectAutoUpdateRemove */
+ remove?: GroupObjectAutoUpdateRemove;
+}
+
+
diff --git a/packages/sms/src/models/v1/group-object-auto-update/index.ts b/packages/sms/src/models/v1/group-object-auto-update/index.ts
new file mode 100644
index 00000000..6ff5756d
--- /dev/null
+++ b/packages/sms/src/models/v1/group-object-auto-update/index.ts
@@ -0,0 +1 @@
+export type { GroupObjectAutoUpdate } from './group-object-auto-update';
diff --git a/packages/sms/src/models/v1/inbound-message-response/inbound-message-response.ts b/packages/sms/src/models/v1/inbound-message-response/inbound-message-response.ts
new file mode 100644
index 00000000..aa580c0c
--- /dev/null
+++ b/packages/sms/src/models/v1/inbound-message-response/inbound-message-response.ts
@@ -0,0 +1,11 @@
+/**
+ * Model: InboundMessageResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { MOBinary } from '../mo-binary';
+import { MOText } from '../mo-text';
+
+export type InboundMessageResponse = MOText | MOBinary;
diff --git a/packages/sms/src/models/v1/inbound-message-response/index.ts b/packages/sms/src/models/v1/inbound-message-response/index.ts
new file mode 100644
index 00000000..38b44f30
--- /dev/null
+++ b/packages/sms/src/models/v1/inbound-message-response/index.ts
@@ -0,0 +1 @@
+export type { InboundMessageResponse } from './inbound-message-response';
diff --git a/packages/sms/src/models/v1/index.ts b/packages/sms/src/models/v1/index.ts
new file mode 100644
index 00000000..d22bc1c0
--- /dev/null
+++ b/packages/sms/src/models/v1/index.ts
@@ -0,0 +1,45 @@
+export * from './api-batch-list';
+export * from './api-batch-list-batches-inner';
+export * from './delivery-feedback-request';
+export * from './api-inbound-list';
+export * from './inbound-message-response';
+export * from './api-mo-message';
+export * from './api-update-binary-mt-message';
+export * from './api-update-mms-mt-message';
+export * from './api-update-mt-message';
+export * from './api-update-text-mt-message';
+export * from './binary-request';
+export * from './binary-response';
+export * from './create-group-response';
+export * from './delivery-report';
+export * from './delivery-report-list';
+export * from './dry-run-request';
+export * from './dry-run-response';
+export * from './dry-run-response-per-recipient-inner';
+export * from './error-response-obj';
+export * from './group-auto-update';
+export * from './create-group-request';
+export * from './group-object-auto-update';
+export * from './group-object-auto-update-remove';
+export * from './inbound-message-response';
+export * from './list-groups-response';
+export * from './mo-binary';
+export * from './mo-text';
+export * from './media-body';
+export * from './media-request';
+export * from './media-response';
+export * from './message-delivery-status';
+export * from './parameter-obj';
+export * from './parameter-obj-parameter-key';
+export * from './recipient-delivery-report';
+export * from './replace-group-request';
+export * from './send-sms-response';
+export * from './send-sms-request';
+export * from './text-request';
+export * from './text-response';
+export * from './update-batch-message-request';
+export * from './update-group-request';
+export * from './update-group-request-auto-update';
+export * from './update-group-request-auto-update-add';
+export * from './update-group-request-auto-update-remove';
+export * from './enums';
diff --git a/packages/sms/src/models/v1/list-groups-response/index.ts b/packages/sms/src/models/v1/list-groups-response/index.ts
new file mode 100644
index 00000000..5cc48f60
--- /dev/null
+++ b/packages/sms/src/models/v1/list-groups-response/index.ts
@@ -0,0 +1 @@
+export type { ListGroupsResponse } from './list-groups-response';
diff --git a/packages/sms/src/models/v1/list-groups-response/list-groups-response.ts b/packages/sms/src/models/v1/list-groups-response/list-groups-response.ts
new file mode 100644
index 00000000..811ffa91
--- /dev/null
+++ b/packages/sms/src/models/v1/list-groups-response/list-groups-response.ts
@@ -0,0 +1,22 @@
+/**
+ * Model: ListGroupsResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { CreateGroupResponse } from '../create-group-response';
+
+export interface ListGroupsResponse {
+
+ /** The requested page. */
+ page?: number;
+ /** The number of groups returned in this request */
+ page_size?: number;
+ /** The total number of groups. */
+ count?: number;
+ /** List of GroupObjects */
+ groups?: CreateGroupResponse[];
+}
+
+
diff --git a/packages/sms/src/models/v1/media-body/index.ts b/packages/sms/src/models/v1/media-body/index.ts
new file mode 100644
index 00000000..e3c9f7a7
--- /dev/null
+++ b/packages/sms/src/models/v1/media-body/index.ts
@@ -0,0 +1 @@
+export type { MediaBody } from './media-body';
diff --git a/packages/sms/src/models/v1/media-body/media-body.ts b/packages/sms/src/models/v1/media-body/media-body.ts
new file mode 100644
index 00000000..2bd16764
--- /dev/null
+++ b/packages/sms/src/models/v1/media-body/media-body.ts
@@ -0,0 +1,20 @@
+/**
+ * Model: MediaBody
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+/**
+ * The message content, including a URL to the media file
+ */
+export interface MediaBody {
+
+ /** The message text. Text only media messages will be rejected, please use SMS instead. */
+ message?: string;
+ /** URL to the media file */
+ url: string;
+}
+
+
diff --git a/packages/sms/src/models/v1/media-request/index.ts b/packages/sms/src/models/v1/media-request/index.ts
new file mode 100644
index 00000000..202e035d
--- /dev/null
+++ b/packages/sms/src/models/v1/media-request/index.ts
@@ -0,0 +1 @@
+export type { MediaRequest } from './media-request';
diff --git a/packages/sms/src/models/v1/media-request/media-request.ts b/packages/sms/src/models/v1/media-request/media-request.ts
new file mode 100644
index 00000000..667f4aec
--- /dev/null
+++ b/packages/sms/src/models/v1/media-request/media-request.ts
@@ -0,0 +1,44 @@
+/**
+ * Model: MediaRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { MediaBody } from '../media-body';
+import { ParameterObj } from '../parameter-obj';
+import { DeliveryReportEnum } from '../enums';
+
+/**
+ * Only available in the US. Contact support if you wish to send MMS.
+ */
+export interface MediaRequest {
+
+ /** List of Phone numbers and group IDs that will receive the batch. More info */
+ to: string[];
+ /** Sender number. Must be valid phone number, short code or alphanumeric. Required if Automatic Default Originator not configured. */
+ from?: string;
+ /** @see MediaBody */
+ body: MediaBody;
+ /** @see ParameterObj */
+ parameters?: ParameterObj;
+ /** MMS */
+ type?: TypeEnum;
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set in the future, the message will be delayed until `send_at` occurs. Must be before `expire_at`. If set in the past, messages will be sent immediately. Formatted as ISO-8601: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ send_at?: Date;
+ /** If set, the system will stop trying to deliver the message at this point. Must be after `send_at`. Default and max is 3 days after `send_at`. Formatted as ISO-8601: `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ expire_at?: Date;
+ /** Override the default callback URL for this batch. Must be valid URL. */
+ callback_url?: string;
+ /** The client identifier of a batch message. If set, the identifier will be added in the delivery report/callback of this batch */
+ client_reference?: string;
+ /** If set to `true`, then [feedback](/docs/sms/api-reference/sms/tag/Batches/#tag/Batches/operation/deliveryFeedback) is expected after successful delivery. */
+ feedback_enabled?: boolean;
+ /** Whether or not you want the media included in your message to be checked against [Sinch MMS channel best practices](/docs/mms/bestpractices/). If set to true, your message will be rejected if it doesn\'t conform to the listed recommendations, otherwise no validation will be performed. */
+ strict_validation?: boolean;
+}
+
+export type TypeEnum = 'mt_media';
+
diff --git a/packages/sms/src/models/v1/media-response/index.ts b/packages/sms/src/models/v1/media-response/index.ts
new file mode 100644
index 00000000..2212f9c8
--- /dev/null
+++ b/packages/sms/src/models/v1/media-response/index.ts
@@ -0,0 +1 @@
+export type { MediaResponse } from './media-response';
diff --git a/packages/sms/src/models/v1/media-response/media-response.ts b/packages/sms/src/models/v1/media-response/media-response.ts
new file mode 100644
index 00000000..eb4356a0
--- /dev/null
+++ b/packages/sms/src/models/v1/media-response/media-response.ts
@@ -0,0 +1,49 @@
+/**
+ * Model: MediaResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { MediaBody } from '../media-body';
+import { ParameterObj } from '../parameter-obj';
+import { DeliveryReportEnum } from '../enums';
+
+export interface MediaResponse {
+
+ /** Unique identifier for batch */
+ id?: string;
+ /** List of Phone numbers and group IDs that will receive the batch. [More info](https://community.sinch.com/t5/Glossary/MSISDN/ta-p/7628) */
+ to?: string[];
+ /** Sender number. Required if Automatic Default Originator not configured. */
+ from?: string;
+ /** Indicates if the batch has been canceled or not. */
+ canceled?: boolean;
+ /** @see MediaBody */
+ body?: MediaBody;
+ /** @see ParameterObj */
+ parameters?: ParameterObj;
+ /** Media message */
+ type?: TypeEnum;
+ /** Timestamp for when batch was created. YYYY-MM-DDThh:mm:ss.SSSZ format */
+ created_at?: Date;
+ /** Timestamp for when batch was last updated. YYYY-MM-DDThh:mm:ss.SSSZ format */
+ modified_at?: Date;
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set in the future the message will be delayed until send_at occurs. Must be before `expire_at`. If set in the past messages will be sent immediately. YYYY-MM-DDThh:mm:ss.SSSZ format */
+ send_at?: Date;
+ /** If set the system will stop trying to deliver the message at this point. Must be after `send_at`. Default and max is 3 days after send_at. YYYY-MM-DDThh:mm:ss.SSSZ format */
+ expire_at?: Date;
+ /** Override the default callback URL for this batch. Must be valid URL. */
+ callback_url?: string;
+ /** The client identifier of a batch message. If set, the identifier will be added in the delivery report/callback of this batch */
+ client_reference?: string;
+ /** If set to true then [feedback](/docs/sms/api-reference/sms/tag/Batches/#tag/Batches/operation/deliveryFeedback) is expected after successful delivery. */
+ feedback_enabled?: boolean;
+ /** Whether or not you want the media included in your message to be checked against [Sinch MMS channel best practices](/docs/mms/bestpractices/). If set to true, your message will be rejected if it doesn\'t conform to the listed recommendations, otherwise no validation will be performed. */
+ strict_validation?: boolean;
+}
+
+export type TypeEnum = 'mt_media';
+
diff --git a/packages/sms/src/models/v1/message-delivery-status/index.ts b/packages/sms/src/models/v1/message-delivery-status/index.ts
new file mode 100644
index 00000000..b23ba4e5
--- /dev/null
+++ b/packages/sms/src/models/v1/message-delivery-status/index.ts
@@ -0,0 +1 @@
+export type { MessageDeliveryStatus } from './message-delivery-status';
diff --git a/packages/sms/src/models/v1/message-delivery-status/message-delivery-status.ts b/packages/sms/src/models/v1/message-delivery-status/message-delivery-status.ts
new file mode 100644
index 00000000..7f89999c
--- /dev/null
+++ b/packages/sms/src/models/v1/message-delivery-status/message-delivery-status.ts
@@ -0,0 +1,26 @@
+/**
+ * Model: MessageDeliveryStatus
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+import { DeliveryReportStatusEnum } from '../enums';
+
+/**
+ * Array with status objects. Only status codes with at least one recipient will be listed.
+ */
+export interface MessageDeliveryStatus {
+
+ /** The detailed status code. */
+ code: number;
+ /** The number of messages that currently has this code. */
+ count: number;
+ /** Only for `full` report. A list of the phone number recipients which messages has this status code. */
+ recipients: string[];
+ /** The simplified status as described in _Delivery Report Statuses_. */
+ status: DeliveryReportStatusEnum;
+}
+
+
diff --git a/packages/sms/src/models/v1/mo-binary/index.ts b/packages/sms/src/models/v1/mo-binary/index.ts
new file mode 100644
index 00000000..5bbba3b1
--- /dev/null
+++ b/packages/sms/src/models/v1/mo-binary/index.ts
@@ -0,0 +1 @@
+export type { MOBinary } from './mo-binary';
diff --git a/packages/sms/src/models/v1/mo-binary/mo-binary.ts b/packages/sms/src/models/v1/mo-binary/mo-binary.ts
new file mode 100644
index 00000000..72f68f77
--- /dev/null
+++ b/packages/sms/src/models/v1/mo-binary/mo-binary.ts
@@ -0,0 +1,21 @@
+/**
+ * Model: MOBinary
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ApiMoMessage } from '../api-mo-message';
+
+export interface MOBinary extends ApiMoMessage {
+
+ /** The message content Base64 encoded. Max 140 bytes together with udh. */
+ body: string;
+ /** SMS in binary format */
+ type: TypeEnum;
+ /** The UDH header of a binary message HEX encoded. Max 140 bytes together with body. */
+ udh: string;
+}
+
+export type TypeEnum = 'mo_binary';
+
diff --git a/packages/sms/src/models/v1/mo-text/index.ts b/packages/sms/src/models/v1/mo-text/index.ts
new file mode 100644
index 00000000..99547e64
--- /dev/null
+++ b/packages/sms/src/models/v1/mo-text/index.ts
@@ -0,0 +1 @@
+export type { MOText } from './mo-text';
diff --git a/packages/sms/src/models/v1/mo-text/mo-text.ts b/packages/sms/src/models/v1/mo-text/mo-text.ts
new file mode 100644
index 00000000..15b24899
--- /dev/null
+++ b/packages/sms/src/models/v1/mo-text/mo-text.ts
@@ -0,0 +1,18 @@
+/**
+ * Model: MOText
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ApiMoMessage } from '../api-mo-message';
+
+export interface MOText extends ApiMoMessage {
+
+ body: string;
+ /** Regular SMS */
+ type: TypeEnum;
+}
+
+export type TypeEnum = 'mo_text';
+
diff --git a/packages/sms/src/models/v1/parameter-obj-parameter-key/index.ts b/packages/sms/src/models/v1/parameter-obj-parameter-key/index.ts
new file mode 100644
index 00000000..2b230f38
--- /dev/null
+++ b/packages/sms/src/models/v1/parameter-obj-parameter-key/index.ts
@@ -0,0 +1 @@
+export type { ParameterObjParameterKey } from './parameter-obj-parameter-key';
diff --git a/packages/sms/src/models/v1/parameter-obj-parameter-key/parameter-obj-parameter-key.ts b/packages/sms/src/models/v1/parameter-obj-parameter-key/parameter-obj-parameter-key.ts
new file mode 100644
index 00000000..33c3de38
--- /dev/null
+++ b/packages/sms/src/models/v1/parameter-obj-parameter-key/parameter-obj-parameter-key.ts
@@ -0,0 +1,20 @@
+/**
+ * Model: ParameterObjParameterKey
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+/**
+ * The name of the parameter that will be replaced in the message body. Letters A-Z and a-z, digits 0-9 and .-_ allowed.
+ */
+export interface ParameterObjParameterKey {
+
+ /** The key is the recipient that should have the `parameter_key` replaced with the value */
+ '{msisdn}'?: string;
+ /** The fall-back value for omitted recipient phone numbers MSISDNs. */
+ default?: string;
+}
+
+
diff --git a/packages/sms/src/models/v1/parameter-obj/index.ts b/packages/sms/src/models/v1/parameter-obj/index.ts
new file mode 100644
index 00000000..39022580
--- /dev/null
+++ b/packages/sms/src/models/v1/parameter-obj/index.ts
@@ -0,0 +1 @@
+export type { ParameterObj } from './parameter-obj';
diff --git a/packages/sms/src/models/v1/parameter-obj/parameter-obj.ts b/packages/sms/src/models/v1/parameter-obj/parameter-obj.ts
new file mode 100644
index 00000000..89e6cb5d
--- /dev/null
+++ b/packages/sms/src/models/v1/parameter-obj/parameter-obj.ts
@@ -0,0 +1,19 @@
+/**
+ * Model: ParameterObj
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ParameterObjParameterKey } from '../parameter-obj-parameter-key';
+
+/**
+ * Contains the parameters that will be used for customizing the message for each recipient. [Click here to learn more about parameterization](/docs/sms/resources/message-info/message-parameterization).
+ */
+export interface ParameterObj extends Record {
+
+ /** @see ParameterObjParameterKey */
+ '{parameter_key}'?: ParameterObjParameterKey;
+}
+
+
diff --git a/packages/sms/src/models/v1/recipient-delivery-report/index.ts b/packages/sms/src/models/v1/recipient-delivery-report/index.ts
new file mode 100644
index 00000000..175dd47d
--- /dev/null
+++ b/packages/sms/src/models/v1/recipient-delivery-report/index.ts
@@ -0,0 +1 @@
+export type { RecipientDeliveryReport } from './recipient-delivery-report';
diff --git a/packages/sms/src/models/v1/recipient-delivery-report/recipient-delivery-report.ts b/packages/sms/src/models/v1/recipient-delivery-report/recipient-delivery-report.ts
new file mode 100644
index 00000000..961522d6
--- /dev/null
+++ b/packages/sms/src/models/v1/recipient-delivery-report/recipient-delivery-report.ts
@@ -0,0 +1,40 @@
+/**
+ * Model: RecipientDeliveryReport
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+import { DeliveryReportStatusEnum } from '../enums';
+
+
+export interface RecipientDeliveryReport {
+
+ /** The default originator used for the recipient this delivery report belongs to, if default originator pool configured and no originator set when submitting batch. */
+ applied_originator?: string;
+ /** A timestamp of when the Delivery Report was created in the Sinch service. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ at: Date;
+ /** The ID of the batch this delivery report belongs to */
+ batch_id: string;
+ /** The client identifier of the batch this delivery report belongs to, if set when submitting batch. */
+ client_reference?: string;
+ /** The detailed status code. */
+ code: number;
+ /** Applied encoding for message. Present only if smart encoding is enabled. */
+ encoding?: EncodingEnum;
+ /** The number of parts the message was split into. Present only if `max_number_of_message_parts` parameter was set. */
+ number_of_message_parts?: number;
+ /** The operator that was used for delivering the message to this recipient, if enabled on the account by Sinch. */
+ operator?: string;
+ /** A timestamp extracted from the Delivery Receipt from the originating SMSC. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ operator_status_at?: Date;
+ /** Phone number that was queried. */
+ recipient: string;
+ /** The simplified status as described in _Delivery Report Statuses_. */
+ status: DeliveryReportStatusEnum;
+ /** The recipient delivery report type. */
+ type: TypeEnum;
+}
+
+export type EncodingEnum = 'GSM' | 'UNICODE';
+export type TypeEnum = 'recipient_delivery_report_sms' | 'recipient_delivery_report_mms';
+
diff --git a/packages/sms/src/models/v1/replace-group-request/index.ts b/packages/sms/src/models/v1/replace-group-request/index.ts
new file mode 100644
index 00000000..b08964a5
--- /dev/null
+++ b/packages/sms/src/models/v1/replace-group-request/index.ts
@@ -0,0 +1 @@
+export type { ReplaceGroupRequest } from './replace-group-request';
diff --git a/packages/sms/src/models/v1/replace-group-request/replace-group-request.ts b/packages/sms/src/models/v1/replace-group-request/replace-group-request.ts
new file mode 100644
index 00000000..63b644bc
--- /dev/null
+++ b/packages/sms/src/models/v1/replace-group-request/replace-group-request.ts
@@ -0,0 +1,17 @@
+/**
+ * Model: ReplaceGroupRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+export interface ReplaceGroupRequest {
+
+ /** Name of group. */
+ name?: string;
+ /** The initial members of the group. Constraints: Elements must be phone numbers in E.164 format MSISDNs. */
+ members: string[];
+}
+
+
diff --git a/packages/sms/src/models/v1/send-sms-request/index.ts b/packages/sms/src/models/v1/send-sms-request/index.ts
new file mode 100644
index 00000000..9171c3fd
--- /dev/null
+++ b/packages/sms/src/models/v1/send-sms-request/index.ts
@@ -0,0 +1 @@
+export type { SendSMSRequest } from './send-sms-request';
diff --git a/packages/sms/src/models/v1/send-sms-request/send-sms-request.ts b/packages/sms/src/models/v1/send-sms-request/send-sms-request.ts
new file mode 100644
index 00000000..d514441b
--- /dev/null
+++ b/packages/sms/src/models/v1/send-sms-request/send-sms-request.ts
@@ -0,0 +1,12 @@
+/**
+ * Model: SendSMSRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { BinaryRequest } from '../binary-request';
+import { MediaRequest } from '../media-request';
+import { TextRequest } from '../text-request';
+
+export type SendSMSRequest = TextRequest | BinaryRequest | MediaRequest;
diff --git a/packages/sms/src/models/v1/send-sms-response/index.ts b/packages/sms/src/models/v1/send-sms-response/index.ts
new file mode 100644
index 00000000..02dd78fa
--- /dev/null
+++ b/packages/sms/src/models/v1/send-sms-response/index.ts
@@ -0,0 +1 @@
+export type { SendSMSResponse, CancelBatchMessageResponse, ReplaceBatchMessageResponse } from './send-sms-response';
diff --git a/packages/sms/src/models/v1/send-sms-response/send-sms-response.ts b/packages/sms/src/models/v1/send-sms-response/send-sms-response.ts
new file mode 100644
index 00000000..5adc0a98
--- /dev/null
+++ b/packages/sms/src/models/v1/send-sms-response/send-sms-response.ts
@@ -0,0 +1,16 @@
+/**
+ * Model: SendSMSResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { BinaryResponse } from '../binary-response';
+import { MediaResponse } from '../media-response';
+import { TextResponse } from '../text-response';
+
+export type SendSMSResponse = TextResponse | BinaryResponse | MediaResponse;
+
+export type CancelBatchMessageResponse = SendSMSResponse;
+
+export type ReplaceBatchMessageResponse = SendSMSResponse;
diff --git a/packages/sms/src/models/v1/text-request/index.ts b/packages/sms/src/models/v1/text-request/index.ts
new file mode 100644
index 00000000..cfcb33dc
--- /dev/null
+++ b/packages/sms/src/models/v1/text-request/index.ts
@@ -0,0 +1 @@
+export type { TextRequest } from './text-request';
diff --git a/packages/sms/src/models/v1/text-request/text-request.ts b/packages/sms/src/models/v1/text-request/text-request.ts
new file mode 100644
index 00000000..3fab8036
--- /dev/null
+++ b/packages/sms/src/models/v1/text-request/text-request.ts
@@ -0,0 +1,48 @@
+/**
+ * Model: TextRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ParameterObj } from '../parameter-obj';
+import { DeliveryReportEnum } from '../enums';
+
+export interface TextRequest {
+
+ /** List of Phone numbers and group IDs that will receive the batch. More info */
+ to: string[];
+ /** Sender number. Must be valid phone number, short code or alphanumeric. Required if Automatic Default Originator not configured. */
+ from?: string;
+ /** @see ParameterObj */
+ parameters?: ParameterObj;
+ /** The message content */
+ body: string;
+ /** Regular SMS */
+ type?: TypeEnum;
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set in the future, the message will be delayed until `send_at` occurs. Must be before `expire_at`. If set in the past, messages will be sent immediately. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ send_at?: Date;
+ /** If set, the system will stop trying to deliver the message at this point. Must be after `send_at`. Default and max is 3 days after `send_at`. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ expire_at?: Date;
+ /** Override the *default* callback URL for this batch. Must be a valid URL. Learn how to set a default callback URL here. */
+ callback_url?: string;
+ /** The client identifier of a batch message. If set, the identifier will be added in the delivery report/callback of this batch */
+ client_reference?: string;
+ /** If set to `true`, then [feedback](/docs/sms/api-reference/sms/tag/Batches/#tag/Batches/operation/deliveryFeedback) is expected after successful delivery. */
+ feedback_enabled?: boolean;
+ /** Shows message on screen without user interaction while not saving the message to the inbox. */
+ flash_message?: boolean;
+ /** If set to `true` the message will be shortened when exceeding one part. */
+ truncate_concat?: boolean;
+ /** Message will be dispatched only if it is not split to more parts than Max Number of Message Parts */
+ max_number_of_message_parts?: number;
+ /** The type of number for the sender number. Use to override the automatic detection. */
+ from_ton?: number;
+ /** Number Plan Indicator for the sender number. Use to override the automatic detection. */
+ from_npi?: number;
+}
+
+export type TypeEnum = 'mt_text' | 'mt_binary' | 'mt_media';
+
diff --git a/packages/sms/src/models/v1/text-response/index.ts b/packages/sms/src/models/v1/text-response/index.ts
new file mode 100644
index 00000000..e00bff39
--- /dev/null
+++ b/packages/sms/src/models/v1/text-response/index.ts
@@ -0,0 +1 @@
+export { TextResponse } from './text-response';
diff --git a/packages/sms/src/models/v1/text-response/text-response.ts b/packages/sms/src/models/v1/text-response/text-response.ts
new file mode 100644
index 00000000..498cd700
--- /dev/null
+++ b/packages/sms/src/models/v1/text-response/text-response.ts
@@ -0,0 +1,56 @@
+/**
+ * Model: TextResponse
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ParameterObj } from '../parameter-obj';
+import { DeliveryReportEnum } from '../enums';
+
+export interface TextResponse {
+
+ /** Unique identifier for batch */
+ id?: string;
+ /** List of Phone numbers and group IDs that will receive the batch. [More info](https://community.sinch.com/t5/Glossary/MSISDN/ta-p/7628) */
+ to?: string[];
+ /** Sender number. Must be valid phone number, short code or alphanumeric. Required if Automatic Default Originator not configured. */
+ from?: string;
+ /** Indicates if the batch has been canceled or not. */
+ canceled?: boolean;
+ /** @see ParameterObj */
+ parameters?: ParameterObj;
+ /** The message content */
+ body?: string;
+ /** Regular SMS */
+ type?: TypeEnum;
+ /** Timestamp for when batch was created. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601):`YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ created_at?: Date;
+ /** Timestamp for when batch was last updated. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601):`YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ modified_at?: Date;
+ /** Request delivery report callback. Note that delivery reports can be fetched from the API regardless of this setting. */
+ delivery_report?: DeliveryReportEnum;
+ /** If set in the future, the message will be delayed until `send_at` occurs. Must be before `expire_at`. If set in the past, messages will be sent immediately. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ send_at?: Date;
+ /** If set, the system will stop trying to deliver the message at this point. Must be after `send_at`. Default and max is 3 days after `send_at`. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ expire_at?: Date;
+ /** Override the default callback URL for this batch. Must be valid URL. */
+ callback_url?: string;
+ /** The client identifier of a batch message. If set, the identifier will be added in the delivery report/callback of this batch */
+ client_reference?: string;
+ /** If set to `true`, then [feedback](/docs/sms/api-reference/sms/tag/Batches/#tag/Batches/operation/deliveryFeedback) is expected after successful delivery. */
+ feedback_enabled?: boolean;
+ /** Shows message on screen without user interaction while not saving the message to the inbox. */
+ flash_message?: boolean;
+ /** If set to `true` the message will be shortened when exceeding one part. */
+ truncate_concat?: boolean;
+ /** Message will be dispatched only if it is not split to more parts than Max Number of Message Parts */
+ max_number_of_message_parts?: number;
+ /** The type of number for the sender number. Use to override the automatic detection. */
+ from_ton?: number;
+ /** Number Plan Indicator for the sender number. Use to override the automatic detection. */
+ from_npi?: number;
+}
+
+export type TypeEnum = 'mt_text' | 'mt_binary' | 'mt_media';
+
diff --git a/packages/sms/src/models/v1/update-batch-message-request/index.ts b/packages/sms/src/models/v1/update-batch-message-request/index.ts
new file mode 100644
index 00000000..cd52b9e2
--- /dev/null
+++ b/packages/sms/src/models/v1/update-batch-message-request/index.ts
@@ -0,0 +1 @@
+export type { UpdateBatchMessageRequest } from './update-batch-message-request';
diff --git a/packages/sms/src/models/v1/update-batch-message-request/update-batch-message-request.ts b/packages/sms/src/models/v1/update-batch-message-request/update-batch-message-request.ts
new file mode 100644
index 00000000..9247db5c
--- /dev/null
+++ b/packages/sms/src/models/v1/update-batch-message-request/update-batch-message-request.ts
@@ -0,0 +1,12 @@
+/**
+ * Model: UpdateBatchMessageRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { ApiUpdateBinaryMtMessage } from '../api-update-binary-mt-message';
+import { ApiUpdateMmsMtMessage } from '../api-update-mms-mt-message';
+import { ApiUpdateTextMtMessage } from '../api-update-text-mt-message';
+
+export type UpdateBatchMessageRequest = ApiUpdateTextMtMessage | ApiUpdateBinaryMtMessage | ApiUpdateMmsMtMessage;
diff --git a/packages/sms/src/models/v1/update-group-request-auto-update-add/index.ts b/packages/sms/src/models/v1/update-group-request-auto-update-add/index.ts
new file mode 100644
index 00000000..33980879
--- /dev/null
+++ b/packages/sms/src/models/v1/update-group-request-auto-update-add/index.ts
@@ -0,0 +1 @@
+export type { UpdateGroupRequestAutoUpdateAdd } from './update-group-request-auto-update-add';
diff --git a/packages/sms/src/models/v1/update-group-request-auto-update-add/update-group-request-auto-update-add.ts b/packages/sms/src/models/v1/update-group-request-auto-update-add/update-group-request-auto-update-add.ts
new file mode 100644
index 00000000..9ded96c3
--- /dev/null
+++ b/packages/sms/src/models/v1/update-group-request-auto-update-add/update-group-request-auto-update-add.ts
@@ -0,0 +1,21 @@
+/**
+ * Model: UpdateGroupRequestAutoUpdateAdd
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+export interface UpdateGroupRequestAutoUpdateAdd {
+
+ /** Keyword to be sent in MO to add phone number to a group opt-in keyword like \"JOIN\". If `auto_update.to` is dedicated long/short number or unique brand keyword like \"Sinch\" if it is a shared short code. Constraints: Must be one word. */
+ first_word?: string;
+ /** Opt-in keyword like \"JOIN\" if auto_update.to is shared short code. Constraints: Must be one word. */
+ second_word?: string;
+}
+
+
+/** Validation regex for first_word */
+export const firstWordPattern = /^\w+$/;
+/** Validation regex for second_word */
+export const secondWordPattern = /^\w+$/;
diff --git a/packages/sms/src/models/v1/update-group-request-auto-update-remove/index.ts b/packages/sms/src/models/v1/update-group-request-auto-update-remove/index.ts
new file mode 100644
index 00000000..be9fe994
--- /dev/null
+++ b/packages/sms/src/models/v1/update-group-request-auto-update-remove/index.ts
@@ -0,0 +1 @@
+export type { UpdateGroupRequestAutoUpdateRemove } from './update-group-request-auto-update-remove';
diff --git a/packages/sms/src/models/v1/update-group-request-auto-update-remove/update-group-request-auto-update-remove.ts b/packages/sms/src/models/v1/update-group-request-auto-update-remove/update-group-request-auto-update-remove.ts
new file mode 100644
index 00000000..f92a0446
--- /dev/null
+++ b/packages/sms/src/models/v1/update-group-request-auto-update-remove/update-group-request-auto-update-remove.ts
@@ -0,0 +1,24 @@
+/**
+ * Model: UpdateGroupRequestAutoUpdateRemove
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+
+/**
+ * Keyword to be sent in MO to remove from a group.
+ */
+export interface UpdateGroupRequestAutoUpdateRemove {
+
+ /** Opt-out keyword. For example, \"LEAVE\" if `auto_update.to` is a dedicated long/short number or a unique brand keyword like \"Sinch\" (if it is a shared short code). Constraints: Must be one word. */
+ first_word?: string;
+ /** Opt-out keyword. For example, \"LEAVE\" if `auto_update.to` is a shared short code. Constraints: Must be one word. */
+ second_word?: string;
+}
+
+
+/** Validation regex for first_word */
+export const firstWordPattern = /^\w+$/;
+/** Validation regex for second_word */
+export const secondWordPattern = /^\w+$/;
diff --git a/packages/sms/src/models/v1/update-group-request-auto-update/index.ts b/packages/sms/src/models/v1/update-group-request-auto-update/index.ts
new file mode 100644
index 00000000..b312ba1f
--- /dev/null
+++ b/packages/sms/src/models/v1/update-group-request-auto-update/index.ts
@@ -0,0 +1 @@
+export type { UpdateGroupRequestAutoUpdate } from './update-group-request-auto-update';
diff --git a/packages/sms/src/models/v1/update-group-request-auto-update/update-group-request-auto-update.ts b/packages/sms/src/models/v1/update-group-request-auto-update/update-group-request-auto-update.ts
new file mode 100644
index 00000000..9ab5dbac
--- /dev/null
+++ b/packages/sms/src/models/v1/update-group-request-auto-update/update-group-request-auto-update.ts
@@ -0,0 +1,21 @@
+/**
+ * Model: UpdateGroupRequestAutoUpdate
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { UpdateGroupRequestAutoUpdateAdd } from '../update-group-request-auto-update-add';
+import { UpdateGroupRequestAutoUpdateRemove } from '../update-group-request-auto-update-remove';
+
+export interface UpdateGroupRequestAutoUpdate {
+
+ /** Short code or long number addressed in MO. Constraints: Must be a valid phone number or short code. */
+ to?: string;
+ /** @see UpdateGroupRequestAutoUpdateAdd */
+ add?: UpdateGroupRequestAutoUpdateAdd;
+ /** @see UpdateGroupRequestAutoUpdateRemove */
+ remove?: UpdateGroupRequestAutoUpdateRemove;
+}
+
+
diff --git a/packages/sms/src/models/v1/update-group-request/index.ts b/packages/sms/src/models/v1/update-group-request/index.ts
new file mode 100644
index 00000000..7044786a
--- /dev/null
+++ b/packages/sms/src/models/v1/update-group-request/index.ts
@@ -0,0 +1 @@
+export type { UpdateGroupRequest } from './update-group-request';
diff --git a/packages/sms/src/models/v1/update-group-request/update-group-request.ts b/packages/sms/src/models/v1/update-group-request/update-group-request.ts
new file mode 100644
index 00000000..791512d2
--- /dev/null
+++ b/packages/sms/src/models/v1/update-group-request/update-group-request.ts
@@ -0,0 +1,26 @@
+/**
+ * Model: UpdateGroupRequest
+ *
+ * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT.
+ *
+ */
+
+import { UpdateGroupRequestAutoUpdate } from '../update-group-request-auto-update';
+
+export interface UpdateGroupRequest {
+
+ /** The name of the group. Omitting `name` from the JSON body will leave the name unchanged. To remove an existing name set, name explicitly to the JSON value `null`. */
+ name?: string;
+ /** Add a list of phone numbers (MSISDNs) to this group. The phone numbers are a strings within an array and must be in E.164 format. */
+ add?: string[];
+ /** Remove a list of phone numbers (MSISDNs) to this group.The phone numbers are a strings within an array and must be in E.164 format. */
+ remove?: string[];
+ /** Copy the members from the another group into this group. Constraints: Must be valid group ID */
+ add_from_group?: string;
+ /** Remove the members in a specified group from this group. Constraints: Must be valid group ID */
+ remove_from_group?: string;
+ /** @see UpdateGroupRequestAutoUpdate */
+ auto_update?: UpdateGroupRequestAutoUpdate;
+}
+
+
diff --git a/packages/sms/src/rest/index.ts b/packages/sms/src/rest/index.ts
new file mode 100644
index 00000000..5b98253d
--- /dev/null
+++ b/packages/sms/src/rest/index.ts
@@ -0,0 +1 @@
+export * from './v1';
diff --git a/packages/sms/src/rest/v1/batches/batches-api.jest.fixture.ts b/packages/sms/src/rest/v1/batches/batches-api.jest.fixture.ts
new file mode 100644
index 00000000..bca5d5ec
--- /dev/null
+++ b/packages/sms/src/rest/v1/batches/batches-api.jest.fixture.ts
@@ -0,0 +1,39 @@
+import { BatchesApi, CancelBatchMessageRequestData, DeliveryFeedbackRequestData, DryRunRequestData, GetBatchMessageRequestData, ListBatchesRequestData, ReplaceBatchMessageRequestData, SendSMSRequestData, UpdateBatchMessageRequestData } from './batches-api';
+import { ApiBatchListBatchesInner, DryRunResponse, SendSMSResponse } from '../../../models';
+import { ApiListPromise } from '@sinch/sdk-client';
+
+export class BatchesApiFixture implements Partial> {
+
+ /**
+ * Fixture associated to function cancel
+ */
+ public cancel: jest.Mock, [CancelBatchMessageRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function sendDeliveryFeedback
+ */
+ public sendDeliveryFeedback: jest.Mock, [DeliveryFeedbackRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function dryRun
+ */
+ public dryRun: jest.Mock, [DryRunRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function get
+ */
+ public get: jest.Mock, [GetBatchMessageRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function list
+ */
+ public list: jest.Mock, [ListBatchesRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function replace
+ */
+ public replace: jest.Mock, [ReplaceBatchMessageRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function send
+ */
+ public send: jest.Mock, [SendSMSRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function update
+ */
+ public update: jest.Mock, [UpdateBatchMessageRequestData]> = jest.fn();
+}
diff --git a/packages/sms/src/rest/v1/batches/batches-api.ts b/packages/sms/src/rest/v1/batches/batches-api.ts
new file mode 100644
index 00000000..eb62c0bc
--- /dev/null
+++ b/packages/sms/src/rest/v1/batches/batches-api.ts
@@ -0,0 +1,340 @@
+import {
+ ApiBatchListBatchesInner,
+ CancelBatchMessageResponse,
+ DeliveryFeedbackRequest,
+ DryRunResponse,
+ DryRunRequest,
+ ReplaceBatchMessageResponse,
+ ReplaceBatchMessageRequest,
+ SendSMSResponse,
+ SendSMSRequest,
+ UpdateBatchMessageRequest,
+} from '../../../models';
+import {
+ RequestBody,
+ ApiListPromise,
+ PaginatedApiProperties,
+ PaginationEnum,
+ SinchClientParameters,
+ buildPageResultPromise,
+ createIteratorMethodsForPagination,
+} from '@sinch/sdk-client';
+import { SmsApi } from '../sms-api';
+
+export interface CancelBatchMessageRequestData {
+ /** The batch ID you received from sending a message. */
+ 'batch_id': string;
+}
+export interface DeliveryFeedbackRequestData {
+ /** The batch ID you received from sending a message. */
+ 'batch_id': string;
+ /** A list of phone numbers (MSISDNs) that successfully received the message. */
+ 'deliveryFeedbackRequestBody': DeliveryFeedbackRequest;
+}
+export interface DryRunRequestData {
+ /** Whether to include per recipient details in the response */
+ 'per_recipient'?: boolean;
+ /** Max number of recipients to include per recipient details for in the response */
+ 'number_of_recipients'?: number;
+ /** */
+ 'dryRunRequestBody'?: DryRunRequest;
+}
+export interface GetBatchMessageRequestData {
+ /** The batch ID you received from sending a message. */
+ 'batch_id': string;
+}
+export interface ListBatchesRequestData {
+ /** The page number starting from 0. */
+ 'page'?: number;
+ /** Determines the size of a page. */
+ 'page_size'?: number;
+ /** Only list messages sent from this sender number. Multiple originating numbers can be comma separated. Must be phone numbers or short code. */
+ 'from'?: string;
+ /** Only list messages received at or after this date/time. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDThh:mm:ss.SSSZ`. Default: Now-24 */
+ 'start_date'?: Date;
+ /** Only list messages received before this date/time. Formatted as [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDThh:mm:ss.SSSZ`. */
+ 'end_date'?: Date;
+ /** Client reference to include */
+ 'client_reference'?: string;
+}
+export interface ReplaceBatchMessageRequestData {
+ /** The batch ID you received from sending a message. */
+ 'batch_id': string;
+ /** */
+ 'replaceBatchMessageRequestBody'?: ReplaceBatchMessageRequest;
+}
+export interface SendSMSRequestData {
+ /** Default schema is Text if type is not specified. */
+ 'sendSMSRequestBody'?: SendSMSRequest;
+}
+export interface UpdateBatchMessageRequestData {
+ /** The batch ID you received from sending a message. */
+ 'batch_id': string;
+ /** */
+ 'updateBatchMessageRequestBody'?: UpdateBatchMessageRequest;
+}
+
+export class BatchesApi extends SmsApi {
+
+ /**
+ * Initialize your interface
+ *
+ * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client.
+ */
+ constructor(sinchClientParameters: SinchClientParameters) {
+ super(sinchClientParameters, 'BatchesApi');
+ }
+
+ /**
+ * Cancel a batch message
+ * A batch can be canceled at any point. If a batch is canceled while it's currently being delivered some messages currently being processed might still be delivered. The delivery report will indicate which messages were canceled and which weren't. Canceling a batch scheduled in the future will result in an empty delivery report while canceling an already sent batch would result in no change to the completed delivery report.
+ * @param { CancelBatchMessageRequestData } data - The data to provide to the API call.
+ */
+ public async cancel(data: CancelBatchMessageRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl
+ = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'CancelBatchMessage',
+ });
+ }
+
+ /**
+ * Send delivery feedback for a message
+ * Send feedback if your system can confirm successful message delivery. Feedback can only be provided if 'feedback_enabled' was set when batch was submitted.
+ * **Batches**: It is possible to submit feedback multiple times for the same batch for different recipients. Feedback without specified recipients is treated as successful message delivery to all recipients referenced in the batch. Note that the 'recipients' key is still required even if the value is empty.
+ * **Groups**: If the batch message was creating using a group ID, at least one recipient is required. Excluding recipients (an empty recipient list) does not work and will result in a failed request.
+ * @param { DeliveryFeedbackRequestData } data - The data to provide to the API call.
+ */
+ public async sendDeliveryFeedback(data: DeliveryFeedbackRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': '',
+ };
+
+ const body: RequestBody
+ = data['deliveryFeedbackRequestBody'] ? JSON.stringify(data['deliveryFeedbackRequestBody']) : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}/delivery_feedback`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'DeliveryFeedback',
+ });
+ }
+
+ /**
+ * Dry run
+ * This operation will perform a dry run of a batch which calculates the bodies and number of parts for all messages in the batch without actually sending any messages.
+ * @param { DryRunRequestData } data - The data to provide to the API call.
+ */
+ public async dryRun(data: DryRunRequestData): Promise {
+ this.client = this.getSinchClient();
+ data['number_of_recipients'] = data['number_of_recipients'] !== undefined ? data['number_of_recipients'] : 100;
+ const getParams = this.client.extractQueryParams(data, [
+ 'per_recipient',
+ 'number_of_recipients']);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['dryRunRequestBody'] ? JSON.stringify(data['dryRunRequestBody']) : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches/dry_run`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'Run',
+ });
+ }
+
+ /**
+ * Get a batch message
+ * This operation returns a specific batch that matches the provided batch ID.
+ * @param { GetBatchMessageRequestData } data - The data to provide to the API call.
+ */
+ public async get(data: GetBatchMessageRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'GetBatchMessage',
+ });
+ }
+
+ /**
+ * List Batches
+ * With the list operation you can list batch messages created in the last 14 days that you have created. This operation supports pagination.
+ * @param { ListBatchesRequestData } data - The data to provide to the API call.
+ * @return {ApiListPromise}
+ */
+ public list(data: ListBatchesRequestData): ApiListPromise {
+ this.client = this.getSinchClient();
+ data['page_size'] = data['page_size'] !== undefined ? data['page_size'] : 30;
+ const getParams = this.client.extractQueryParams(
+ data,
+ ['page', 'page_size', 'from', 'start_date', 'end_date', 'client_reference'],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches`;
+
+ const requestOptionsPromise
+ = this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined);
+
+ const operationProperties: PaginatedApiProperties = {
+ pagination: PaginationEnum.PAGE,
+ apiName: this.apiName,
+ operationId: 'ListBatches',
+ dataKey: 'batches',
+ };
+
+ // Create the promise containing the response wrapped as a PageResult
+ const listPromise = buildPageResultPromise(
+ this.client,
+ requestOptionsPromise,
+ operationProperties);
+
+ // Add properties to the Promise to offer the possibility to use it as an iterator
+ Object.assign(
+ listPromise,
+ createIteratorMethodsForPagination(
+ this.client, requestOptionsPromise, listPromise, operationProperties),
+ );
+
+ return listPromise as ApiListPromise;
+ }
+
+ /**
+ * Replace a batch
+ * This operation will replace all the parameters of a batch with the provided values. It is the same as cancelling a batch and sending a new one instead.
+ * @param { ReplaceBatchMessageRequestData } data - The data to provide to the API call.
+ */
+ public async replace(data: ReplaceBatchMessageRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody
+ = data['replaceBatchMessageRequestBody'] ? JSON.stringify(data['replaceBatchMessageRequestBody']) : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'PUT', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'ReplaceBatch',
+ });
+ }
+
+ /**
+ * Send
+ * Send a message or a batch of messages. Depending on the length of the body, one message might be split into multiple parts and charged accordingly. Any groups targeted in a scheduled batch will be evaluated at the time of sending. If a group is deleted between batch creation and scheduled date, it will be considered empty. Be sure to use the correct <a href=\"/docs/sms/api-reference/#base-url\" target=\"_blank\">region</a> in the server URL.
+ * @param { SendSMSRequestData } data - The data to provide to the API call.
+ */
+ public async send(data: SendSMSRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['sendSMSRequestBody'] ? JSON.stringify(data['sendSMSRequestBody']) : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'SendSMS',
+ });
+ }
+
+ /**
+ * Update a Batch message
+ * This operation updates all specified parameters of a batch that matches the provided batch ID.
+ * @param { UpdateBatchMessageRequestData } data - The data to provide to the API call.
+ */
+ public async update(data: UpdateBatchMessageRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody
+ = data['updateBatchMessageRequestBody'] ? JSON.stringify(data['updateBatchMessageRequestBody']) : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'UpdateBatchMessage',
+ });
+ }
+
+}
diff --git a/packages/sms/src/rest/v1/batches/index.ts b/packages/sms/src/rest/v1/batches/index.ts
new file mode 100644
index 00000000..bb581ace
--- /dev/null
+++ b/packages/sms/src/rest/v1/batches/index.ts
@@ -0,0 +1 @@
+export * from './batches-api';
diff --git a/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.jest.fixture.ts b/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.jest.fixture.ts
new file mode 100644
index 00000000..0cfe10ef
--- /dev/null
+++ b/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.jest.fixture.ts
@@ -0,0 +1,21 @@
+import { DeliveryReportsApi, GetDeliveryReportByBatchIdRequestData, GetDeliveryReportByPhoneNumberRequestData, GetDeliveryReportsRequestData } from './delivery-reports-api';
+import { DeliveryReport, RecipientDeliveryReport } from '../../../models';
+import { ApiListPromise } from '@sinch/sdk-client';
+
+export class DeliveryReportsApiFixture implements Partial> {
+
+ /**
+ * Fixture associated to function getByBatchId
+ */
+ public get: jest.Mock,
+ [GetDeliveryReportByBatchIdRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function getDeliveryReportByPhoneNumber
+ */
+ public getByPhoneNumber: jest.Mock,
+ [GetDeliveryReportByPhoneNumberRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function list
+ */
+ public list: jest.Mock, [GetDeliveryReportsRequestData]> = jest.fn();
+}
diff --git a/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.ts b/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.ts
new file mode 100644
index 00000000..3ba4cb47
--- /dev/null
+++ b/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.ts
@@ -0,0 +1,170 @@
+import {
+ DeliveryReport,
+ DeliveryReportStatusEnum,
+ RecipientDeliveryReport,
+} from '../../../models';
+import {
+ RequestBody,
+ ApiListPromise,
+ PaginatedApiProperties,
+ PaginationEnum,
+ SinchClientParameters,
+ buildPageResultPromise,
+ createIteratorMethodsForPagination,
+} from '@sinch/sdk-client';
+import { SmsApi } from '../sms-api';
+
+export type GetDeliveryReportByBatchIdTypeEnum = 'summary' | 'full';
+export interface GetDeliveryReportByBatchIdRequestData {
+ /** The batch ID you received from sending a message. */
+ 'batch_id': string;
+ /** The type of delivery report. - A `summary` will count the number of messages sent per status. - A `full` report give that of a `summary` report but in addition, lists phone numbers. */
+ 'type'?: GetDeliveryReportByBatchIdTypeEnum;
+ /** Comma separated list of delivery_report_statuses to include */
+ 'status'?: DeliveryReportStatusEnum[];
+ /** Comma separated list of delivery_receipt_error_codes to include\" */
+ 'code'?: string;
+}
+export interface GetDeliveryReportByPhoneNumberRequestData {
+ /** The batch ID you received from sending a message. */
+ 'batch_id': string;
+ /** Phone number for which you to want to search. */
+ 'recipient_msisdn': string;
+}
+export interface GetDeliveryReportsRequestData {
+ /** The page number starting from 0. */
+ 'page'?: number;
+ /** Determines the size of a page. */
+ 'page_size'?: number;
+ /** Only list messages received at or after this date/time. Default: 24h ago */
+ 'start_date'?: Date;
+ /** Only list messages received before this date/time. */
+ 'end_date'?: Date;
+ /** Comma separated list of delivery report statuses to include. */
+ 'status'?: DeliveryReportStatusEnum[];
+ /** Comma separated list of delivery receipt error codes to include. */
+ 'code'?: string;
+ /** Client reference to include */
+ 'client_reference'?: string;
+}
+
+export class DeliveryReportsApi extends SmsApi {
+
+ /**
+ * Initialize your interface
+ *
+ * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client.
+ */
+ constructor(sinchClientParameters: SinchClientParameters) {
+ super(sinchClientParameters, 'DeliveryReportsApi');
+ }
+
+ /**
+ * Retrieve a delivery report
+ * Delivery reports can be retrieved even if no callback was requested. The difference between a summary and a full report is only that the full report contains the phone numbers in <a href=\"https://community.sinch.com/t5/Glossary/E-164/ta-p/7537\" target=\"_blank\">E.164</a> format for each status code.
+ * @param { GetDeliveryReportByBatchIdRequestData } data - The data to provide to the API call.
+ */
+ public async get(data: GetDeliveryReportByBatchIdRequestData): Promise {
+ this.client = this.getSinchClient();
+ data['type'] = data['type'] !== undefined ? data['type'] : 'summary';
+ const getParams = this.client.extractQueryParams(
+ data,
+ ['type', 'status', 'code'],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}/delivery_report`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'GetDeliveryReportByBatchId',
+ });
+ }
+
+ /**
+ * Retrieve a recipient delivery report
+ * A recipient delivery report contains the message status for a single recipient phone number.
+ * @param { GetDeliveryReportByPhoneNumberRequestData } data - The data to provide to the API call.
+ */
+ public async getByPhoneNumber(data: GetDeliveryReportByPhoneNumberRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}/delivery_report/${data['recipient_msisdn']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'GetDeliveryReportByPhoneNumber',
+ });
+ }
+
+ /**
+ * Retrieve a list of delivery reports
+ * Get a list of finished delivery reports. This operation supports pagination.
+ * @param { GetDeliveryReportsRequestData } data - The data to provide to the API call.
+ * @return {ApiListPromise}
+ */
+ public list(data: GetDeliveryReportsRequestData): ApiListPromise {
+ this.client = this.getSinchClient();
+ data['page'] = data['page'] !== undefined ? data['page'] : 0;
+ data['page_size'] = data['page_size'] !== undefined ? data['page_size'] : 30;
+ const getParams = this.client.extractQueryParams(
+ data,
+ ['page', 'page_size', 'start_date', 'end_date', 'status', 'code', 'client_reference'],
+ );
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/delivery_reports`;
+
+ const requestOptionsPromise
+ = this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined);
+
+ const operationProperties: PaginatedApiProperties = {
+ pagination: PaginationEnum.PAGE,
+ apiName: this.apiName,
+ operationId: 'GetDeliveryReports',
+ dataKey: 'delivery_reports',
+ };
+
+ // Create the promise containing the response wrapped as a PageResult
+ const listPromise = buildPageResultPromise(
+ this.client,
+ requestOptionsPromise,
+ operationProperties);
+
+ // Add properties to the Promise to offer the possibility to use it as an iterator
+ Object.assign(
+ listPromise,
+ createIteratorMethodsForPagination(
+ this.client, requestOptionsPromise, listPromise, operationProperties),
+ );
+
+ return listPromise as ApiListPromise;
+ }
+
+}
diff --git a/packages/sms/src/rest/v1/delivery-reports/index.ts b/packages/sms/src/rest/v1/delivery-reports/index.ts
new file mode 100644
index 00000000..4434f072
--- /dev/null
+++ b/packages/sms/src/rest/v1/delivery-reports/index.ts
@@ -0,0 +1 @@
+export * from './delivery-reports-api';
diff --git a/packages/sms/src/rest/v1/enums.ts b/packages/sms/src/rest/v1/enums.ts
new file mode 100644
index 00000000..274d5fd5
--- /dev/null
+++ b/packages/sms/src/rest/v1/enums.ts
@@ -0,0 +1 @@
+export type { GetDeliveryReportByBatchIdTypeEnum } from './delivery-reports';
diff --git a/packages/sms/src/rest/v1/fixtures.jest.ts b/packages/sms/src/rest/v1/fixtures.jest.ts
new file mode 100644
index 00000000..4111cde7
--- /dev/null
+++ b/packages/sms/src/rest/v1/fixtures.jest.ts
@@ -0,0 +1,4 @@
+export { BatchesApiFixture } from './batches/batches-api.jest.fixture';
+export { DeliveryReportsApiFixture } from './delivery-reports/delivery-reports-api.jest.fixture';
+export { GroupsApiFixture } from './groups/groups-api.jest.fixture';
+export { InboundsApiFixture } from './inbounds/inbounds-api.jest.fixture';
diff --git a/packages/sms/src/rest/v1/groups/groups-api.jest.fixture.ts b/packages/sms/src/rest/v1/groups/groups-api.jest.fixture.ts
new file mode 100644
index 00000000..40371099
--- /dev/null
+++ b/packages/sms/src/rest/v1/groups/groups-api.jest.fixture.ts
@@ -0,0 +1,35 @@
+import { GroupsApi, CreateGroupRequestData, DeleteGroupRequestData, ListMembersRequestData, ListGroupsRequestData, ReplaceGroupRequestData, GetGroupRequestData, UpdateGroupRequestData } from './groups-api';
+import { CreateGroupResponse, GroupResponse } from '../../../models';
+import { ApiListPromise } from '@sinch/sdk-client';
+
+export class GroupsApiFixture implements Partial> {
+
+ /**
+ * Fixture associated to function createGroup
+ */
+ public create: jest.Mock, [CreateGroupRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function deleteGroup
+ */
+ public delete: jest.Mock, [DeleteGroupRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function getMembers
+ */
+ public listMembers: jest.Mock, [ListMembersRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function listGroups
+ */
+ public list: jest.Mock, [ListGroupsRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function replaceGroup
+ */
+ public replace: jest.Mock, [ReplaceGroupRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function retrieveGroup
+ */
+ public get: jest.Mock, [GetGroupRequestData]> = jest.fn();
+ /**
+ * Fixture associated to function updateGroup
+ */
+ public update: jest.Mock, [UpdateGroupRequestData]> = jest.fn();
+}
diff --git a/packages/sms/src/rest/v1/groups/groups-api.ts b/packages/sms/src/rest/v1/groups/groups-api.ts
new file mode 100644
index 00000000..9d68681c
--- /dev/null
+++ b/packages/sms/src/rest/v1/groups/groups-api.ts
@@ -0,0 +1,280 @@
+import {
+ CreateGroupResponse,
+ CreateGroupRequest,
+ ReplaceGroupRequest,
+ UpdateGroupRequest,
+ GroupResponse,
+ ReplaceGroupResponse,
+ UpdateGroupResponse,
+} from '../../../models';
+import {
+ RequestBody,
+ ApiListPromise,
+ PaginatedApiProperties,
+ PaginationEnum,
+ SinchClientParameters,
+ buildPageResultPromise,
+ createIteratorMethodsForPagination,
+} from '@sinch/sdk-client';
+import { SmsApi } from '../sms-api';
+
+export interface CreateGroupRequestData {
+ /** */
+ 'createGroupRequestBody'?: CreateGroupRequest;
+}
+export interface DeleteGroupRequestData {
+ /** ID of a group that you are interested in getting. */
+ 'group_id': string;
+}
+export interface ListMembersRequestData {
+ /** ID of a group that you are interested in getting. */
+ 'group_id': string;
+}
+export interface ListGroupsRequestData {
+ /** The page number starting from 0. */
+ 'page'?: number;
+ /** Determines the size of a page. */
+ 'page_size'?: number;
+}
+export interface ReplaceGroupRequestData {
+ /** ID of a group that you are interested in getting. */
+ 'group_id': string;
+ /** */
+ 'replaceGroupRequestBody'?: ReplaceGroupRequest;
+}
+export interface GetGroupRequestData {
+ /** ID of a group that you are interested in getting. */
+ 'group_id': string;
+}
+export interface UpdateGroupRequestData {
+ /** ID of a group that you are interested in getting. */
+ 'group_id': string;
+ /** */
+ 'updateGroupRequestBody'?: UpdateGroupRequest;
+}
+
+export class GroupsApi extends SmsApi {
+
+ /**
+ * Initialize your interface
+ *
+ * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client.
+ */
+ constructor(sinchClientParameters: SinchClientParameters) {
+ super(sinchClientParameters, 'GroupsApi');
+ }
+
+ /**
+ * Create a group
+ * A group is a set of phone numbers (MSISDNs) that can be used as a target in the `send_batch_msg` operation. An MSISDN can only occur once in a group and any attempts to add a duplicate would be ignored but not rejected.
+ * @param { CreateGroupRequestData } data - The data to provide to the API call.
+ */
+ public async create(data: CreateGroupRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['createGroupRequestBody'] ? JSON.stringify(data['createGroupRequestBody']) : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/groups`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'CreateGroup',
+ });
+ }
+
+ /**
+ * Delete a group
+ * This operation deletes the group with the provided group ID.
+ * @param { DeleteGroupRequestData } data - The data to provide to the API call.
+ */
+ public async delete(data: DeleteGroupRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': '',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/groups/${data['group_id']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'DeleteGroup',
+ });
+ }
+
+ /**
+ * Get phone numbers for a group
+ * This operation retrieves the members of the group with the provided group ID.
+ * @param { ListMembersRequestData } data - The data to provide to the API call.
+ */
+ public async listMembers(data: ListMembersRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/groups/${data['group_id']}/members`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'GetMembers',
+ });
+ }
+
+ /**
+ * List Groups
+ * With the list operation you can list all groups that you have created. This operation supports pagination. Groups are returned in reverse chronological order.
+ * @param { ListGroupsRequestData } data - The data to provide to the API call.
+ * @return {ApiListPromise}
+ */
+ public list(data: ListGroupsRequestData): ApiListPromise {
+ this.client = this.getSinchClient();
+ data['page'] = data['page'] !== undefined ? data['page'] : 0;
+ data['page_size'] = data['page_size'] !== undefined ? data['page_size'] : 30;
+ const getParams = this.client.extractQueryParams(data, ['page', 'page_size']);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/groups`;
+
+ const requestOptionsPromise = this.client.prepareOptions(
+ basePathUrl, 'GET', getParams, headers, body || undefined);
+
+ const operationProperties: PaginatedApiProperties = {
+ pagination: PaginationEnum.PAGE,
+ apiName: this.apiName,
+ operationId: 'ListGroups',
+ dataKey: 'groups',
+ };
+
+ // Create the promise containing the response wrapped as a PageResult
+ const listPromise = buildPageResultPromise(
+ this.client,
+ requestOptionsPromise,
+ operationProperties);
+
+ // Add properties to the Promise to offer the possibility to use it as an iterator
+ Object.assign(
+ listPromise,
+ createIteratorMethodsForPagination(
+ this.client, requestOptionsPromise, listPromise, operationProperties),
+ );
+
+ return listPromise as ApiListPromise;
+ }
+
+ /**
+ * Replace a group
+ * The replace operation will replace all parameters, including members, of an existing group with new values. Replacing a group targeted by a batch message scheduled in the future is allowed and changes will be reflected when the batch is sent.
+ * @param { ReplaceGroupRequestData } data - The data to provide to the API call.
+ */
+ public async replace(data: ReplaceGroupRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['replaceGroupRequestBody'] ? JSON.stringify(data['replaceGroupRequestBody']) : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/groups/${data['group_id']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'PUT', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'ReplaceGroup',
+ });
+ }
+
+ /**
+ * Retrieve a group
+ * This operation retrieves a specific group with the provided group ID.
+ * @param { GetGroupRequestData } data - The data to provide to the API call.
+ */
+ public async get(data: GetGroupRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = '';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/groups/${data['group_id']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall({
+ url,
+ requestOptions,
+ apiName: this.apiName,
+ operationId: 'RetrieveGroup',
+ });
+ }
+
+ /**
+ * Update a group
+ * With the update group operation, you can add and remove members in an existing group as well as rename the group. This method encompasses a few ways to update a group: 1. By using `add` and `remove` arrays containing phone numbers, you control the group movements. Any list of valid numbers in E.164 format can be added. 2. By using the `auto_update` object, your customer can add or remove themselves from groups. 3. You can also add or remove other groups into this group with `add_from_group` and `remove_from_group`. #### Other group update info - The request will not be rejected for duplicate adds or unknown removes. - The additions will be done before the deletions. If an phone number is on both lists, it will not be apart of the resulting group. - Updating a group targeted by a batch message scheduled in the future is allowed. Changes will be reflected when the batch is sent.
+ * @param { UpdateGroupRequestData } data - The data to provide to the API call.
+ */
+ public async update(data: UpdateGroupRequestData): Promise {
+ this.client = this.getSinchClient();
+ const getParams = this.client.extractQueryParams(data, [] as never[]);
+ const headers: { [key: string]: string | undefined } = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ };
+
+ const body: RequestBody = data['updateGroupRequestBody'] ? JSON.stringify(data['updateGroupRequestBody']) : '{}';
+ const basePathUrl = `${this.client.apiClientOptions.basePath}/xms/v1/${this.client.apiClientOptions.projectId}/groups/${data['group_id']}`;
+
+ const requestOptions
+ = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined);
+ const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams);
+
+ return this.client.processCall