├── examples ├── calls │ ├── create-call │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── main.bal │ │ └── Create call.md │ ├── fetch-call-log │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── Fetch call log.md │ │ └── main.bal │ ├── list-call-logs │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── List call logs.md │ │ └── main.bal │ └── delete-call-log │ │ ├── .github │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── Delete call log.md │ │ └── main.bal ├── accounts │ ├── fetch-account │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── Fetch account.md │ │ └── main.bal │ ├── fetch-balance │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── Fetch balance.md │ │ └── main.bal │ ├── list-accounts │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── List accounts.md │ │ └── main.bal │ ├── update-account │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── Update account.md │ │ └── main.bal │ └── create-sub-account │ │ ├── .github │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── main.bal │ │ └── Create sub account.md ├── messages │ ├── create-sms-message │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── main.bal │ │ └── Create SMS Message.md │ ├── delete-message-log │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── Delete message log.md │ │ └── main.bal │ ├── fetch-message-log │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── Fetch message log.md │ │ └── main.bal │ ├── list-message-logs │ │ ├── .github │ │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── List message log.md │ │ └── main.bal │ └── create-whatsapp-message │ │ ├── .github │ │ └── README.md │ │ ├── Ballerina.toml │ │ ├── Create Whatsapp message.md │ │ └── main.bal ├── build.sh ├── build.gradle └── README.md ├── ballerina ├── icon.png ├── resources │ ├── api-key-info.png │ ├── api-key-config.png │ ├── create-api-key.png │ ├── get-credentails.png │ ├── get-phone-number.png │ ├── phone-number-config.png │ └── search-phone-number.png ├── Ballerina.toml ├── build.gradle ├── tests │ ├── README.md │ └── tests.bal ├── Dependencies.toml ├── Module.md ├── Package.md ├── utils.bal └── modules │ └── oas │ └── utils.bal ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github ├── pull_request_template.md ├── CODEOWNERS └── workflows │ ├── daily-build.yml │ ├── pull-request.yml │ ├── ci.yml │ ├── release.yml │ ├── dev-stage-release.yml │ └── regenerate-connector.yml ├── gradle.properties ├── docs ├── license.txt ├── spec │ ├── wrapper-sanitization.md │ └── sanitizations.md └── proposals │ └── api_key_auth_support.md ├── .gitignore ├── settings.gradle ├── changelog.md ├── gradlew.bat ├── gradlew ├── LICENSE.txt └── README.md /examples/calls/create-call/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Create call.md -------------------------------------------------------------------------------- /examples/accounts/fetch-account/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Fetch account.md -------------------------------------------------------------------------------- /examples/accounts/fetch-balance/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Fetch balance.md -------------------------------------------------------------------------------- /examples/accounts/list-accounts/.github/README.md: -------------------------------------------------------------------------------- 1 | ../List accounts.md -------------------------------------------------------------------------------- /examples/calls/fetch-call-log/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Fetch call log.md -------------------------------------------------------------------------------- /examples/calls/list-call-logs/.github/README.md: -------------------------------------------------------------------------------- 1 | ../List call logs.md -------------------------------------------------------------------------------- /examples/accounts/update-account/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Update account.md -------------------------------------------------------------------------------- /examples/calls/delete-call-log/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Delete call log.md -------------------------------------------------------------------------------- /examples/accounts/create-sub-account/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Create sub account.md -------------------------------------------------------------------------------- /examples/messages/create-sms-message/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Create SMS Message.md -------------------------------------------------------------------------------- /examples/messages/delete-message-log/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Delete message log.md -------------------------------------------------------------------------------- /examples/messages/fetch-message-log/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Fetch message log.md -------------------------------------------------------------------------------- /examples/messages/list-message-logs/.github/README.md: -------------------------------------------------------------------------------- 1 | ../List message log.md -------------------------------------------------------------------------------- /examples/messages/create-whatsapp-message/.github/README.md: -------------------------------------------------------------------------------- 1 | ../Create Whatsapp message.md -------------------------------------------------------------------------------- /ballerina/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/ballerina/icon.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /ballerina/resources/api-key-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/ballerina/resources/api-key-info.png -------------------------------------------------------------------------------- /ballerina/resources/api-key-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/ballerina/resources/api-key-config.png -------------------------------------------------------------------------------- /ballerina/resources/create-api-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/ballerina/resources/create-api-key.png -------------------------------------------------------------------------------- /ballerina/resources/get-credentails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/ballerina/resources/get-credentails.png -------------------------------------------------------------------------------- /ballerina/resources/get-phone-number.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/ballerina/resources/get-phone-number.png -------------------------------------------------------------------------------- /ballerina/resources/phone-number-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/ballerina/resources/phone-number-config.png -------------------------------------------------------------------------------- /ballerina/resources/search-phone-number.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/HEAD/ballerina/resources/search-phone-number.png -------------------------------------------------------------------------------- /examples/calls/create-call/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "create_call" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/calls/fetch-call-log/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "fetch_call_log" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/calls/list-call-logs/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "list_call_logs" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/accounts/fetch-account/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "fetch_account" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/accounts/fetch-balance/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "fetch_balance" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/accounts/list-accounts/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "list_accounts" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/accounts/update-account/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "update_account" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/calls/delete-call-log/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "delete_call_log" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/messages/fetch-message-log/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "fetch_message" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/messages/list-message-logs/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "list_messages" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/messages/delete-message-log/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "delete_message" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/accounts/create-sub-account/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "create_sub_account" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/messages/create-sms-message/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "create_sms_message" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /examples/messages/create-whatsapp-message/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "twilio_samples" 3 | name = "create_whatsapp_message" 4 | version = "0.1.0" 5 | distribution = "2201.8.2" 6 | 7 | [build-options] 8 | observabilityIncluded = true 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | Fixes: 4 | 5 | ## Examples 6 | 7 | ## Checklist 8 | - [ ] Linked to an issue 9 | - [ ] Updated the specification 10 | - [ ] Updated the changelog 11 | - [ ] Added tests 12 | - [ ] Checked native-image compatibility -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # See: https://help.github.com/articles/about-codeowners/ 5 | 6 | # These owners will be the default owners for everything in the repo. 7 | * @niveathika @RDPerera @shafreenAnfar 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.caching=true 2 | group=io.ballerina.stdlib 3 | version=5.0.1-SNAPSHOT 4 | ballerinaLangVersion=2201.10.0 5 | 6 | checkstylePluginVersion=10.12.0 7 | spotbugsPluginVersion=5.0.14 8 | shadowJarPluginVersion=8.1.1 9 | downloadPluginVersion=5.4.0 10 | releasePluginVersion=2.8.0 11 | testngVersion=7.6.1 12 | eclipseLsp4jVersion=0.12.0 13 | ballerinaGradlePluginVersion=2.2.4 14 | -------------------------------------------------------------------------------- /.github/workflows/daily-build.yml: -------------------------------------------------------------------------------- 1 | name: Daily build 2 | 3 | on: 4 | schedule: 5 | - cron: "30 2 * * *" 6 | 7 | jobs: 8 | call_workflow: 9 | name: Run Daily Build Workflow 10 | if: ${{ github.repository_owner == 'ballerina-platform' }} 11 | uses: ballerina-platform/ballerina-library/.github/workflows/daily-build-connector-template.yml@main 12 | secrets: inherit 13 | with: 14 | repo-name: module-ballerinax-twilio 15 | -------------------------------------------------------------------------------- /ballerina/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | distribution = "2201.10.0" 3 | org = "ballerinax" 4 | name = "twilio" 5 | version = "5.0.1" 6 | authors = ["Ballerina"] 7 | repository = "https://github.com/ballerina-platform/module-ballerinax-twilio" 8 | keywords = ["Communication/Call & SMS", "Cost/Paid", "Vendor/Twilio", "Area/Communication", "Type/Connector"] 9 | icon = "icon.png" 10 | license = ["Apache-2.0"] 11 | 12 | [build-options] 13 | observabilityIncluded = true 14 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: PR Build 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: pull_request 8 | 9 | jobs: 10 | call_workflow: 11 | name: Run PR Build Workflow 12 | if: ${{ github.repository_owner == 'ballerina-platform' }} 13 | uses: ballerina-platform/ballerina-library/.github/workflows/pr-build-connector-template.yml@main 14 | secrets: inherit 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - 2201.[0-9]+.x 8 | repository_dispatch: 9 | types: check_connector_for_breaking_changes 10 | 11 | jobs: 12 | call_workflow: 13 | name: Run Connector Build Workflow 14 | if: ${{ github.repository_owner == 'ballerina-platform' }} 15 | uses: ballerina-platform/ballerina-library/.github/workflows/build-connector-template.yml@main 16 | secrets: inherit 17 | with: 18 | repo-name: module-ballerinax-twilio 19 | -------------------------------------------------------------------------------- /examples/messages/list-message-logs/List message log.md: -------------------------------------------------------------------------------- 1 | # List messages 2 | 3 | This example demonstrates how to list messages using Twilio connector. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /examples/messages/delete-message-log/Delete message log.md: -------------------------------------------------------------------------------- 1 | # Delete Message 2 | 3 | This example demonstrates how to delete a message using Twilio connector. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Release 2 | 3 | on: 4 | workflow_dispatch: 5 | repository_dispatch: 6 | types: [ stdlib-release-pipeline ] 7 | 8 | jobs: 9 | call_workflow: 10 | name: Run Release Workflow 11 | if: ${{ github.repository_owner == 'ballerina-platform' }} 12 | uses: ballerina-platform/ballerina-library/.github/workflows/release-package-connector-template.yml@main 13 | secrets: inherit 14 | with: 15 | package-name: twilio 16 | package-org: ballerinax 17 | additional-build-flags: "-x :twilio-examples:build" 18 | additional-release-flags: "-x :twilio-examples:build" 19 | additional-publish-flags: "-x :twilio-examples:build" 20 | -------------------------------------------------------------------------------- /examples/calls/fetch-call-log/Fetch call log.md: -------------------------------------------------------------------------------- 1 | # Fetch call log for a Twilio account 2 | 3 | This example demonstrates how to fetch call log for a call using Twilio connector. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /examples/messages/fetch-message-log/Fetch message log.md: -------------------------------------------------------------------------------- 1 | # Fetch message information 2 | 3 | This example demonstrates how to fetch message information using Twilio connector. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /docs/license.txt: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | -------------------------------------------------------------------------------- /examples/messages/create-whatsapp-message/Create Whatsapp message.md: -------------------------------------------------------------------------------- 1 | # Send Whatsapp Message 2 | 3 | This example demonstrates how to send a Whatsapp message using Twilio connector. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /examples/calls/delete-call-log/Delete call log.md: -------------------------------------------------------------------------------- 1 | # Delete call log for a call using Twilio 2 | 3 | This example demonstrates how to delete call log for a call using Twilio connector. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID = "" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /.github/workflows/dev-stage-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish to the Ballerina Dev\Stage Central 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | environment: 7 | type: choice 8 | description: Select Environment 9 | required: true 10 | options: 11 | - DEV CENTRAL 12 | - STAGE CENTRAL 13 | 14 | jobs: 15 | call_workflow: 16 | name: Run Dev\Stage Central Publish Workflow 17 | if: ${{ github.repository_owner == 'ballerina-platform' }} 18 | uses: ballerina-platform/ballerina-library/.github/workflows/dev-stage-central-publish-connector-template.yml@main 19 | secrets: inherit 20 | with: 21 | environment: ${{ github.event.inputs.environment }} 22 | -------------------------------------------------------------------------------- /examples/accounts/fetch-account/Fetch account.md: -------------------------------------------------------------------------------- 1 | # Fetch account details for a Twilio account 2 | 3 | This example demonstrates how to fetch account details for a Twilio account using Ballerina. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /examples/accounts/fetch-balance/Fetch balance.md: -------------------------------------------------------------------------------- 1 | # Fetch account balance for a Twilio account 2 | 3 | This example demonstrates how to fetch account balance for a Twilio account using Ballerina. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /examples/accounts/update-account/Update account.md: -------------------------------------------------------------------------------- 1 | # Update account details for a Twilio account 2 | 3 | This example demonstrates how to update account details for a Twilio account using Ballerina. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /examples/calls/list-call-logs/List call logs.md: -------------------------------------------------------------------------------- 1 | # Listdown all the call logs under a Twilio account 2 | 3 | This example demonstrates how to list down all the call logs under a Twilio account using Ballerina. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /examples/accounts/list-accounts/List accounts.md: -------------------------------------------------------------------------------- 1 | # Listdown all the sub-accounts under a Twilio account 2 | 3 | This example demonstrates how to list down all the sub-accounts under a Twilio account using Ballerina. 4 | 5 | ## Prerequisites 6 | 7 | ### 1. Set up 8 | Refer to the setup guide in [Ballerina Central](https://central.ballerina.io/ballerinax/twilio/latest) for necessary credentials. 9 | 10 | ### 2. Configuration 11 | 12 | Configure Twilio API credentials in Config.toml in the example directory: 13 | 14 | ```toml 15 | API_KEY="" 16 | API_SECRET="" 17 | ACCOUNT_SID="" 18 | ``` 19 | 20 | ## Run the Example 21 | 22 | Execute the following command to run the example: 23 | 24 | ```bash 25 | bal run 26 | ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore compiled class file 2 | *.class 3 | 4 | # Ignore log file 5 | *.log 6 | 7 | # Ignore config file 8 | **/Config.toml 9 | 10 | # Ignore BlueJ files 11 | *.ctxt 12 | 13 | # Ignore mobile tools for Java (J2ME) 14 | .mtj.tmp/ 15 | 16 | # Ignore package Files # 17 | *.jar 18 | !gradle-wrapper/*.jar 19 | *.war 20 | *.ear 21 | *.zip 22 | *.tar.gz 23 | *.rar 24 | *.deb 25 | 26 | # Ignore virtual machine crash logs 27 | hs_err_pid* 28 | 29 | # Ignore everything in these directories 30 | target 31 | .idea 32 | .classpath 33 | .settings 34 | .project 35 | .vscode 36 | *.iml 37 | *.ipr 38 | *.iws 39 | .gradle 40 | build 41 | generated 42 | 43 | # Ignore MAC DS files 44 | .DS_Store 45 | 46 | # Ignore environment files 47 | *.env 48 | 49 | # Ignore all Dependencies.toml files in the examples directory 50 | examples/**/Dependencies.toml 51 | 52 | # Ignore cache 53 | .cache/ 54 | -------------------------------------------------------------------------------- /examples/accounts/fetch-account/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to fetch an account 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | twilio:Account account = check twilio->fetchAccount(accountSid); 38 | io:println("Account details: " + account.toString()); 39 | } 40 | -------------------------------------------------------------------------------- /examples/accounts/fetch-balance/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to fetch balance of an account 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | twilio:Balance balance = check twilio->fetchBalance(accountSid); 38 | io:println(balance?.balance, balance?.currency); 39 | } 40 | -------------------------------------------------------------------------------- /examples/messages/fetch-message-log/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to fetch a message. 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | 38 | string MessageSID = "SM4f16fca1d7391c99249b842f063c4da0"; 39 | 40 | twilio:Message message = check twilio->fetchMessage(MessageSID); 41 | io:println("Message details: " + message.toString()); 42 | } 43 | -------------------------------------------------------------------------------- /examples/accounts/create-sub-account/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 22 | configurable string authToken = os:getEnv("AUTH_TOKEN"); 23 | 24 | // Twilio configurations 25 | twilio:ConnectionConfig twilioConfig = { 26 | auth: { 27 | accountSid, 28 | authToken 29 | } 30 | }; 31 | 32 | // This sample demonstrates a scenario where Twilio connector is used to create a subaccount under the account which one used to make the request. 33 | public function main() returns error? { 34 | twilio:Client twilio = check new (twilioConfig); 35 | 36 | twilio:CreateAccountRequest subAccountReqest = { 37 | FriendlyName: "Sample Sub Account" 38 | }; 39 | 40 | twilio:Account subAccountInfo = check twilio->createAccount(subAccountReqest); 41 | io:println(subAccountInfo.toString()); 42 | } 43 | -------------------------------------------------------------------------------- /examples/calls/create-call/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 22 | configurable string authToken = os:getEnv("AUTH_TOKEN"); 23 | 24 | // Twilio configurations 25 | twilio:ConnectionConfig twilioConfig = { 26 | auth: { 27 | accountSid, 28 | authToken 29 | } 30 | }; 31 | 32 | // This sample demonstrates a scenario where Twilio connector is used to make a voice call to a number. 33 | public function main() returns error? { 34 | twilio:Client twilio = check new (twilioConfig); 35 | 36 | twilio:CreateCallRequest callRequest = { 37 | To: "+00123456789", 38 | From: "+00123456789", 39 | Url: "http://demo.twilio.com/docs/voice.xml" 40 | }; 41 | 42 | twilio:Call response = check twilio->createCall(callRequest); 43 | io:println("Call Status: ",response?.status); 44 | } 45 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.3/userguide/building_swift_projects.html in the Gradle documentation. 6 | */ 7 | 8 | pluginManagement { 9 | plugins { 10 | id "com.github.spotbugs-base" version "${spotbugsPluginVersion}" 11 | id "com.github.johnrengelman.shadow" version "${shadowJarPluginVersion}" 12 | id "de.undercouch.download" version "${downloadPluginVersion}" 13 | id "net.researchgate.release" version "${releasePluginVersion}" 14 | id "io.ballerina.plugin" version "${ballerinaGradlePluginVersion}" 15 | } 16 | 17 | repositories { 18 | gradlePluginPortal() 19 | maven { 20 | url = 'https://maven.pkg.github.com/ballerina-platform/*' 21 | credentials { 22 | username System.getenv("packageUser") 23 | password System.getenv("packagePAT") 24 | } 25 | } 26 | } 27 | } 28 | 29 | plugins { 30 | id "com.gradle.enterprise" version "3.2" 31 | } 32 | 33 | rootProject.name = 'module-ballerinax-twilio' 34 | 35 | include ':twilio-ballerina' 36 | include ':twilio-examples' 37 | 38 | project(':twilio-ballerina').projectDir = file("ballerina") 39 | project(':twilio-examples').projectDir = file("examples") 40 | 41 | gradleEnterprise { 42 | buildScan { 43 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 44 | termsOfServiceAgree = 'yes' 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/messages/create-sms-message/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 22 | configurable string authToken = os:getEnv("AUTH_TOKEN"); 23 | 24 | // Twilio configurations 25 | twilio:ConnectionConfig twilioConfig = { 26 | auth: { 27 | accountSid, 28 | authToken 29 | } 30 | }; 31 | 32 | // This sample demonstrates a scenario where Twilio connector is used to send a text message to a number. 33 | public function main() returns error? { 34 | twilio:Client twilio = check new (twilioConfig); 35 | 36 | twilio:CreateMessageRequest messageRequest = { 37 | To: "+00123456789", 38 | From: "+00123456789", 39 | Body: "Hello from Ballerina" 40 | }; 41 | 42 | twilio:Message response = check twilio->createMessage(messageRequest); 43 | io:print("Message Status: ",response?.status); 44 | } 45 | -------------------------------------------------------------------------------- /examples/accounts/update-account/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to update a Twilio account. 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | 38 | twilio:UpdateAccountRequest updateAccountRequest = { 39 | FriendlyName: "Sample Account Name" 40 | }; 41 | 42 | twilio:Account updatedAccountInfo = check twilio->updateAccount(accountSid, updateAccountRequest); 43 | io:println(updatedAccountInfo?.friendly_name); 44 | } 45 | -------------------------------------------------------------------------------- /examples/calls/list-call-logs/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to list all call logs. 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | 38 | twilio:ListCallResponse response = check twilio->listCall(); 39 | 40 | twilio:Call[]? calls = response.calls; 41 | if calls is twilio:Call[] { 42 | calls.forEach(function(twilio:Call call) { 43 | io:println("Call details: " + call.toString()); 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/accounts/list-accounts/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to list all accounts. 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | twilio:ListAccountResponse response = check twilio->listAccount(); 38 | 39 | twilio:Account[]? accounts = response.accounts; 40 | if accounts is twilio:Account[] { 41 | accounts.forEach(function(twilio:Account account) { 42 | io:println("Account details: " + account.toString()); 43 | }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /examples/messages/list-message-logs/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to list all messages. 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | 38 | twilio:ListMessageResponse response = check twilio->listMessage(); 39 | 40 | twilio:Message[]? messages = response.messages; 41 | if messages is twilio:Message[] { 42 | messages.forEach(function(twilio:Message message) { 43 | io:println("Message: " + message.toString()); 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/messages/create-whatsapp-message/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to send a whatsapp message to a number. 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | 38 | twilio:CreateMessageRequest messageRequest = { 39 | To: "whatsapp:+00123456789", 40 | From: "whatsapp:+00123456789", 41 | Body: "Hello from Ballerina" 42 | }; 43 | 44 | twilio:Message response = check twilio->createMessage(messageRequest); 45 | io:print("Whatsapp Message Status: ",response?.status); 46 | } 47 | -------------------------------------------------------------------------------- /examples/messages/delete-message-log/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/http; 18 | import ballerina/io; 19 | import ballerina/os; 20 | import ballerinax/twilio; 21 | 22 | configurable string apiKey = os:getEnv("API_KEY"); 23 | configurable string apiSecret = os:getEnv("API_SECRET"); 24 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 25 | 26 | // Twilio configurations 27 | twilio:ConnectionConfig twilioConfig = { 28 | auth: { 29 | apiKey, 30 | apiSecret, 31 | accountSid 32 | } 33 | }; 34 | 35 | // This sample demonstrates a scenario where Twilio connector is used to delete a message. 36 | public function main() returns error? { 37 | twilio:Client twilio = check new (twilioConfig); 38 | 39 | string MessageSID = "SM55a867023dcf1e506aa6a67b514d370c"; 40 | 41 | http:Response? response = check twilio->deleteMessage(MessageSID); 42 | if response is http:Response { 43 | io:println("Message deleted successfully!"); 44 | } else { 45 | io:println("Error! deleting the message failed."); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /examples/calls/fetch-call-log/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/twilio; 20 | 21 | configurable string apiKey = os:getEnv("API_KEY"); 22 | configurable string apiSecret = os:getEnv("API_SECRET"); 23 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 24 | 25 | // Twilio configurations 26 | twilio:ConnectionConfig twilioConfig = { 27 | auth: { 28 | apiKey, 29 | apiSecret, 30 | accountSid 31 | } 32 | }; 33 | 34 | // This sample demonstrates a scenario where Twilio connector is used to fetch a call log. 35 | public function main() returns error? { 36 | twilio:Client twilio = check new (twilioConfig); 37 | 38 | // Call SID: An identifier of 34 digits in length that uniquely identifies a call (https://support.twilio.com/hc/en-us/articles/223180488-What-is-a-Call-SID-). 39 | // You can obtain this identifier by running the 'listCall()' or by accessing the TwilioConsole > Monitor > Logs > CallLogs 40 | string CallSID = "CAeb8427d6e95108ff0a8953fa301d1f1f"; 41 | 42 | twilio:Call call = check twilio->fetchCall(CallSID); 43 | io:println("Call details: " + call.toString()); 44 | } 45 | -------------------------------------------------------------------------------- /docs/spec/wrapper-sanitization.md: -------------------------------------------------------------------------------- 1 | # Sanitization for client 2 | After generating the client using OpenAPI specification, the following modifications are made to the generated client by introducing a wrapper client. 3 | 4 | 1. Removed the `string accountSid` parameter from all non-account-related functions and added it as an optional parameter to each function, with the default parameter set to `accountSid` in the initial client configurations. 5 | 6 | For example, the function: 7 | 8 | ```ballerina 9 | remote isolated function createCall(string accountSid, CreateCallRequest payload) returns Call|error { 10 | } 11 | ``` 12 | 13 | is restructured as: 14 | 15 | ```ballerina 16 | remote isolated function createCall(CreateCallRequest payload, string? accountSid = ()) returns Call|error { 17 | return self.generatedClient->createCall(accountSid ?: self.accountSid, payload); 18 | } 19 | ``` 20 | 21 | 2. Updated authentication configuration structure replacing the original `http:CredentialsConfig` with custom authentication configurations, allowing support for both Auth Token based and API Key based authentication mechanisms. 22 | 23 | The `ConnectionConfig` type now accepts `AuthTokenConfig` or `ApiKeyConfig` as possible values for the `auth` field. 24 | 25 | ```ballerina 26 | public type ConnectionConfig record {| 27 | AuthTokenConfig|ApiKeyConfig auth; 28 | // Other methods 29 | |} 30 | ``` 31 | 32 | `AuthTokenConfig`: Contains `accountSid` and `authToken` for standard token-based authentication. 33 | 34 | ```ballerina 35 | public type AuthTokenConfig record {| 36 | string accountSid; 37 | string authToken; 38 | |}; 39 | ``` 40 | 41 | `ApiKeyConfig`: Contains `accountSid`, `apiKey`, and `apiSecret` for API key-based authentication. 42 | 43 | ```ballerina 44 | public type ApiKeyConfig record {| 45 | string apiKey; 46 | string apiSecret; 47 | string accountSid; 48 | |}; 49 | ``` 50 | -------------------------------------------------------------------------------- /examples/calls/delete-call-log/main.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/http; 18 | import ballerina/io; 19 | import ballerina/os; 20 | import ballerinax/twilio; 21 | 22 | configurable string apiKey = os:getEnv("API_KEY"); 23 | configurable string apiSecret = os:getEnv("API_SECRET"); 24 | configurable string accountSid = os:getEnv("ACCOUNT_SID"); 25 | 26 | // Twilio configurations 27 | twilio:ConnectionConfig twilioConfig = { 28 | auth: { 29 | apiKey, 30 | apiSecret, 31 | accountSid 32 | } 33 | }; 34 | 35 | // This sample demonstrates a scenario where Twilio connector is used to delete a call log. 36 | public function main() returns error? { 37 | twilio:Client twilio = check new (twilioConfig); 38 | 39 | // Call SID: An identifier of 34 digits in length that uniquely identifies a call (https://support.twilio.com/hc/en-us/articles/223180488-What-is-a-Call-SID-). 40 | // You can obtain this identifier by running the 'listCall()' or by accessing the TwilioConsole > Monitor > Logs > CallLogs 41 | string CallSID = "CAeb8427d6e95108ff0a8953fa301d1f1f"; 42 | 43 | http:Response? response = check twilio->deleteCall(CallSID); 44 | if response is http:Response { 45 | io:println("Call log Deleted."); 46 | } else { 47 | io:println("Error! deleting the call log failed."); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BAL_EXAMPLES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | BAL_CENTRAL_DIR="$HOME/.ballerina/repositories/central.ballerina.io" 5 | BAL_HOME_DIR="$BAL_EXAMPLES_DIR/../ballerina" 6 | 7 | set -e 8 | 9 | case "$1" in 10 | build) 11 | BAL_CMD="build" 12 | ;; 13 | run) 14 | BAL_CMD="run" 15 | ;; 16 | *) 17 | echo "Invalid command provided: '$1'. Please provide 'build' or 'run' as the command." 18 | exit 1 19 | ;; 20 | esac 21 | 22 | # Read Ballerina package name 23 | BAL_PACKAGE_NAME=$(awk -F'"' '/^name/ {print $2}' "$BAL_HOME_DIR/Ballerina.toml") 24 | 25 | # Push the package to the local repository 26 | cd "$BAL_HOME_DIR" && 27 | bal pack && 28 | bal push --repository=local 29 | 30 | # Remove the cache directories in the repositories 31 | cacheDirs=$(ls -d $BAL_CENTRAL_DIR/cache-* 2>/dev/null) || true 32 | for dir in "${cacheDirs[@]}"; do 33 | [ -d "$dir" ] && rm -r "$dir" 34 | done 35 | echo "Successfully cleaned the cache directories" 36 | 37 | # Create the package directory in the central repository, this will not be present if no modules are pulled 38 | mkdir -p "$BAL_CENTRAL_DIR/bala/ballerinax/$BAL_PACKAGE_NAME" 39 | 40 | # Update the central repository 41 | BAL_DESTINATION_DIR="$HOME/.ballerina/repositories/central.ballerina.io/bala/ballerinax/$BAL_PACKAGE_NAME" 42 | BAL_SOURCE_DIR="$HOME/.ballerina/repositories/local/bala/ballerinax/$BAL_PACKAGE_NAME" 43 | [ -d "$BAL_DESTINATION_DIR" ] && rm -r "$BAL_DESTINATION_DIR" 44 | [ -d "$BAL_SOURCE_DIR" ] && cp -r "$BAL_SOURCE_DIR" "$BAL_DESTINATION_DIR" 45 | echo "Successfully updated the local central repositories" 46 | 47 | echo "$BAL_DESTINATION_DIR" 48 | echo "$BAL_SOURCE_DIR" 49 | 50 | # Loop through examples in the examples directory 51 | cd "$BAL_EXAMPLES_DIR" 52 | for dir in $(find "$BAL_EXAMPLES_DIR" -type d -maxdepth 2 -mindepth 2); do 53 | # Skip the lib and tmp directories in build directory 54 | if [[ "$dir" == *libs ]] || [[ "$dir" == *tmp ]]; then 55 | continue 56 | fi 57 | (cd "$dir" && bal "$BAL_CMD" --offline && cd ..); 58 | done 59 | 60 | # Remove generated JAR files 61 | find "$BAL_HOME_DIR" -maxdepth 2 -type f -name "*.jar" | while read -r JAR_FILE; do 62 | rm "$JAR_FILE" 63 | done -------------------------------------------------------------------------------- /.github/workflows/regenerate-connector.yml: -------------------------------------------------------------------------------- 1 | name: Regenerate OpenAPI Connector 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | openapi-url: 7 | description: "URL of the OpenAPI JSON" 8 | required: false 9 | type: string 10 | flatten-openapi: 11 | description: "Enable OpenAPI Flattening" 12 | required: false 13 | type: boolean 14 | default: true 15 | additional-flatten-flags: 16 | description: "Additional flags for OpenAPI Flattening" 17 | required: false 18 | type: string 19 | default: "" 20 | align-openapi: 21 | description: "Enable OpenAPI Alignment" 22 | required: false 23 | type: boolean 24 | default: true 25 | additional-align-flags: 26 | description: "Additional flags for OpenAPI Alignment" 27 | required: false 28 | type: string 29 | default: "" 30 | additional-generation-flags: 31 | description: "Additional flags for OpenAPI Generation" 32 | required: false 33 | type: string 34 | default: "" 35 | distribution-zip: 36 | description: "Distribution of the Ballerina version to be used" 37 | required: false 38 | type: string 39 | default: "" 40 | auto-merge: 41 | description: "Enable auto-merge of the PR" 42 | required: false 43 | type: boolean 44 | default: true 45 | ballerina-version: 46 | description: "Ballerina Language Version" 47 | required: false 48 | type: string 49 | default: "" 50 | 51 | jobs: 52 | call_workflow: 53 | name: Run Regenerate Connector Workflow 54 | if: ${{ github.repository_owner == 'ballerina-platform' }} 55 | uses: ballerina-platform/ballerina-library/.github/workflows/regenerate-connector-template.yml@main 56 | secrets: inherit 57 | with: 58 | openapi-url: ${{ inputs.openapi-url }} 59 | flatten-openapi: ${{ inputs.flatten-openapi }} 60 | additional-flatten-flags: ${{ inputs.additional-flatten-flags }} 61 | align-openapi: ${{ inputs.align-openapi }} 62 | additional-align-flags: ${{ inputs.additional-align-flags }} 63 | additional-generation-flags: ${{ inputs.additional-generation-flags }} 64 | distribution-zip: ${{ inputs.distribution-zip }} 65 | auto-merge: ${{ inputs.auto-merge }} 66 | ballerina-version: ${{ inputs.ballerina-version }} 67 | generation-path: "ballerina/modules/oas" 68 | -------------------------------------------------------------------------------- /examples/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import org.apache.tools.ant.taskdefs.condition.Os 20 | 21 | apply plugin: 'java' 22 | 23 | def graalvmFlag = "" 24 | 25 | task testExamples { 26 | if (project.hasProperty("balGraalVMTest")) { 27 | graalvmFlag = "--graalvm" 28 | } 29 | doLast { 30 | try { 31 | exec { 32 | workingDir project.projectDir 33 | println("Working dir: ${workingDir}") 34 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 35 | commandLine 'cmd', "/c", "chmod +x ./build.sh && ./build.sh run && exit %%ERRORLEVEL%%" 36 | } else { 37 | commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh run" 38 | } 39 | } 40 | } catch (Exception e) { 41 | println("Example Build failed: " + e.message) 42 | throw e 43 | } 44 | } 45 | } 46 | 47 | task buildExamples { 48 | gradle.taskGraph.whenReady { graph -> 49 | if (graph.hasTask(":twilio-examples:test")) { 50 | buildExamples.enabled = false 51 | } else { 52 | testExamples.enabled = false 53 | } 54 | } 55 | doLast { 56 | try { 57 | exec { 58 | workingDir project.projectDir 59 | println("Working dir: ${workingDir}") 60 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 61 | commandLine 'cmd', "/c", "chmod +x ./build.sh && ./build.sh build && exit %%ERRORLEVEL%%" 62 | } else { 63 | commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh build" 64 | } 65 | } 66 | } catch (Exception e) { 67 | println("Example Build failed: " + e.message) 68 | throw e 69 | } 70 | } 71 | } 72 | 73 | buildExamples.dependsOn ":twilio-ballerina:build" 74 | testExamples.dependsOn ":twilio-ballerina:build" 75 | 76 | // TODO: Enable the examples build once https://github.com/ballerina-platform/ballerina-library/issues/6135 is fixed 77 | // build.dependsOn buildExamples 78 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | This file contains all the notable changes done to the Ballerina Twilio Connector through the releases. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | ### Added 9 | - [Add API Key based authentication support for the Ballerina Twilio connector](https://github.com/ballerina-platform/ballerina-library/issues/7343) 10 | 11 | ## [4.0.1] - 2024-02-15 12 | ### Changed 13 | - Documentation updated with minor changes. 14 | 15 | ## [4.0.0] - 2024-01-12 16 | ### Added 17 | - Following functionalities are added to the Twilio connector. 18 | - Create a new Twilio subaccount 19 | - Retrieve a collection of accounts linked to the requester's account 20 | - Modify account properties 21 | - Handle addresses: create, list, delete, fetch, update 22 | - Manage applications: create, retrieve list, delete, fetch, update properties 23 | - Work with authorized connect apps: fetch instance, retrieve list 24 | - List available phone number countries and types 25 | - Fetch account balance 26 | - Manage outgoing calls and recordings 27 | - Handle conferences: fetch instance, update, retrieve list 28 | - Manage connect apps: fetch instance, update, delete, retrieve list 29 | - Handle incoming phone numbers: update, fetch, delete, list, purchase 30 | - Manage add-ons, keys, and media resources 31 | - Handle messages: send, retrieve list, delete, fetch, update, create feedback 32 | - Manage signing keys and notifications 33 | - Handle outgoing caller IDs: fetch instance, update, delete, retrieve list 34 | - Manage participants in a conference: fetch instance, update properties, kick, create, retrieve list 35 | - Handle payments and queues: create session, update, remove empty queue, retrieve list 36 | - Manage recordings: fetch instance, delete, retrieve list 37 | - Handle add-on results and payloads: fetch instance, delete, retrieve list 38 | - Manage recording transcriptions: fetch, delete, list 39 | - Handle phone number SafeList: add, check, remove 40 | - Manage short codes: fetch instance, update, retrieve list 41 | - Manage credential list mappings and IP Access Control Lists 42 | - Handle domains: create, fetch instance, update attributes, delete 43 | - Manage usage records and triggers: fetch instance, update, delete, create, retrieve list 44 | - Manage user-defined messages: create, subscribe, delete subscription 45 | 46 | ### Changed 47 | - getAccountDetails() changed to fetchAccount() 48 | - sendSms() changed to createMessage() 49 | - getMessage() changed to fetchMessage() 50 | - sendWhatsAppMessage() available under createMessage() with channel type as whatsapp 51 | - makeVoiceCall() changed to createCall() -------------------------------------------------------------------------------- /ballerina/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import org.apache.tools.ant.taskdefs.condition.Os 20 | 21 | plugins { 22 | id 'io.ballerina.plugin' 23 | } 24 | 25 | description = 'Twilio - Ballerina' 26 | 27 | def packageName = "twilio" 28 | def packageOrg = "ballerinax" 29 | def tomlVersion = stripBallerinaExtensionVersion("${project.version}") 30 | def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml") 31 | def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml") 32 | 33 | def stripBallerinaExtensionVersion(String extVersion) { 34 | if (extVersion.matches(project.ext.timestampedVersionRegex)) { 35 | def splitVersion = extVersion.split('-') 36 | if (splitVersion.length > 3) { 37 | def strippedValues = splitVersion[0..-4] 38 | return strippedValues.join('-') 39 | } else { 40 | return extVersion 41 | } 42 | } else { 43 | return extVersion.replace("${project.ext.snapshotVersion}", "") 44 | } 45 | } 46 | 47 | ballerina { 48 | packageOrganization = packageOrg 49 | module = packageName 50 | testCoverageParam = "--code-coverage --coverage-format=xml --excludes=\"modules/**/**\"" 51 | isConnector = true 52 | platform = "any" 53 | } 54 | 55 | task updateTomlFiles { 56 | doLast { 57 | def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version) 58 | newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion) 59 | ballerinaTomlFile.text = newBallerinaToml 60 | } 61 | } 62 | 63 | task commitTomlFiles { 64 | doLast { 65 | project.exec { 66 | ignoreExitValue true 67 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 68 | commandLine 'cmd', '/c', "git commit -m \"[Automated] Update the toml files\" Ballerina.toml Dependencies.toml" 69 | } else { 70 | commandLine 'sh', '-c', "git commit -m '[Automated] Update the toml files' Ballerina.toml Dependencies.toml" 71 | } 72 | } 73 | } 74 | } 75 | 76 | clean { 77 | delete 'build' 78 | } 79 | 80 | publishToMavenLocal.dependsOn build 81 | publish.dependsOn build 82 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /ballerina/tests/README.md: -------------------------------------------------------------------------------- 1 | # Running Tests 2 | 3 | There are two test environments for the Twilio connector. The default test environment is the mock server for Twilio API. The other test environment is the actual Twilio API. You can run the tests in either of these environments and each has its own compatible set of tests. 4 | 5 | Test Groups | Environment 6 | ---| --- 7 | mock_tests | Mock server for Twilio API (Defualt Environment) 8 | live_tests | Twilio API 9 | 10 | ## Running Tests in the Mock Server 11 | 12 | To execute the tests on the mock server, ensure that the `IS_TEST_ON_LIVE_SERVER` environment variable is either set to false or unset before initiating the tests. This environment variable can be configured within the `Config.toml` file located in the tests directory or specified as an environmental variable. 13 | 14 | #### Using a Config.toml File 15 | 16 | Create a `Config.toml` file in the tests directory and add your authentication credentials and phone number for the authorized user: 17 | 18 | ```toml 19 | isTestOnLiveServer = false 20 | ``` 21 | 22 | #### Using Environment Variables 23 | 24 | Alternatively, you can set your authentication credentials as environment variables: 25 | ```bash 26 | export IS_TEST_ON_LIVE_SERVER=false 27 | ``` 28 | 29 | Then, run the following command to run the tests: 30 | ```bash 31 | ./gradlew clean test 32 | ``` 33 | 34 | ## Running Tests Against Twilio API 35 | 36 | ### Prerequisites 37 | 38 | To run the tests, you need Twilio account credentials, a Twilio phone number and a test phone number. To get Twilio account credentials and Twilio phone number; 39 | 40 | 1. Create a [Twilio account](https://www.twilio.com/). 41 | 42 | 2. Obtain a [Twilio phone number](https://support.twilio.com/hc/en-us/articles/223136107-How-does-Twilio-s-Free-Trial-work-). 43 | 44 | > **Tip:** If you are using a trial account, you may need to verify your recipients' phone numbers before initiating any communication with them. 45 | 46 | 3. Obtain a [Twilio Account Auth Token](https://support.twilio.com/hc/en-us/articles/223136027-Auth-Tokens-and-How-to-Change-Them). 47 | 48 | Now, you can set Twilio credentials and phone numbers either in a `Config.toml` file in the tests directory or as environment variables. 49 | 50 | #### Using a Config.toml File 51 | 52 | Create a `Config.toml` file in the tests directory and add your authentication credentials and phone number for the authorized user: 53 | 54 | ```toml 55 | isTestOnLiveServer = true 56 | accountSid="" 57 | authToken="" 58 | toPhoneNumber="" 59 | fromPhoneNumber="" 60 | apiKey="" 61 | apiSecret="" 62 | ``` 63 | 64 | #### Using Environment Variables 65 | 66 | Alternatively, you can set your authentication credentials as environment variables: 67 | ```bash 68 | export IS_TEST_ON_LIVE_SERVER=true 69 | export ACCOUNT_SID="" 70 | export AUTH_TOKEN="" 71 | export TO_PHONE="" 72 | export TWILIO_PHONE="" 73 | export API_KEY="" 74 | export API_SECRET="" 75 | ``` 76 | 77 | Then, run the following command to run the tests: 78 | ```bash 79 | ./gradlew clean test -Pgroups="live_tests" 80 | ``` 81 | -------------------------------------------------------------------------------- /docs/proposals/api_key_auth_support.md: -------------------------------------------------------------------------------- 1 | # Proposal: Add API Key Based Authentication Support for Twilio Connector 2 | 3 | _Owners_: @SachinAkash01 4 | _Reviewers_: @ayeshLK @NipunaRanasinghe 5 | _Created_: 2024/11/07 6 | _Updated_: 2024/11/07 7 | _Issue_: [#7343](https://github.com/ballerina-platform/ballerina-library/issues/7343) 8 | 9 | ## Summary 10 | Implement the capabilities to support API Key based authentication for the Ballerina Twilio Connector. 11 | 12 | ## Goals 13 | - Enhance the Ballerina Twilio Connector by adding support for API Key based authentication for client validation. 14 | 15 | ## Motivation 16 | In the current Ballerina Twilio connector (version 4.x.x), only Auth Token-based authentication is supported, which grants full access to the associated Twilio account. While this is sufficient for local testing or low-risk scenarios, it poses significant security challenges in production environments. Auth Tokens allow any client with access to interact with the entire Twilio account, including sensitive resources and data, exposing a risk of unauthorized access if credentials are compromised. 17 | 18 | API Key-based authentication provides a robust alternative by enabling finer-grained control over access permissions. Twilio’s API Key authentication allows developers to issue and manage multiple keys with tailored scopes, specific to certain applications or functionalities. API Keys can be rotated, revoked, or regenerated without impacting the overall account integrity, thereby reducing downtime in the event of a compromise and allowing for quicker incident response. 19 | 20 | By implementing API Key-based authentication in the Ballerina Twilio connector, we can offer developers a more flexible and secure mechanism for managing Twilio API interactions. This approach aligns with industry best practices, improving security posture and minimizing the risks associated with broad-scope credentials in production environments. 21 | 22 | ## Description 23 | In the current approach (Auth Token based authentication) of the Ballerina Twilio connector requires an `accountSid`and `authToken`, which grants full access to the Twilio account. To improve security and offer more granular control over access, this proposal introduces support for API Key-based authentication. API Key-based authentication allows developers to use an `apiKey`, `apiSecret`, and `accountSid` limiting access to specific resources and allowing for easier key management 24 | 25 | ### Enhanced ConnectionConfig Structure: 26 | - The `ConnectionConfig` type will be modified to support both authentication mechanisms. The `auth` field will be accepting either `AuthTokenConfig` or `ApiKeyConfig` allowing the user to specify their preferred authentication method. 27 | 28 | ```ballerina 29 | @display {label: "Connection Config"} 30 | public type ConnectionConfig record {| 31 | AuthTokenConfig|ApiKeyConfig auth; 32 | //other fields 33 | |}; 34 | ``` 35 | 36 | - Two distinct records `AuthTokenConfig` and `ApiKeyConfig`, define the required fields for each authentication type. 37 | 38 | ```ballerina 39 | public type AuthTokenConfig record {| 40 | string accountSid; 41 | string authToken; 42 | |}; 43 | 44 | public type ApiKeyConfig record {| 45 | string accountSid; 46 | string apiKey; 47 | string apiSecret; 48 | |}; 49 | ``` 50 | 51 | - This approach improves security and flexibility, allowing granular control over Twilio account access without exposing the full account credentials in production settings. 52 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This directory contains a collection of sample code examples written in Ballerina, demonstrating various use cases of the module. The examples are categorized into three groups based on the functionality they illustrate. 4 | 5 | 1. Account management 6 | - [Create a sub-account](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/accounts/create-sub-account) - Create a subaccount under a Twilio account 7 | - [Fetch an account](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/accounts/fetch-account) - Get details of a Twilio account 8 | - [Fetch balance](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/accounts/fetch-balance) - Get the balance of a Twilio account 9 | - [List accounts](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/accounts/list-accounts) - List all subaccounts under a Twilio account 10 | - [Update an account](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/accounts/update-account) - Update the name of a Twilio account 11 | 2. Call management 12 | - [Make a call](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/calls/create-call) - Make a call to a phone number via a Twilio 13 | - [Fetch call log](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/calls/fetch-call-log) - Get details of a call made via a Twilio 14 | - [List call logs](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/calls/list-call-logs) - Get details of all calls made via a Twilio 15 | - [Delete a call log](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/calls/delete-call-log) - Delete the log of a call made via Twilio 16 | 3. Message management 17 | - [Send an SMS message](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/messages/create-sms-message) - Send an SMS to a phone number via a Twilio 18 | - [Send a Whatsapp message](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/messages/create-whatsapp-message) - Send a Whatsapp message to a phone number via a Twilio 19 | - [List message logs](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/messages/list-message-logs) - Get details of all messages sent via a Twilio 20 | - [Fetch a message log](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/messages/fetch-message-log) - Get details of a message sent via a Twilio 21 | - [Delete a message log](https://github.com/RDPerera/module-ballerinax-twilio/tree/master/examples/messages/delete-message-log) - Delete a message log via a Twilio 22 | 23 | ## Running an Example 24 | 25 | Execute the following commands to build an example from the source. 26 | 27 | * To build an example 28 | 29 | `bal build ` 30 | 31 | 32 | * To run an example 33 | 34 | `bal run ` 35 | 36 | ## Building the Examples with the Local Module 37 | 38 | **Warning**: Because of the absence of support for reading local repositories for single Ballerina files, the bala of 39 | the module is manually written to the central repository as a workaround. Consequently, the bash script may modify your 40 | local Ballerina repositories. 41 | 42 | Execute the following commands to build all the examples against the changes you have made to the module locally. 43 | 44 | * To build all the examples 45 | 46 | `./build.sh build` 47 | 48 | 49 | * To run all the examples 50 | 51 | `./build.sh run` -------------------------------------------------------------------------------- /examples/accounts/create-sub-account/Create sub account.md: -------------------------------------------------------------------------------- 1 | # Create sub account in Twilio 2 | 3 | This example demonstrates how to create a sub account under your Twilio account using Ballerina. 4 | 5 | ## Prerequisites 6 | 7 | Before using the ballerinax-twilio connector you must have access to Twilio API, If you do not have access to Twilio API please complete the following steps: 8 | 9 | ### Step 1: Create a Twilio account 10 | 11 | Creating a Twilio account can be done by visiting [Twilio](https://www.twilio.com) and clicking the "Try Twilio for Free" button. 12 | 13 | ### Step 2: Obtain a Twilio phone number 14 | 15 | All trial projects can provision a free trial phone number for testing. Here's how to get started. 16 | 17 | > **Notice:** Trial project phone number selection may be limited. You must upgrade your Twilio project to provision more than one phone number, or to provision a number that is not available to trial projects. 18 | 19 | 1. Access the Buy a Number page in the Console. 20 | 21 | ![Get Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-phone-number.png) 22 | 23 | 2. Enter the criteria for the phone number you need, and then click Search. 24 | 25 | ![Configure Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/phone-number-config.png) 26 | 27 | - Country: Select the desired country from the drop-down menu. 28 | - Number or Location: Select the desired option to search by digits/phrases, or a specific City or Region. 29 | - Capabilities: Select your service needs for this number. 30 | 31 | 3. Click Buy to purchase a phone number for your current project or sub-account. 32 | 33 | ![Search Results](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/search-phone-number.png) 34 | > **Notice:** Many countries require identity documentation for Phone Number compliance. Requests to provision phone numbers with these regulations will be required to select or add the required documentation after clicking Buy in Console. To see which countries and phone number types are affected by these requirements, please see twilio's [Phone Number Regulations](https://www.twilio.com/guidelines/regulatory) site. 35 | 36 | ### Step 3: Obtain a Twilio account Sid with auth token 37 | 38 | Twilio uses Account SID and the Auth Token to determine which account an API request is coming from: You can find your account Sid and auth token in your [Twilio console](https://www.twilio.com/console). 39 | 40 | ![Twilio Credentials](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-credentails.png) 41 | 42 | Your account's Auth Token is hidden by default. Click show to display the token, and hide to conceal it again. For further information click [here](https://support.twilio.com/hc/en-us/articles/223136027-Auth-Tokens-and-How-to-Change-Them) 43 | 44 | ## Quickstart 45 | 46 | ### Configuration 47 | 48 | Configure Twilio API credentials in Config.toml in the example directory: 49 | 50 | ```toml 51 | accountSid="" 52 | authToken="" 53 | ``` 54 | 55 | To use the `twilio` connector in your Ballerina application, modify the `.bal` file as follows: 56 | 57 | ### Step 1 - Import the module 58 | 59 | Import the Twilio module into your Ballerina program as shown below: 60 | 61 | ```ballerina 62 | import ballerinax/twilio; 63 | ``` 64 | 65 | ### Step 2 - Create a new connector instance 66 | 67 | To create a new connector instance, add a configuration as follows (You can use [configurable variables](https://ballerina.io/learn/by-example/configurable.html) to provide the necessary credentials): 68 | 69 | ```ballerina 70 | configurable string accountSid = ?; 71 | configurable string authToken = ?; 72 | 73 | twilio:ConnectionConfig twilioConfig = { 74 | auth: { 75 | accountSid, 76 | authToken 77 | } 78 | }; 79 | 80 | twilio:Client twilio = check new (twilioConfig); 81 | ``` 82 | 83 | ### Step 3 - Invoke the connector operation 84 | 85 | Invoke the sending SMS operation using the client as shown below: 86 | 87 | ```ballerina 88 | public function main() returns error? { 89 | twilio:Client twilio = check new (twilioConfig); 90 | 91 | twilio:CreateAccountRequest subAccountReqest = { 92 | FriendlyName: "Sample Sub Account" 93 | }; 94 | 95 | twilio:Account subAccountInfo = check twilio->createAccount(subAccountReqest); 96 | io:println(subAccountInfo.toString()); 97 | } 98 | ``` 99 | 100 | ## Run the Example 101 | 102 | Execute the following command to run the example: 103 | 104 | ```bash 105 | bal run 106 | ``` -------------------------------------------------------------------------------- /examples/calls/create-call/Create call.md: -------------------------------------------------------------------------------- 1 | # Make a call using Twilio 2 | 3 | This example demonstrates how to make a call using Twilio connector. 4 | 5 | ## Prerequisites 6 | 7 | Before using the ballerinax-twilio connector you must have access to Twilio API, If you do not have access to Twilio API please complete the following steps: 8 | 9 | ### Step 1: Create a Twilio account 10 | 11 | Creating a Twilio account can be done by visiting [Twilio](https://www.twilio.com) and clicking the "Try Twilio for Free" button. 12 | 13 | ### Step 2: Obtain a Twilio phone number 14 | 15 | All trial projects can provision a free trial phone number for testing. Here's how to get started. 16 | 17 | > **Notice:** Trial project phone number selection may be limited. You must upgrade your Twilio project to provision more than one phone number, or to provision a number that is not available to trial projects. 18 | 19 | 1. Access the Buy a Number page in the Console. 20 | 21 | ![Get Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-phone-number.png) 22 | 23 | 2. Enter the criteria for the phone number you need, and then click Search. 24 | 25 | ![Configure Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/phone-number-config.png) 26 | 27 | - Country: Select the desired country from the drop-down menu. 28 | - Number or Location: Select the desired option to search by digits/phrases, or a specific City or Region. 29 | - Capabilities: Select your service needs for this number. 30 | 31 | 3. Click Buy to purchase a phone number for your current project or sub-account. 32 | 33 | ![Search Results](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/search-phone-number.png) 34 | > **Notice:** Many countries require identity documentation for Phone Number compliance. Requests to provision phone numbers with these regulations will be required to select or add the required documentation after clicking Buy in Console. To see which countries and phone number types are affected by these requirements, please see twilio's [Phone Number Regulations](https://www.twilio.com/guidelines/regulatory) site. 35 | 36 | ### Step 3: Obtain a Twilio account Sid with auth token 37 | 38 | Twilio uses Account SID and the Auth Token to determine which account an API request is coming from: You can find your account Sid and auth token in your [Twilio console](https://www.twilio.com/console). 39 | 40 | ![Twilio Credentials](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-credentails.png) 41 | 42 | Your account's Auth Token is hidden by default. Click show to display the token, and hide to conceal it again. For further information click [here](https://support.twilio.com/hc/en-us/articles/223136027-Auth-Tokens-and-How-to-Change-Them) 43 | 44 | ## Quickstart 45 | 46 | ### Configuration 47 | 48 | Configure Twilio API credentials in Config.toml in the example directory: 49 | 50 | ```toml 51 | accountSid="" 52 | authToken="" 53 | ``` 54 | 55 | To use the `twilio` connector in your Ballerina application, modify the `.bal` file as follows: 56 | 57 | ### Step 1 - Import the module 58 | 59 | Import the Twilio module into your Ballerina program as shown below: 60 | 61 | ```ballerina 62 | import ballerinax/twilio; 63 | ``` 64 | 65 | ### Step 2 - Create a new connector instance 66 | 67 | To create a new connector instance, add a configuration as follows (You can use [configurable variables](https://ballerina.io/learn/by-example/configurable.html) to provide the necessary credentials): 68 | 69 | ```ballerina 70 | configurable string accountSid = ?; 71 | configurable string authToken = ?; 72 | 73 | twilio:ConnectionConfig twilioConfig = { 74 | auth: { 75 | accountSid, 76 | authToken 77 | } 78 | }; 79 | 80 | twilio:Client twilio = check new (twilioConfig); 81 | ``` 82 | 83 | ### Step 3 - Invoke the connector operation 84 | 85 | Invoke the sending SMS operation using the client as shown below: 86 | 87 | ```ballerina 88 | public function main() returns error? { 89 | twilio:Client twilio = check new (twilioConfig); 90 | 91 | twilio:CreateCallRequest callRequest = { 92 | To: "+XXXXXXXXXXX", 93 | From: "+XXXXXXXXXXX", 94 | Url: "http://demo.twilio.com/docs/voice.xml" 95 | }; 96 | 97 | twilio:Call response = check twilio->createCall(callRequest); 98 | io:println("Call Status: ",response?.status); 99 | } 100 | ``` 101 | 102 | ## Run the Example 103 | 104 | Execute the following command to run the example: 105 | 106 | ```bash 107 | bal run 108 | ``` -------------------------------------------------------------------------------- /examples/messages/create-sms-message/Create SMS Message.md: -------------------------------------------------------------------------------- 1 | # Send SMS Message 2 | 3 | This example demonstrates how to send an SMS message using Twilio connector. 4 | 5 | ## Prerequisites 6 | 7 | Before using the ballerinax-twilio connector you must have access to Twilio API, If you do not have access to Twilio API please complete the following steps: 8 | 9 | ### Step 1: Create a Twilio account 10 | 11 | Creating a Twilio account can be done by visiting [Twilio](https://www.twilio.com) and clicking the "Try Twilio for Free" button. 12 | 13 | ### Step 2: Obtain a Twilio phone number 14 | 15 | All trial projects can provision a free trial phone number for testing. Here's how to get started. 16 | 17 | > **Notice:** Trial project phone number selection may be limited. You must upgrade your Twilio project to provision more than one phone number, or to provision a number that is not available to trial projects. 18 | 19 | 1. Access the Buy a Number page in the Console. 20 | 21 | ![Get Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-phone-number.png) 22 | 23 | 2. Enter the criteria for the phone number you need, and then click Search. 24 | 25 | ![Configure Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/phone-number-config.png) 26 | 27 | - Country: Select the desired country from the drop-down menu. 28 | - Number or Location: Select the desired option to search by digits/phrases, or a specific City or Region. 29 | - Capabilities: Select your service needs for this number. 30 | 31 | 3. Click Buy to purchase a phone number for your current project or sub-account. 32 | 33 | ![Search Results](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/search-phone-number.png) 34 | > **Notice:** Many countries require identity documentation for Phone Number compliance. Requests to provision phone numbers with these regulations will be required to select or add the required documentation after clicking Buy in Console. To see which countries and phone number types are affected by these requirements, please see twilio's [Phone Number Regulations](https://www.twilio.com/guidelines/regulatory) site. 35 | 36 | ### Step 3: Obtain a Twilio account Sid with auth token 37 | 38 | Twilio uses Account SID and the Auth Token to determine which account an API request is coming from: You can find your account Sid and auth token in your [Twilio console](https://www.twilio.com/console). 39 | 40 | ![Twilio Credentials](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-credentails.png) 41 | 42 | Your account's Auth Token is hidden by default. Click show to display the token, and hide to conceal it again. For further information click [here](https://support.twilio.com/hc/en-us/articles/223136027-Auth-Tokens-and-How-to-Change-Them) 43 | 44 | ## Quickstart 45 | 46 | ### Configuration 47 | 48 | Configure Twilio API credentials in Config.toml in the example directory: 49 | 50 | ```toml 51 | accountSid="" 52 | authToken="" 53 | ``` 54 | 55 | To use the `twilio` connector in your Ballerina application, modify the `.bal` file as follows: 56 | 57 | ### Step 1 - Import the module 58 | 59 | Import the Twilio module into your Ballerina program as shown below: 60 | 61 | ```ballerina 62 | import ballerinax/twilio; 63 | ``` 64 | 65 | ### Step 2 - Create a new connector instance 66 | 67 | To create a new connector instance, add a configuration as follows (You can use [configurable variables](https://ballerina.io/learn/by-example/configurable.html) to provide the necessary credentials): 68 | 69 | ```ballerina 70 | configurable string accountSid = ?; 71 | configurable string authToken = ?; 72 | 73 | twilio:ConnectionConfig twilioConfig = { 74 | auth: { 75 | accountSid, 76 | authToken 77 | } 78 | }; 79 | 80 | twilio:Client twilio = check new (twilioConfig); 81 | ``` 82 | 83 | ### Step 3 - Invoke the connector operation 84 | 85 | Invoke the sending SMS operation using the client as shown below: 86 | 87 | ```ballerina 88 | public function main() returns error? { 89 | twilio:CreateMessageRequest messageRequest = { 90 | To: "+XXXXXXXXXXX", // Phone number that you want to send the message to 91 | From: "+XXXXXXXXXXX", // Twilio phone number 92 | Body: "Hello from Ballerina" 93 | }; 94 | 95 | twilio:Message response = check twilio->createMessage(messageRequest); 96 | 97 | // Print the status of the message from the response 98 | io:println("Message Status: ", response?.status); 99 | } 100 | ``` 101 | 102 | ## Run the Example 103 | 104 | Execute the following command to run the example: 105 | 106 | ```bash 107 | bal run 108 | ``` -------------------------------------------------------------------------------- /docs/spec/sanitizations.md: -------------------------------------------------------------------------------- 1 | # Sanitations: Ballerina Twilio Connector 2 | 3 | _Authors_: @RDPerera \ 4 | _Reviewers_: @NipunaRanasinghe \ 5 | _Created_: 2024/02/14 \ 6 | _Updated_: 2024/02/14 \ 7 | _Edition_: Swan Lake 8 | 9 | This document lists the sanitations applied to the OpenAPI specification and the generated client for the Twilio connector. 10 | 11 | ## Sanitations for the OpenAPI specification 12 | 13 | This connector is generated using Twilio's Basic [API version 2010-04-01](https://github.com/twilio/twilio-oai/blob/main/spec/yaml/twilio_api_v2010.yaml), and the following sanitations were applied to the specification before client generation. 14 | 15 | 1. Removed the `api.v2010.account.` and `api.v2010.` suffixes from the record names to enhance the user-friendliness of the specifications. For instance, `api.v2010.account.address` is now renamed to `address`, resulting in the type name changing from `ApiV2010AccountAddress` to `Address`. 16 | 17 | 2. Excluded `available_phone_number_country` from `available_phone_number_country.available_phone_number_toll_free` to prevent an OpenAPI tool reference handling error ([`Ballerina only supports local references.`](https://github.com/ballerina-platform/ballerina-library/issues/4887)). This change also improves the clarity of the record names. 18 | 19 | 3. Modified parameter names in response to [this issue](https://github.com/ballerina-platform/ballerina-library/issues/4882). 20 | 21 | - `startTime<` changed to `startedOnOrBefore` 22 | - `startTime>` changed to `startedOnOrAfter` 23 | - `endTime<` changed to `endedOnOrBefore` 24 | - `endTime>` changed to `endedOnOrAfter` 25 | - `messageDate<` changed to `loggedOnOrBefore` 26 | - `messageDate>` changed to `loggedOnOrAfter` 27 | - `dateCreated<` changed to `createdOnOrBefore` 28 | - `dateCreated>` changed to `createdOnOrAfter` 29 | - `dateUpdated<` changed to `updatedOnOrBefore` 30 | - `dateUpdated>` changed to `updatedOnOrAfter` 31 | - `dateSent<` changed to `sentOnOrBefore` 32 | - `dateSent>` changed to `sentOnOrAfter` 33 | 34 | 4. Add missing payload documentation for the following functions. 35 | - createAccount 36 | - updateAccount 37 | - createAddress 38 | - updateAddress 39 | - createApplication 40 | - updateApplication 41 | - createCall 42 | - updateCall 43 | - updateCallFeedback 44 | - createCallFeedbackSummary 45 | - createCallRecording 46 | - updateCallRecording 47 | - updateConference 48 | - updateConferenceRecording 49 | - updateConnectApp 50 | - updateIncomingPhoneNumber 51 | - createIncomingPhoneNumber 52 | - createIncomingPhoneNumberAssignedAddOn 53 | - createIncomingPhoneNumberLocal 54 | - createIncomingPhoneNumberMobile 55 | - createIncomingPhoneNumberTollFree 56 | - updateKey 57 | - createNewKey 58 | - updateMember 59 | - createMessage 60 | - updateMessage 61 | - createMessageFeedback 62 | - listSigningKey 63 | - createNewSigningKey 64 | - updateOutgoingCallerId 65 | - createValidationRequest 66 | - updateParticipant 67 | - createParticipant 68 | - createPayments 69 | - updatePayments 70 | - updateQueue 71 | - createQueue 72 | - updateShortCode 73 | - fetchSigningKey 74 | - updateSigningKey 75 | - deleteSigningKey 76 | - createSipAuthCallsCredentialListMapping 77 | - createSipAuthCallsIpAccessControlListMapping 78 | - createSipAuthRegistrationsCredentialListMapping 79 | - createSipCredential 80 | - updateSipCredential 81 | - createSipCredentialList 82 | - updateSipCredentialList 83 | - createSipCredentialListMapping 84 | - createSipDomain 85 | - updateSipDomain 86 | - createSipIpAccessControlList 87 | - updateSipIpAccessControlList 88 | - createSipIpAccessControlListMapping 89 | - createSipIpAddress 90 | - updateSipIpAddress 91 | - createSiprec 92 | - updateSiprec 93 | - createStream 94 | - updateStream 95 | - createToken 96 | - updateUsageTrigger 97 | - createUsageTrigger 98 | - createUserDefinedMessage 99 | - createUserDefinedMessageSubscription 100 | 101 | 5. Add missing functions documentation for following functions. 102 | - createAddress 103 | - fetchAddress 104 | - updateAddress 105 | - deleteAddress 106 | - listAvailablePhoneNumberCountry 107 | - fetchAvailablePhoneNumberCountry 108 | - listAvailablePhoneNumberLocal 109 | - listAvailablePhoneNumberMachineToMachine 110 | - listAvailablePhoneNumberMobile 111 | - listAvailablePhoneNumberNational 112 | - listAvailablePhoneNumberTollFree 113 | - listAvailablePhoneNumberSharedCost 114 | - listAvailablePhoneNumberVoip 115 | - fetchCallNotification 116 | - listCallNotification 117 | - updateConference 118 | - listDependentPhoneNumber 119 | - listIncomingPhoneNumberLocal 120 | - listIncomingPhoneNumberMobile 121 | - listIncomingPhoneNumberTollFree 122 | - fetchKey 123 | - updateKey 124 | - deleteKey 125 | - createNewKey 126 | - listSigningKey 127 | - createValidationRequest 128 | - createParticipant 129 | - fetchRecordingTranscription 130 | - deleteRecordingTranscription 131 | - listRecordingTranscription 132 | - fetchSigningKey 133 | - updateSigningKey 134 | - deleteSigningKey 135 | - listUsageRecordAllTime 136 | - listUsageRecordDaily 137 | - listUsageRecordLastMonth 138 | - listUsageRecordMonthly 139 | - listUsageRecordThisMonth 140 | - listUsageRecordToday 141 | - listUsageRecordYearly 142 | - listUsageRecordYesterday 143 | - deleteUsageTrigger 144 | 145 | 6. Add missing `mms`, `sms`, `voice`,and `fax` parameter documentation for the `capabilities` record. 146 | 147 | ## Sanitations for the generated client 148 | 149 | After generating the client using openAPI specification, the following modifications are made to the generated client by introducing a wrapper client. 150 | 151 | 1. Removed the `string accountSid` parameter from all non-account-related functions and added it as an optional parameter to each function, with the default parameter set to `accountSid` in the initial client configurations. 152 | 153 | For example, the function: 154 | 155 | ```ballerina 156 | remote isolated function createCall(string accountSid, CreateCallRequest payload) returns Call|error { 157 | } 158 | ``` 159 | 160 | is restructured as: 161 | 162 | ```ballerina 163 | remote isolated function createCall(CreateCallRequest payload, string? accountSid = ()) returns Call|error { 164 | return self.generatedClient->createCall(accountSid ?: self.accountSid, payload); 165 | } 166 | ``` -------------------------------------------------------------------------------- /ballerina/Dependencies.toml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED FILE. DO NOT MODIFY. 2 | 3 | # This file is auto-generated by Ballerina for managing dependency versions. 4 | # It should not be modified by hand. 5 | 6 | [ballerina] 7 | dependencies-toml-version = "2" 8 | distribution-version = "2201.10.0" 9 | 10 | [[package]] 11 | org = "ballerina" 12 | name = "auth" 13 | version = "2.12.0" 14 | dependencies = [ 15 | {org = "ballerina", name = "crypto"}, 16 | {org = "ballerina", name = "jballerina.java"}, 17 | {org = "ballerina", name = "lang.array"}, 18 | {org = "ballerina", name = "lang.string"}, 19 | {org = "ballerina", name = "log"} 20 | ] 21 | 22 | [[package]] 23 | org = "ballerina" 24 | name = "cache" 25 | version = "3.8.0" 26 | dependencies = [ 27 | {org = "ballerina", name = "constraint"}, 28 | {org = "ballerina", name = "jballerina.java"}, 29 | {org = "ballerina", name = "task"}, 30 | {org = "ballerina", name = "time"} 31 | ] 32 | 33 | [[package]] 34 | org = "ballerina" 35 | name = "constraint" 36 | version = "1.5.0" 37 | dependencies = [ 38 | {org = "ballerina", name = "jballerina.java"} 39 | ] 40 | modules = [ 41 | {org = "ballerina", packageName = "constraint", moduleName = "constraint"} 42 | ] 43 | 44 | [[package]] 45 | org = "ballerina" 46 | name = "crypto" 47 | version = "2.7.2" 48 | dependencies = [ 49 | {org = "ballerina", name = "jballerina.java"}, 50 | {org = "ballerina", name = "time"} 51 | ] 52 | 53 | [[package]] 54 | org = "ballerina" 55 | name = "file" 56 | version = "1.10.0" 57 | dependencies = [ 58 | {org = "ballerina", name = "io"}, 59 | {org = "ballerina", name = "jballerina.java"}, 60 | {org = "ballerina", name = "os"}, 61 | {org = "ballerina", name = "time"} 62 | ] 63 | 64 | [[package]] 65 | org = "ballerina" 66 | name = "http" 67 | version = "2.12.10" 68 | dependencies = [ 69 | {org = "ballerina", name = "auth"}, 70 | {org = "ballerina", name = "cache"}, 71 | {org = "ballerina", name = "constraint"}, 72 | {org = "ballerina", name = "crypto"}, 73 | {org = "ballerina", name = "file"}, 74 | {org = "ballerina", name = "io"}, 75 | {org = "ballerina", name = "jballerina.java"}, 76 | {org = "ballerina", name = "jwt"}, 77 | {org = "ballerina", name = "lang.array"}, 78 | {org = "ballerina", name = "lang.decimal"}, 79 | {org = "ballerina", name = "lang.int"}, 80 | {org = "ballerina", name = "lang.regexp"}, 81 | {org = "ballerina", name = "lang.runtime"}, 82 | {org = "ballerina", name = "lang.string"}, 83 | {org = "ballerina", name = "lang.value"}, 84 | {org = "ballerina", name = "log"}, 85 | {org = "ballerina", name = "mime"}, 86 | {org = "ballerina", name = "oauth2"}, 87 | {org = "ballerina", name = "observe"}, 88 | {org = "ballerina", name = "time"}, 89 | {org = "ballerina", name = "url"} 90 | ] 91 | modules = [ 92 | {org = "ballerina", packageName = "http", moduleName = "http"}, 93 | {org = "ballerina", packageName = "http", moduleName = "http.httpscerr"} 94 | ] 95 | 96 | [[package]] 97 | org = "ballerina" 98 | name = "io" 99 | version = "1.6.3" 100 | dependencies = [ 101 | {org = "ballerina", name = "jballerina.java"}, 102 | {org = "ballerina", name = "lang.value"} 103 | ] 104 | 105 | [[package]] 106 | org = "ballerina" 107 | name = "jballerina.java" 108 | version = "0.0.0" 109 | 110 | [[package]] 111 | org = "ballerina" 112 | name = "jwt" 113 | version = "2.13.0" 114 | dependencies = [ 115 | {org = "ballerina", name = "cache"}, 116 | {org = "ballerina", name = "crypto"}, 117 | {org = "ballerina", name = "io"}, 118 | {org = "ballerina", name = "jballerina.java"}, 119 | {org = "ballerina", name = "lang.int"}, 120 | {org = "ballerina", name = "lang.string"}, 121 | {org = "ballerina", name = "log"}, 122 | {org = "ballerina", name = "time"} 123 | ] 124 | 125 | [[package]] 126 | org = "ballerina" 127 | name = "lang.__internal" 128 | version = "0.0.0" 129 | dependencies = [ 130 | {org = "ballerina", name = "jballerina.java"}, 131 | {org = "ballerina", name = "lang.object"} 132 | ] 133 | 134 | [[package]] 135 | org = "ballerina" 136 | name = "lang.array" 137 | version = "0.0.0" 138 | dependencies = [ 139 | {org = "ballerina", name = "jballerina.java"}, 140 | {org = "ballerina", name = "lang.__internal"} 141 | ] 142 | 143 | [[package]] 144 | org = "ballerina" 145 | name = "lang.decimal" 146 | version = "0.0.0" 147 | dependencies = [ 148 | {org = "ballerina", name = "jballerina.java"} 149 | ] 150 | 151 | [[package]] 152 | org = "ballerina" 153 | name = "lang.error" 154 | version = "0.0.0" 155 | scope = "testOnly" 156 | dependencies = [ 157 | {org = "ballerina", name = "jballerina.java"} 158 | ] 159 | 160 | [[package]] 161 | org = "ballerina" 162 | name = "lang.int" 163 | version = "0.0.0" 164 | dependencies = [ 165 | {org = "ballerina", name = "jballerina.java"}, 166 | {org = "ballerina", name = "lang.__internal"}, 167 | {org = "ballerina", name = "lang.object"} 168 | ] 169 | 170 | [[package]] 171 | org = "ballerina" 172 | name = "lang.object" 173 | version = "0.0.0" 174 | 175 | [[package]] 176 | org = "ballerina" 177 | name = "lang.regexp" 178 | version = "0.0.0" 179 | dependencies = [ 180 | {org = "ballerina", name = "jballerina.java"} 181 | ] 182 | 183 | [[package]] 184 | org = "ballerina" 185 | name = "lang.runtime" 186 | version = "0.0.0" 187 | dependencies = [ 188 | {org = "ballerina", name = "jballerina.java"} 189 | ] 190 | 191 | [[package]] 192 | org = "ballerina" 193 | name = "lang.string" 194 | version = "0.0.0" 195 | dependencies = [ 196 | {org = "ballerina", name = "jballerina.java"}, 197 | {org = "ballerina", name = "lang.regexp"} 198 | ] 199 | 200 | [[package]] 201 | org = "ballerina" 202 | name = "lang.value" 203 | version = "0.0.0" 204 | dependencies = [ 205 | {org = "ballerina", name = "jballerina.java"} 206 | ] 207 | 208 | [[package]] 209 | org = "ballerina" 210 | name = "log" 211 | version = "2.10.0" 212 | dependencies = [ 213 | {org = "ballerina", name = "io"}, 214 | {org = "ballerina", name = "jballerina.java"}, 215 | {org = "ballerina", name = "lang.value"}, 216 | {org = "ballerina", name = "observe"} 217 | ] 218 | modules = [ 219 | {org = "ballerina", packageName = "log", moduleName = "log"} 220 | ] 221 | 222 | [[package]] 223 | org = "ballerina" 224 | name = "mime" 225 | version = "2.10.1" 226 | dependencies = [ 227 | {org = "ballerina", name = "io"}, 228 | {org = "ballerina", name = "jballerina.java"}, 229 | {org = "ballerina", name = "lang.int"}, 230 | {org = "ballerina", name = "log"} 231 | ] 232 | 233 | [[package]] 234 | org = "ballerina" 235 | name = "oauth2" 236 | version = "2.12.0" 237 | dependencies = [ 238 | {org = "ballerina", name = "cache"}, 239 | {org = "ballerina", name = "crypto"}, 240 | {org = "ballerina", name = "jballerina.java"}, 241 | {org = "ballerina", name = "log"}, 242 | {org = "ballerina", name = "time"}, 243 | {org = "ballerina", name = "url"} 244 | ] 245 | 246 | [[package]] 247 | org = "ballerina" 248 | name = "observe" 249 | version = "1.3.0" 250 | dependencies = [ 251 | {org = "ballerina", name = "jballerina.java"} 252 | ] 253 | 254 | [[package]] 255 | org = "ballerina" 256 | name = "os" 257 | version = "1.8.0" 258 | dependencies = [ 259 | {org = "ballerina", name = "io"}, 260 | {org = "ballerina", name = "jballerina.java"} 261 | ] 262 | modules = [ 263 | {org = "ballerina", packageName = "os", moduleName = "os"} 264 | ] 265 | 266 | [[package]] 267 | org = "ballerina" 268 | name = "task" 269 | version = "2.5.0" 270 | dependencies = [ 271 | {org = "ballerina", name = "jballerina.java"}, 272 | {org = "ballerina", name = "time"} 273 | ] 274 | 275 | [[package]] 276 | org = "ballerina" 277 | name = "test" 278 | version = "0.0.0" 279 | scope = "testOnly" 280 | dependencies = [ 281 | {org = "ballerina", name = "jballerina.java"}, 282 | {org = "ballerina", name = "lang.array"}, 283 | {org = "ballerina", name = "lang.error"} 284 | ] 285 | modules = [ 286 | {org = "ballerina", packageName = "test", moduleName = "test"} 287 | ] 288 | 289 | [[package]] 290 | org = "ballerina" 291 | name = "time" 292 | version = "2.5.0" 293 | dependencies = [ 294 | {org = "ballerina", name = "jballerina.java"} 295 | ] 296 | 297 | [[package]] 298 | org = "ballerina" 299 | name = "url" 300 | version = "2.4.0" 301 | dependencies = [ 302 | {org = "ballerina", name = "jballerina.java"} 303 | ] 304 | modules = [ 305 | {org = "ballerina", packageName = "url", moduleName = "url"} 306 | ] 307 | 308 | [[package]] 309 | org = "ballerinai" 310 | name = "observe" 311 | version = "0.0.0" 312 | dependencies = [ 313 | {org = "ballerina", name = "jballerina.java"}, 314 | {org = "ballerina", name = "observe"} 315 | ] 316 | modules = [ 317 | {org = "ballerinai", packageName = "observe", moduleName = "observe"} 318 | ] 319 | 320 | [[package]] 321 | org = "ballerinax" 322 | name = "twilio" 323 | version = "5.0.1" 324 | dependencies = [ 325 | {org = "ballerina", name = "constraint"}, 326 | {org = "ballerina", name = "http"}, 327 | {org = "ballerina", name = "log"}, 328 | {org = "ballerina", name = "os"}, 329 | {org = "ballerina", name = "test"}, 330 | {org = "ballerina", name = "url"}, 331 | {org = "ballerinai", name = "observe"} 332 | ] 333 | modules = [ 334 | {org = "ballerinax", packageName = "twilio", moduleName = "twilio"}, 335 | {org = "ballerinax", packageName = "twilio", moduleName = "twilio.mock"}, 336 | {org = "ballerinax", packageName = "twilio", moduleName = "twilio.oas"} 337 | ] 338 | 339 | -------------------------------------------------------------------------------- /ballerina/Module.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | Twilio is a cloud communications platform that allows software developers to programmatically make and receive phone calls, send and receive text messages, and perform other communication functions using its web service APIs. 4 | 5 | The Ballerina Twilio connector supports the [Twilio Basic API version 2010-04-01](https://www.twilio.com/docs/iam/api), enabling users to leverage these communication capabilities within their Ballerina applications. 6 | 7 | ## Setup guide 8 | 9 | Before using the ballerinax-twilio connector you must have access to Twilio API, If you do not have access to Twilio API please complete the following steps: 10 | 11 | ### Step 1: Create a Twilio account 12 | 13 | Creating a Twilio account can be done by visiting [Twilio](https://www.twilio.com) and clicking the "Try Twilio for Free" button. 14 | 15 | ### Step 2: Obtain a Twilio phone number 16 | 17 | All trial projects can provision a free trial phone number for testing. Here's how to get started. 18 | 19 | > **Notice:** Trial project phone number selection may be limited. You must upgrade your Twilio project to provision more than one phone number, or to provision a number that is not available to trial projects. 20 | 21 | 1. Access the Buy a Number page in the Console. 22 | 23 | ![Get Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-phone-number.png) 24 | 25 | 2. Enter the criteria for the phone number you need, and then click Search. 26 | 27 | ![Configure Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/phone-number-config.png) 28 | 29 | - Country: Select the desired country from the drop-down menu. 30 | - Number or Location: Select the desired option to search by digits/phrases, or a specific City or Region. 31 | - Capabilities: Select your service needs for this number. 32 | 33 | 3. Click Buy to purchase a phone number for your current project or sub-account. 34 | 35 | ![Search Results](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/search-phone-number.png) 36 | > **Notice:** Many countries require identity documentation for Phone Number compliance. Requests to provision phone numbers with these regulations will be required to select or add the required documentation after clicking Buy in Console. To see which countries and phone number types are affected by these requirements, please see twilio's [Phone Number Regulations](https://www.twilio.com/guidelines/regulatory) site. 37 | 38 | ### Step 3: Obtain a Twilio API Key, API Secret with Account SID 39 | 40 | You can find API Keys related information under [API keys & tokens](https://console.twilio.com/us1/account/keys-credentials/api-keys) section in your Twilio account. If you do not have an API Key and a Secret, please complete the following steps: 41 | 42 | 1. Access the [API keys & tokens](https://console.twilio.com/us1/account/keys-credentials/api-keys) page in your Twilio account, and then click on Create API key. 43 | 44 | ![Twilio API Key](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/api-key-config.png) 45 | 46 | 2. Enter the criteria for the API Key you need, and then click Create. 47 | 48 | ![Create API Key](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/create-api-key.png) 49 | 50 | - Friendly name: Enter a human-readable name for your API key. It helps you identify the key later, especially if you have multiple API keys. 51 | - Region: Enter the geographical region where the API key will be used. 52 | - Key type: There are different types of API keys you can create, 53 | - Standard: Provides access to all Twilio API functionalities except for managing API keys and configuring accounts and subaccounts. 54 | - Main: Offers the same access as standard keys but also allows managing API keys and configuring accounts and subaccounts. 55 | - Restricted: Allows fine-grained access to specific Twilio API resources, enabling you to set permissions for different API endpoints 56 | 57 | 3. Save the API key SID and the Secret in a safe place to use in your application. 58 | 59 | ![API Key Info](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/api-key-info.png) 60 | 61 | > **Important:** This secret is only shown once. Please make note of it and store it in a safe and a secure location. 62 | 63 | 4. In order to obtain the Account SID of your Twilio account, you can visit your [Twilio console](https://www.twilio.com/console). 64 | 65 | ![Twilio Credentials](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-credentails.png) 66 | 67 | ## Quickstart 68 | 69 | To use the `twilio` connector in your Ballerina application, modify the `.bal` file as follows: 70 | 71 | ### Step 1 - Import the module 72 | 73 | Import the Twilio module into your Ballerina program as shown below: 74 | 75 | ```ballerina 76 | import ballerinax/twilio; 77 | ``` 78 | 79 | ### Step 2 - Create a new connector instance 80 | 81 | To create a new connector instance, add a configuration as follows (You can use [configurable variables](https://ballerina.io/learn/by-example/configurable.html) to provide the necessary credentials): 82 | 83 | ```ballerina 84 | configurable string apiKey = ?; 85 | configurable string apiSecret = ?; 86 | configurable string accountSid = ?; 87 | 88 | twilio:ConnectionConfig twilioConfig = { 89 | auth: { 90 | apiKey, 91 | apiSecret, 92 | accountSid 93 | } 94 | }; 95 | 96 | twilio:Client twilio = check new (twilioConfig); 97 | ``` 98 | 99 | ### Step 3 - Invoke the connector operation 100 | 101 | Invoke the sending SMS operation using the client as shown below: 102 | 103 | ```ballerina 104 | public function main() returns error? { 105 | twilio:CreateMessageRequest messageRequest = { 106 | To: "+XXXXXXXXXXX", // Phone number that you want to send the message to 107 | From: "+XXXXXXXXXXX", // Twilio phone number 108 | Body: "Hello from Ballerina" 109 | }; 110 | 111 | twilio:Message response = check twilio->createMessage(messageRequest); 112 | 113 | // Print the status of the message from the response 114 | io:println("Message Status: ", response?.status); 115 | } 116 | ``` 117 | 118 | ### Step 4: Run the Ballerina application 119 | 120 | Execute the command below to execute the Ballerina application: 121 | 122 | ```bash 123 | bal run 124 | ``` 125 | 126 | ## Examples 127 | 128 | The Twilio connector comes equipped with examples that demonstrate its usage across various scenarios. These examples are conveniently organized into three distinct groups based on the functionalities they showcase. For a more hands-on experience and a deeper understanding of these capabilities, we encourage you to experiment with the provided examples in your development environment. 129 | 130 | 1. Account management 131 | - [Create a sub-account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/create-sub-account) - Create a subaccount under a Twilio account 132 | - [Fetch an account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/fetch-account) - Get details of a Twilio account 133 | - [Fetch balance](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/fetch-balance) - Get the balance of a Twilio account 134 | - [List accounts](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/list-accounts) - List all subaccounts under a Twilio account 135 | - [Update an account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/update-account) - Update the name of a Twilio account 136 | 2. Call management 137 | - [Make a call](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/create-call) - Make a call to a phone number via a Twilio 138 | - [Fetch call log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/fetch-call-log) - Get details of a call made via a Twilio 139 | - [List call logs](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/list-call-logs) - Get details of all calls made via a Twilio 140 | - [Delete a call log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/delete-call-log) - Delete the log of a call made via Twilio 141 | 3. Message management 142 | - [Send an SMS message](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/create-sms-message) - Send an SMS to a phone number via a Twilio 143 | - [Send a Whatsapp message](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/create-whatsapp-message) - Send a Whatsapp message to a phone number via a Twilio 144 | - [List message logs](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/list-message-logs) - Get details of all messages sent via a Twilio 145 | - [Fetch a message log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/fetch-message-log) - Get details of a message sent via a Twilio 146 | - [Delete a message log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/delete-message-log) - Delete a message log via a Twilio -------------------------------------------------------------------------------- /ballerina/Package.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | Twilio is a cloud communications platform that allows software developers to programmatically make and receive phone calls, send and receive text messages, and perform other communication functions using its web service APIs. 4 | 5 | The Ballerina Twilio connector supports the [Twilio Basic API version 2010-04-01](https://www.twilio.com/docs/iam/api), enabling users to leverage these communication capabilities within their Ballerina applications. 6 | 7 | ## Setup guide 8 | 9 | Before using the ballerinax-twilio connector you must have access to Twilio API, If you do not have access to Twilio API please complete the following steps: 10 | 11 | ### Step 1: Create a Twilio account 12 | 13 | Creating a Twilio account can be done by visiting [Twilio](https://www.twilio.com) and clicking the "Try Twilio for Free" button. 14 | 15 | ### Step 2: Obtain a Twilio phone number 16 | 17 | All trial projects can provision a free trial phone number for testing. Here's how to get started. 18 | 19 | > **Notice:** Trial project phone number selection may be limited. You must upgrade your Twilio project to provision more than one phone number, or to provision a number that is not available to trial projects. 20 | 21 | 1. Access the Buy a Number page in the Console. 22 | 23 | ![Get Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-phone-number.png) 24 | 25 | 2. Enter the criteria for the phone number you need, and then click Search. 26 | 27 | ![Configure Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/phone-number-config.png) 28 | 29 | - Country: Select the desired country from the drop-down menu. 30 | - Number or Location: Select the desired option to search by digits/phrases, or a specific City or Region. 31 | - Capabilities: Select your service needs for this number. 32 | 33 | 3. Click Buy to purchase a phone number for your current project or sub-account. 34 | 35 | ![Search Results](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/search-phone-number.png) 36 | > **Notice:** Many countries require identity documentation for Phone Number compliance. Requests to provision phone numbers with these regulations will be required to select or add the required documentation after clicking Buy in Console. To see which countries and phone number types are affected by these requirements, please see twilio's [Phone Number Regulations](https://www.twilio.com/guidelines/regulatory) site. 37 | 38 | ### Step 3: Obtain a Twilio API Key, API Secret with Account SID 39 | 40 | You can find API Keys related information under [API keys & tokens](https://console.twilio.com/us1/account/keys-credentials/api-keys) section in your Twilio account. If you do not have an API Key and a Secret, please complete the following steps: 41 | 42 | 1. Access the [API keys & tokens](https://console.twilio.com/us1/account/keys-credentials/api-keys) page in your Twilio account, and then click on Create API key. 43 | 44 | ![Twilio API Key](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/api-key-config.png) 45 | 46 | 2. Enter the criteria for the API Key you need, and then click Create. 47 | 48 | ![Create API Key](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/create-api-key.png) 49 | 50 | - Friendly name: Enter a human-readable name for your API key. It helps you identify the key later, especially if you have multiple API keys. 51 | - Region: Enter the geographical region where the API key will be used. 52 | - Key type: There are different types of API keys you can create, 53 | - Standard: Provides access to all Twilio API functionalities except for managing API keys and configuring accounts and subaccounts. 54 | - Main: Offers the same access as standard keys but also allows managing API keys and configuring accounts and subaccounts. 55 | - Restricted: Allows fine-grained access to specific Twilio API resources, enabling you to set permissions for different API endpoints 56 | 57 | 3. Save the API key SID and the Secret in a safe place to use in your application. 58 | 59 | ![API Key Info](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/api-key-info.png) 60 | 61 | > **Important:** This secret is only shown once. Please make note of it and store it in a safe and a secure location. 62 | 63 | 4. In order to obtain the Account SID of your Twilio account, you can visit your [Twilio console](https://www.twilio.com/console). 64 | 65 | ![Twilio Credentials](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-credentails.png) 66 | 67 | ## Quickstart 68 | 69 | To use the `twilio` connector in your Ballerina application, modify the `.bal` file as follows: 70 | 71 | ### Step 1 - Import the module 72 | 73 | Import the Twilio module into your Ballerina program as shown below: 74 | 75 | ```ballerina 76 | import ballerinax/twilio; 77 | ``` 78 | 79 | ### Step 2 - Create a new connector instance 80 | 81 | To create a new connector instance, add a configuration as follows (You can use [configurable variables](https://ballerina.io/learn/by-example/configurable.html) to provide the necessary credentials): 82 | 83 | ```ballerina 84 | configurable string apiKey = ?; 85 | configurable string apiSecret =? 86 | configurable string accountSid = ?; 87 | 88 | twilio:ConnectionConfig twilioConfig = { 89 | auth: { 90 | apiKey, 91 | apiSecret, 92 | accountSid 93 | } 94 | }; 95 | 96 | twilio:Client twilio = check new (twilioConfig); 97 | ``` 98 | 99 | ### Step 3 - Invoke the connector operation 100 | 101 | Invoke the sending SMS operation using the client as shown below: 102 | 103 | ```ballerina 104 | public function main() returns error? { 105 | twilio:CreateMessageRequest messageRequest = { 106 | To: "+XXXXXXXXXXX", // Phone number that you want to send the message to 107 | From: "+XXXXXXXXXXX", // Twilio phone number 108 | Body: "Hello from Ballerina" 109 | }; 110 | 111 | twilio:Message response = check twilio->createMessage(messageRequest); 112 | 113 | // Print the status of the message from the response 114 | io:println("Message Status: ", response?.status); 115 | } 116 | ``` 117 | 118 | ### Step 4: Run the Ballerina application 119 | 120 | Execute the command below to execute the Ballerina application: 121 | 122 | ```bash 123 | bal run 124 | ``` 125 | 126 | ## Examples 127 | 128 | The Twilio connector comes equipped with examples that demonstrate its usage across various scenarios. These examples are conveniently organized into three distinct groups based on the functionalities they showcase. For a more hands-on experience and a deeper understanding of these capabilities, we encourage you to experiment with the provided examples in your development environment. 129 | 130 | 1. Account management 131 | - [Create a sub-account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/create-sub-account) - Create a subaccount under a Twilio account 132 | - [Fetch an account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/fetch-account) - Get details of a Twilio account 133 | - [Fetch balance](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/fetch-balance) - Get the balance of a Twilio account 134 | - [List accounts](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/list-accounts) - List all subaccounts under a Twilio account 135 | - [Update an account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/update-account) - Update the name of a Twilio account 136 | 2. Call management 137 | - [Make a call](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/create-call) - Make a call to a phone number via a Twilio 138 | - [Fetch call log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/fetch-call-log) - Get details of a call made via a Twilio 139 | - [List call logs](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/list-call-logs) - Get details of all calls made via a Twilio 140 | - [Delete a call log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/delete-call-log) - Delete the log of a call made via Twilio 141 | 3. Message management 142 | - [Send an SMS message](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/create-sms-message) - Send an SMS to a phone number via a Twilio 143 | - [Send a Whatsapp message](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/create-whatsapp-message) - Send a Whatsapp message to a phone number via a Twilio 144 | - [List message logs](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/list-message-logs) - Get details of all messages sent via a Twilio 145 | - [Fetch a message log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/fetch-message-log) - Get details of a message sent via a Twilio 146 | - [Delete a message log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/delete-message-log) - Delete a message log via a Twilio -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /ballerina/utils.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | // AUTO-GENERATED FILE. DO NOT MODIFY. 18 | // This file is auto-generated by the Ballerina OpenAPI tool. 19 | 20 | import ballerina/url; 21 | 22 | type SimpleBasicType string|boolean|int|float|decimal; 23 | 24 | # Represents encoding mechanism details. 25 | type Encoding record { 26 | # Defines how multiple values are delimited 27 | string style = FORM; 28 | # Specifies whether arrays and objects should generate as separate fields 29 | boolean explode = true; 30 | # Specifies the custom content type 31 | string contentType?; 32 | # Specifies the custom headers 33 | map headers?; 34 | }; 35 | 36 | enum EncodingStyle { 37 | DEEPOBJECT, FORM, SPACEDELIMITED, PIPEDELIMITED 38 | } 39 | 40 | final Encoding & readonly defaultEncoding = {}; 41 | 42 | # Generate client request when the media type is given as application/x-www-form-urlencoded. 43 | # 44 | # + encodingMap - Includes the information about the encoding mechanism 45 | # + anyRecord - Record to be serialized 46 | # + return - Serialized request body or query parameter as a string 47 | isolated function createFormURLEncodedRequestBody(record {|anydata...;|} anyRecord, map encodingMap = {}) returns string { 48 | string[] payload = []; 49 | foreach [string, anydata] [key, value] in anyRecord.entries() { 50 | Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; 51 | if value is SimpleBasicType { 52 | payload.push(key, "=", getEncodedUri(value.toString())); 53 | } else if value is SimpleBasicType[] { 54 | payload.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); 55 | } else if (value is record {}) { 56 | if encodingData.style == DEEPOBJECT { 57 | payload.push(getDeepObjectStyleRequest(key, value)); 58 | } else { 59 | payload.push(getFormStyleRequest(key, value)); 60 | } 61 | } else if (value is record {}[]) { 62 | payload.push(getSerializedRecordArray(key, value, encodingData.style, encodingData.explode)); 63 | } 64 | payload.push("&"); 65 | } 66 | _ = payload.pop(); 67 | return string:'join("", ...payload); 68 | } 69 | 70 | # Serialize the record according to the deepObject style. 71 | # 72 | # + parent - Parent record name 73 | # + anyRecord - Record to be serialized 74 | # + return - Serialized record as a string 75 | isolated function getDeepObjectStyleRequest(string parent, record {} anyRecord) returns string { 76 | string[] recordArray = []; 77 | foreach [string, anydata] [key, value] in anyRecord.entries() { 78 | if value is SimpleBasicType { 79 | recordArray.push(parent + "[" + key + "]" + "=" + getEncodedUri(value.toString())); 80 | } else if value is SimpleBasicType[] { 81 | recordArray.push(getSerializedArray(parent + "[" + key + "]" + "[]", value, DEEPOBJECT, true)); 82 | } else if value is record {} { 83 | string nextParent = parent + "[" + key + "]"; 84 | recordArray.push(getDeepObjectStyleRequest(nextParent, value)); 85 | } else if value is record {}[] { 86 | string nextParent = parent + "[" + key + "]"; 87 | recordArray.push(getSerializedRecordArray(nextParent, value, DEEPOBJECT)); 88 | } 89 | recordArray.push("&"); 90 | } 91 | _ = recordArray.pop(); 92 | return string:'join("", ...recordArray); 93 | } 94 | 95 | # Serialize the record according to the form style. 96 | # 97 | # + parent - Parent record name 98 | # + anyRecord - Record to be serialized 99 | # + explode - Specifies whether arrays and objects should generate separate parameters 100 | # + return - Serialized record as a string 101 | isolated function getFormStyleRequest(string parent, record {} anyRecord, boolean explode = true) returns string { 102 | string[] recordArray = []; 103 | if explode { 104 | foreach [string, anydata] [key, value] in anyRecord.entries() { 105 | if (value is SimpleBasicType) { 106 | recordArray.push(key, "=", getEncodedUri(value.toString())); 107 | } else if (value is SimpleBasicType[]) { 108 | recordArray.push(getSerializedArray(key, value, explode = explode)); 109 | } else if (value is record {}) { 110 | recordArray.push(getFormStyleRequest(parent, value, explode)); 111 | } 112 | recordArray.push("&"); 113 | } 114 | _ = recordArray.pop(); 115 | } else { 116 | foreach [string, anydata] [key, value] in anyRecord.entries() { 117 | if (value is SimpleBasicType) { 118 | recordArray.push(key, ",", getEncodedUri(value.toString())); 119 | } else if (value is SimpleBasicType[]) { 120 | recordArray.push(getSerializedArray(key, value, explode = false)); 121 | } else if (value is record {}) { 122 | recordArray.push(getFormStyleRequest(parent, value, explode)); 123 | } 124 | recordArray.push(","); 125 | } 126 | _ = recordArray.pop(); 127 | } 128 | return string:'join("", ...recordArray); 129 | } 130 | 131 | # Serialize arrays. 132 | # 133 | # + arrayName - Name of the field with arrays 134 | # + anyArray - Array to be serialized 135 | # + style - Defines how multiple values are delimited 136 | # + explode - Specifies whether arrays and objects should generate separate parameters 137 | # + return - Serialized array as a string 138 | isolated function getSerializedArray(string arrayName, anydata[] anyArray, string style = "form", boolean explode = true) returns string { 139 | string key = arrayName; 140 | string[] arrayValues = []; 141 | if (anyArray.length() > 0) { 142 | if (style == FORM && !explode) { 143 | arrayValues.push(key, "="); 144 | foreach anydata i in anyArray { 145 | arrayValues.push(getEncodedUri(i.toString()), ","); 146 | } 147 | } else if (style == SPACEDELIMITED && !explode) { 148 | arrayValues.push(key, "="); 149 | foreach anydata i in anyArray { 150 | arrayValues.push(getEncodedUri(i.toString()), "%20"); 151 | } 152 | } else if (style == PIPEDELIMITED && !explode) { 153 | arrayValues.push(key, "="); 154 | foreach anydata i in anyArray { 155 | arrayValues.push(getEncodedUri(i.toString()), "|"); 156 | } 157 | } else if (style == DEEPOBJECT) { 158 | foreach anydata i in anyArray { 159 | arrayValues.push(key, "[]", "=", getEncodedUri(i.toString()), "&"); 160 | } 161 | } else { 162 | foreach anydata i in anyArray { 163 | arrayValues.push(key, "=", getEncodedUri(i.toString()), "&"); 164 | } 165 | } 166 | _ = arrayValues.pop(); 167 | } 168 | return string:'join("", ...arrayValues); 169 | } 170 | 171 | # Serialize the array of records according to the form style. 172 | # 173 | # + parent - Parent record name 174 | # + value - Array of records to be serialized 175 | # + style - Defines how multiple values are delimited 176 | # + explode - Specifies whether arrays and objects should generate separate parameters 177 | # + return - Serialized record as a string 178 | isolated function getSerializedRecordArray(string parent, record {}[] value, string style = FORM, boolean explode = true) returns string { 179 | string[] serializedArray = []; 180 | if style == DEEPOBJECT { 181 | int arayIndex = 0; 182 | foreach var recordItem in value { 183 | serializedArray.push(getDeepObjectStyleRequest(parent + "[" + arayIndex.toString() + "]", recordItem), "&"); 184 | arayIndex = arayIndex + 1; 185 | } 186 | } else { 187 | if (!explode) { 188 | serializedArray.push(parent, "="); 189 | } 190 | foreach var recordItem in value { 191 | serializedArray.push(getFormStyleRequest(parent, recordItem, explode), ","); 192 | } 193 | } 194 | _ = serializedArray.pop(); 195 | return string:'join("", ...serializedArray); 196 | } 197 | 198 | # Get Encoded URI for a given value. 199 | # 200 | # + value - Value to be encoded 201 | # + return - Encoded string 202 | isolated function getEncodedUri(anydata value) returns string { 203 | string|error encoded = url:encode(value.toString(), "UTF8"); 204 | if (encoded is string) { 205 | return encoded; 206 | } else { 207 | return value.toString(); 208 | } 209 | } 210 | 211 | # Generate query path with query parameter. 212 | # 213 | # + queryParam - Query parameter map 214 | # + encodingMap - Details on serialization mechanism 215 | # + return - Returns generated Path or error at failure of client initialization 216 | isolated function getPathForQueryParam(map queryParam, map encodingMap = {}) returns string|error { 217 | string[] param = []; 218 | if (queryParam.length() > 0) { 219 | param.push("?"); 220 | foreach var [key, value] in queryParam.entries() { 221 | if value is () { 222 | _ = queryParam.remove(key); 223 | continue; 224 | } 225 | Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; 226 | if (value is SimpleBasicType) { 227 | param.push(key, "=", getEncodedUri(value.toString())); 228 | } else if (value is SimpleBasicType[]) { 229 | param.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); 230 | } else if (value is record {}) { 231 | if (encodingData.style == DEEPOBJECT) { 232 | param.push(getDeepObjectStyleRequest(key, value)); 233 | } else { 234 | param.push(getFormStyleRequest(key, value, encodingData.explode)); 235 | } 236 | } else { 237 | param.push(key, "=", value.toString()); 238 | } 239 | param.push("&"); 240 | } 241 | _ = param.pop(); 242 | } 243 | string restOfPath = string:'join("", ...param); 244 | return restOfPath; 245 | } 246 | -------------------------------------------------------------------------------- /ballerina/modules/oas/utils.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | // AUTO-GENERATED FILE. DO NOT MODIFY. 18 | // This file is auto-generated by the Ballerina OpenAPI tool. 19 | 20 | import ballerina/url; 21 | 22 | type SimpleBasicType string|boolean|int|float|decimal; 23 | 24 | # Represents encoding mechanism details. 25 | type Encoding record { 26 | # Defines how multiple values are delimited 27 | string style = FORM; 28 | # Specifies whether arrays and objects should generate as separate fields 29 | boolean explode = true; 30 | # Specifies the custom content type 31 | string contentType?; 32 | # Specifies the custom headers 33 | map headers?; 34 | }; 35 | 36 | enum EncodingStyle { 37 | DEEPOBJECT, FORM, SPACEDELIMITED, PIPEDELIMITED 38 | } 39 | 40 | final Encoding & readonly defaultEncoding = {}; 41 | 42 | # Generate client request when the media type is given as application/x-www-form-urlencoded. 43 | # 44 | # + encodingMap - Includes the information about the encoding mechanism 45 | # + anyRecord - Record to be serialized 46 | # + return - Serialized request body or query parameter as a string 47 | isolated function createFormURLEncodedRequestBody(record {|anydata...;|} anyRecord, map encodingMap = {}) returns string { 48 | string[] payload = []; 49 | foreach [string, anydata] [key, value] in anyRecord.entries() { 50 | Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; 51 | if value is SimpleBasicType { 52 | payload.push(key, "=", getEncodedUri(value.toString())); 53 | } else if value is SimpleBasicType[] { 54 | payload.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); 55 | } else if (value is record {}) { 56 | if encodingData.style == DEEPOBJECT { 57 | payload.push(getDeepObjectStyleRequest(key, value)); 58 | } else { 59 | payload.push(getFormStyleRequest(key, value)); 60 | } 61 | } else if (value is record {}[]) { 62 | payload.push(getSerializedRecordArray(key, value, encodingData.style, encodingData.explode)); 63 | } 64 | payload.push("&"); 65 | } 66 | _ = payload.pop(); 67 | return string:'join("", ...payload); 68 | } 69 | 70 | # Serialize the record according to the deepObject style. 71 | # 72 | # + parent - Parent record name 73 | # + anyRecord - Record to be serialized 74 | # + return - Serialized record as a string 75 | isolated function getDeepObjectStyleRequest(string parent, record {} anyRecord) returns string { 76 | string[] recordArray = []; 77 | foreach [string, anydata] [key, value] in anyRecord.entries() { 78 | if value is SimpleBasicType { 79 | recordArray.push(parent + "[" + key + "]" + "=" + getEncodedUri(value.toString())); 80 | } else if value is SimpleBasicType[] { 81 | recordArray.push(getSerializedArray(parent + "[" + key + "]" + "[]", value, DEEPOBJECT, true)); 82 | } else if value is record {} { 83 | string nextParent = parent + "[" + key + "]"; 84 | recordArray.push(getDeepObjectStyleRequest(nextParent, value)); 85 | } else if value is record {}[] { 86 | string nextParent = parent + "[" + key + "]"; 87 | recordArray.push(getSerializedRecordArray(nextParent, value, DEEPOBJECT)); 88 | } 89 | recordArray.push("&"); 90 | } 91 | _ = recordArray.pop(); 92 | return string:'join("", ...recordArray); 93 | } 94 | 95 | # Serialize the record according to the form style. 96 | # 97 | # + parent - Parent record name 98 | # + anyRecord - Record to be serialized 99 | # + explode - Specifies whether arrays and objects should generate separate parameters 100 | # + return - Serialized record as a string 101 | isolated function getFormStyleRequest(string parent, record {} anyRecord, boolean explode = true) returns string { 102 | string[] recordArray = []; 103 | if explode { 104 | foreach [string, anydata] [key, value] in anyRecord.entries() { 105 | if (value is SimpleBasicType) { 106 | recordArray.push(key, "=", getEncodedUri(value.toString())); 107 | } else if (value is SimpleBasicType[]) { 108 | recordArray.push(getSerializedArray(key, value, explode = explode)); 109 | } else if (value is record {}) { 110 | recordArray.push(getFormStyleRequest(parent, value, explode)); 111 | } 112 | recordArray.push("&"); 113 | } 114 | _ = recordArray.pop(); 115 | } else { 116 | foreach [string, anydata] [key, value] in anyRecord.entries() { 117 | if (value is SimpleBasicType) { 118 | recordArray.push(key, ",", getEncodedUri(value.toString())); 119 | } else if (value is SimpleBasicType[]) { 120 | recordArray.push(getSerializedArray(key, value, explode = false)); 121 | } else if (value is record {}) { 122 | recordArray.push(getFormStyleRequest(parent, value, explode)); 123 | } 124 | recordArray.push(","); 125 | } 126 | _ = recordArray.pop(); 127 | } 128 | return string:'join("", ...recordArray); 129 | } 130 | 131 | # Serialize arrays. 132 | # 133 | # + arrayName - Name of the field with arrays 134 | # + anyArray - Array to be serialized 135 | # + style - Defines how multiple values are delimited 136 | # + explode - Specifies whether arrays and objects should generate separate parameters 137 | # + return - Serialized array as a string 138 | isolated function getSerializedArray(string arrayName, anydata[] anyArray, string style = "form", boolean explode = true) returns string { 139 | string key = arrayName; 140 | string[] arrayValues = []; 141 | if (anyArray.length() > 0) { 142 | if (style == FORM && !explode) { 143 | arrayValues.push(key, "="); 144 | foreach anydata i in anyArray { 145 | arrayValues.push(getEncodedUri(i.toString()), ","); 146 | } 147 | } else if (style == SPACEDELIMITED && !explode) { 148 | arrayValues.push(key, "="); 149 | foreach anydata i in anyArray { 150 | arrayValues.push(getEncodedUri(i.toString()), "%20"); 151 | } 152 | } else if (style == PIPEDELIMITED && !explode) { 153 | arrayValues.push(key, "="); 154 | foreach anydata i in anyArray { 155 | arrayValues.push(getEncodedUri(i.toString()), "|"); 156 | } 157 | } else if (style == DEEPOBJECT) { 158 | foreach anydata i in anyArray { 159 | arrayValues.push(key, "[]", "=", getEncodedUri(i.toString()), "&"); 160 | } 161 | } else { 162 | foreach anydata i in anyArray { 163 | arrayValues.push(key, "=", getEncodedUri(i.toString()), "&"); 164 | } 165 | } 166 | _ = arrayValues.pop(); 167 | } 168 | return string:'join("", ...arrayValues); 169 | } 170 | 171 | # Serialize the array of records according to the form style. 172 | # 173 | # + parent - Parent record name 174 | # + value - Array of records to be serialized 175 | # + style - Defines how multiple values are delimited 176 | # + explode - Specifies whether arrays and objects should generate separate parameters 177 | # + return - Serialized record as a string 178 | isolated function getSerializedRecordArray(string parent, record {}[] value, string style = FORM, boolean explode = true) returns string { 179 | string[] serializedArray = []; 180 | if style == DEEPOBJECT { 181 | int arayIndex = 0; 182 | foreach var recordItem in value { 183 | serializedArray.push(getDeepObjectStyleRequest(parent + "[" + arayIndex.toString() + "]", recordItem), "&"); 184 | arayIndex = arayIndex + 1; 185 | } 186 | } else { 187 | if (!explode) { 188 | serializedArray.push(parent, "="); 189 | } 190 | foreach var recordItem in value { 191 | serializedArray.push(getFormStyleRequest(parent, recordItem, explode), ","); 192 | } 193 | } 194 | _ = serializedArray.pop(); 195 | return string:'join("", ...serializedArray); 196 | } 197 | 198 | # Get Encoded URI for a given value. 199 | # 200 | # + value - Value to be encoded 201 | # + return - Encoded string 202 | isolated function getEncodedUri(anydata value) returns string { 203 | string|error encoded = url:encode(value.toString(), "UTF8"); 204 | if (encoded is string) { 205 | return encoded; 206 | } else { 207 | return value.toString(); 208 | } 209 | } 210 | 211 | # Generate query path with query parameter. 212 | # 213 | # + queryParam - Query parameter map 214 | # + encodingMap - Details on serialization mechanism 215 | # + return - Returns generated Path or error at failure of client initialization 216 | isolated function getPathForQueryParam(map queryParam, map encodingMap = {}) returns string|error { 217 | string[] param = []; 218 | if (queryParam.length() > 0) { 219 | param.push("?"); 220 | foreach var [key, value] in queryParam.entries() { 221 | if value is () { 222 | _ = queryParam.remove(key); 223 | continue; 224 | } 225 | Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; 226 | if (value is SimpleBasicType) { 227 | param.push(key, "=", getEncodedUri(value.toString())); 228 | } else if (value is SimpleBasicType[]) { 229 | param.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); 230 | } else if (value is record {}) { 231 | if (encodingData.style == DEEPOBJECT) { 232 | param.push(getDeepObjectStyleRequest(key, value)); 233 | } else { 234 | param.push(getFormStyleRequest(key, value, encodingData.explode)); 235 | } 236 | } else { 237 | param.push(key, "=", value.toString()); 238 | } 239 | param.push("&"); 240 | } 241 | _ = param.pop(); 242 | } 243 | string restOfPath = string:'join("", ...param); 244 | return restOfPath; 245 | } 246 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ballerina Twilio Connector 2 | 3 | [![Build](https://github.com/ballerina-platform/module-ballerinax-twilio/actions/workflows/ci.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-twilio/actions/workflows/ci.yml) 4 | [![GitHub Last Commit](https://img.shields.io/github/last-commit/ballerina-platform/module-ballerinax-twilio.svg)](https://github.com/ballerina-platform/module-ballerinax-twilio/commits/master) 5 | [![GitHub Issues](https://img.shields.io/github/issues/ballerina-platform/ballerina-library/module/twilio.svg?label=Open%20Issues)](https://github.com/ballerina-platform/ballerina-library/labels/module/twilio) 6 | 7 | ## Overview 8 | 9 | Twilio is a cloud communications platform that allows software developers to programmatically make and receive phone calls, send and receive text messages, and perform other communication functions using its web service APIs. 10 | 11 | The Ballerina Twilio connector supports the [Twilio Basic API version 2010-04-01](https://www.twilio.com/docs/iam/api), enabling users to leverage these communication capabilities within their Ballerina applications. 12 | 13 | ## Setup guide 14 | 15 | Before using the ballerinax-twilio connector you must have access to Twilio API, If you do not have access to Twilio API please complete the following steps: 16 | 17 | ### Step 1: Create a Twilio account 18 | 19 | Creating a Twilio account can be done by visiting [Twilio](https://www.twilio.com) and clicking the "Try Twilio for Free" button. 20 | 21 | ### Step 2: Obtain a Twilio phone number 22 | 23 | All trial projects can provision a free trial phone number for testing. Here's how to get started. 24 | 25 | > **Notice:** Trial project phone number selection may be limited. You must upgrade your Twilio project to provision more than one phone number, or to provision a number that is not available to trial projects. 26 | 27 | 1. Access the Buy a Number page in the Console. 28 | 29 | ![Get Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-phone-number.png) 30 | 31 | 2. Enter the criteria for the phone number you need, and then click Search. 32 | 33 | ![Configure Phone Number](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/phone-number-config.png) 34 | 35 | - Country: Select the desired country from the drop-down menu. 36 | - Number or Location: Select the desired option to search by digits/phrases, or a specific City or Region. 37 | - Capabilities: Select your service needs for this number. 38 | 39 | 3. Click Buy to purchase a phone number for your current project or sub-account. 40 | 41 | ![Search Results](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/search-phone-number.png) 42 | > **Notice:** Many countries require identity documentation for Phone Number compliance. Requests to provision phone numbers with these regulations will be required to select or add the required documentation after clicking Buy in Console. To see which countries and phone number types are affected by these requirements, please see twilio's [Phone Number Regulations](https://www.twilio.com/guidelines/regulatory) site. 43 | 44 | ### Step 3: Obtain the Twilio account SID with API key and API secret 45 | 46 | You can find API keys related information under [API keys & tokens](https://console.twilio.com/us1/account/keys-credentials/api-keys) section in your Twilio account. If you do not have an API key and a secret, please complete the following steps: 47 | 48 | 1. Access the [API keys & tokens](https://console.twilio.com/us1/account/keys-credentials/api-keys) page in your Twilio account, and then click on Create API key. 49 | 50 | ![Twilio API Key](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/api-key-config.png) 51 | 52 | 2. Enter the criteria for the API Key you need, and then click Create. 53 | 54 | ![Create API Key](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/create-api-key.png) 55 | 56 | - Friendly name: Enter a human-readable name for your API key. It helps you identify the key later, especially if you have multiple API keys. 57 | - Region: Enter the geographical region where the API key will be used. 58 | - Key type: There are different types of API keys you can create, 59 | - Standard: Provides access to all Twilio API functionalities except for managing API keys and configuring accounts and subaccounts. 60 | - Main: Offers the same access as standard keys but also allows managing API keys and configuring accounts and subaccounts. 61 | - Restricted: Allows fine-grained access to specific Twilio API resources, enabling you to set permissions for different API endpoints 62 | 63 | 3. Save the API key SID and the Secret in a safe place to use in your application. 64 | 65 | ![API Key Info](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/api-key-info.png) 66 | 67 | > **Important:** This secret is only shown once. Please make note of it and store it in a safe and a secure location. 68 | 69 | 4. In order to obtain the Account SID of your Twilio account, you can visit your [Twilio console](https://www.twilio.com/console). 70 | 71 | ![Twilio Credentials](https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-twilio/master/ballerina/resources/get-credentails.png) 72 | 73 | ## Quickstart 74 | 75 | To use the `twilio` connector in your Ballerina application, modify the `.bal` file as follows: 76 | 77 | ### Step 1 - Import the module 78 | 79 | Import the Twilio module into your Ballerina program as shown below: 80 | 81 | ```ballerina 82 | import ballerinax/twilio; 83 | ``` 84 | 85 | ### Step 2 - Create a new connector instance 86 | 87 | To create a new connector instance, add a configuration as follows (You can use [configurable variables](https://ballerina.io/learn/by-example/configurable.html) to provide the necessary credentials): 88 | 89 | ```ballerina 90 | configurable string apiKey = ?; 91 | configurable string apiSecret = ?; 92 | configurable string accountSid = ?; 93 | 94 | twilio:ConnectionConfig twilioConfig = { 95 | auth: { 96 | apiKey, 97 | apiSecret, 98 | accountSid 99 | } 100 | }; 101 | 102 | twilio:Client twilio = check new (twilioConfig); 103 | ``` 104 | 105 | ### Step 3 - Invoke the connector operation 106 | 107 | Invoke the sending SMS operation using the client as shown below: 108 | 109 | ```ballerina 110 | public function main() returns error? { 111 | twilio:CreateMessageRequest messageRequest = { 112 | To: "+XXXXXXXXXXX", // Phone number that you want to send the message to 113 | From: "+XXXXXXXXXXX", // Twilio phone number 114 | Body: "Hello from Ballerina" 115 | }; 116 | 117 | twilio:Message response = check twilio->createMessage(messageRequest); 118 | 119 | // Print the status of the message from the response 120 | io:println("Message Status: ", response?.status); 121 | } 122 | ``` 123 | 124 | ### Step 4: Run the Ballerina application 125 | 126 | Execute the command below to execute the Ballerina application: 127 | 128 | ```bash 129 | bal run 130 | ``` 131 | 132 | ## Examples 133 | 134 | The Twilio connector comes equipped with examples that demonstrate its usage across various scenarios. These examples are conveniently organized into three distinct groups based on the functionalities they showcase. For a more hands-on experience and a deeper understanding of these capabilities, we encourage you to experiment with the provided examples in your development environment. 135 | 136 | 1. Account management 137 | - [Create a sub-account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/create-sub-account) - Create a subaccount under a Twilio account 138 | - [Fetch an account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/fetch-account) - Get details of a Twilio account 139 | - [Fetch balance](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/fetch-balance) - Get the balance of a Twilio account 140 | - [List accounts](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/list-accounts) - List all subaccounts under a Twilio account 141 | - [Update an account](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/accounts/update-account) - Update the name of a Twilio account 142 | 2. Call management 143 | - [Make a call](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/create-call) - Make a call to a phone number via a Twilio 144 | - [Fetch call log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/fetch-call-log) - Get details of a call made via a Twilio 145 | - [List call logs](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/list-call-logs) - Get details of all calls made via a Twilio 146 | - [Delete a call log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/calls/delete-call-log) - Delete the log of a call made via Twilio 147 | 3. Message management 148 | - [Send an SMS message](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/create-sms-message) - Send an SMS to a phone number via a Twilio 149 | - [Send a Whatsapp message](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/create-whatsapp-message) - Send a Whatsapp message to a phone number via a Twilio 150 | - [List message logs](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/list-message-logs) - Get details of all messages sent via a Twilio 151 | - [Fetch a message log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/fetch-message-log) - Get details of a message sent via a Twilio 152 | - [Delete a message log](https://github.com/ballerina-platform/module-ballerinax-twilio/tree/master/examples/messages/delete-message-log) - Delete a message log via a Twilio 153 | 154 | ## Issues and projects 155 | 156 | The **Issues** and **Projects** tabs are disabled for this repository as this is part of the Ballerina library. To report bugs, request new features, start new discussions, view project boards, etc., visit the Ballerina library [parent repository](https://github.com/ballerina-platform/ballerina-library). 157 | 158 | This repository only contains the source code for the package. 159 | 160 | ## Build from the source 161 | 162 | ### Prerequisites 163 | 164 | 1. Download and install Java SE Development Kit (JDK) version 17. You can download it from either of the following sources: 165 | 166 | * [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) 167 | * [OpenJDK](https://adoptium.net/) 168 | 169 | > **Note:** After installation, remember to set the `JAVA_HOME` environment variable to the directory where JDK was installed. 170 | 171 | 2. Download and install [Ballerina Swan Lake](https://ballerina.io/). 172 | 173 | 3. Download and install [Docker](https://www.docker.com/get-started). 174 | 175 | > **Note**: Ensure that the Docker daemon is running before executing any tests. 176 | 177 | 4. Export Github Personal access token with read package permissions as follows, 178 | ``` 179 | export packageUser= 180 | export packagePAT= 181 | ``` 182 | 183 | ### Build options 184 | 185 | Execute the commands below to build from the source. 186 | 187 | 1. To build the package: 188 | ``` 189 | ./gradlew clean build 190 | ``` 191 | 192 | 2. To run the tests: 193 | ``` 194 | ./gradlew clean test 195 | ``` 196 | 197 | 3. To build the without the tests: 198 | ``` 199 | ./gradlew clean build -x test 200 | ``` 201 | 202 | 4. To run tests against different environments: 203 | 204 | ```bash 205 | ./gradlew clean test -Pgroups= 206 | ``` 207 | 208 | The following test environments, along with their respective groups of compatible tests, are available to test the connector. 209 | 210 | Groups | Environment 211 | ---| --- 212 | mock_tests | Mock server for Twilio API (Default Environment) 213 | live_tests | Twilio API 214 | 215 | To run tests against these environments, you can follow this [Test Guide](https://github.com/ballerina-platform/module-ballerinax-twilio/blob/master/ballerina/tests/README.md). 216 | 217 | 5. To debug the package with a remote debugger: 218 | ``` 219 | ./gradlew clean build -Pdebug= 220 | ``` 221 | 222 | 6. To debug with the Ballerina language: 223 | ``` 224 | ./gradlew clean build -PbalJavaDebug= 225 | ``` 226 | 227 | 7. Publish the generated artifacts to the local Ballerina Central repository: 228 | ``` 229 | ./gradlew clean build -PpublishToLocalCentral=true 230 | ``` 231 | 232 | 8. Publish the generated artifacts to the Ballerina Central repository: 233 | ``` 234 | ./gradlew clean build -PpublishToCentral=true 235 | ``` 236 | 237 | ## Contribute to Ballerina 238 | 239 | As an open-source project, Ballerina welcomes contributions from the community. 240 | 241 | For more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md). 242 | 243 | ## Code of conduct 244 | 245 | All the contributors are encouraged to read the [Ballerina Code of Conduct](https://ballerina.io/code-of-conduct). 246 | 247 | ## Useful links 248 | 249 | * For more information go to the [Twilio package](https://central.ballerina.io/ballerinax/twilio/latest). 250 | * For example demonstrations of the usage, go to [Ballerina By Examples](https://ballerina.io/learn/by-example/). 251 | * Chat live with us via our [Discord server](https://discord.gg/ballerinalang). 252 | * Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag. 253 | -------------------------------------------------------------------------------- /ballerina/tests/tests.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import twilio.mock as _; 18 | 19 | import ballerina/http; 20 | import ballerina/log; 21 | import ballerina/os; 22 | import ballerina/test; 23 | 24 | configurable boolean isTestOnLiveServer = os:getEnv("IS_TEST_ON_LIVE_SERVER") == "true"; 25 | 26 | // Configurables 27 | configurable string accountSid = isTestOnLiveServer ? os:getEnv("ACCOUNT_SID"): "AC12345678901234567890123456789012"; 28 | configurable string authToken = isTestOnLiveServer ? os:getEnv("AUTH_TOKEN"): "AU12345678901234567890123456789012"; 29 | configurable string toPhoneNumber = isTestOnLiveServer ? os:getEnv("TO_PHONE"): "+011234567890"; 30 | configurable string fromPhoneNumber = isTestOnLiveServer ? os:getEnv("TWILIO_PHONE"): "+098765432101"; 31 | 32 | Client twilio = test:mock(Client); 33 | 34 | // Common test data 35 | string sampleName = "ballerina_test"; 36 | string messageBody = "Hello from Ballerina!"; 37 | string recordingURL = "http://demo.twilio.com/docs/voice.xml"; 38 | string globalCallSid = ""; 39 | string globalAddressSid = ""; 40 | string globalMsgSid = ""; 41 | 42 | CreateAccountRequest crAccReq = { 43 | FriendlyName: sampleName 44 | }; 45 | UpdateAccountRequest upAccReq = { 46 | FriendlyName: "bellerina_test_master" 47 | }; 48 | CreateAddressRequest crAddReq = { 49 | FriendlyName: sampleName, 50 | City: "city_of_ballerina", 51 | Street: "street_of_ballerina", 52 | CustomerName: "ballerina_tester", 53 | IsoCountry: "LK", 54 | PostalCode: "00000", 55 | Region: "region_of_ballerina" 56 | }; 57 | UpdateAddressRequest upAddReq = { 58 | FriendlyName: "ballerina_test_updated" 59 | }; 60 | CreateCallRequest callReq = { 61 | To: toPhoneNumber, 62 | From: fromPhoneNumber, 63 | Url: recordingURL 64 | }; 65 | CreateMessageRequest msgReq = { 66 | To: toPhoneNumber, 67 | From: fromPhoneNumber, 68 | Body: messageBody 69 | }; 70 | 71 | 72 | @test:BeforeSuite 73 | function initializeClientsForTwilioServer () returns error? { 74 | if (isTestOnLiveServer) { 75 | log:printInfo("Running tests on actual server"); 76 | twilio = check new ({auth: {accountSid: accountSid, authToken: authToken}}); 77 | } else { 78 | log:printInfo("Running tests on mock server"); 79 | twilio = check new ({auth: {accountSid: accountSid, authToken: authToken}}, serviceUrl = "http://localhost:9090/"); 80 | } 81 | } 82 | @test:Config { 83 | groups: ["live_tests", "mock_tests"], 84 | enable: true 85 | } 86 | function testListAccount() returns error? { 87 | ListAccountResponse? response = check twilio->listAccount(); 88 | if (response is ListAccountResponse) { 89 | Account[]? accounts = response.accounts; 90 | if accounts is Account[] { 91 | Account account = accounts[0]; 92 | test:assertEquals(account?.owner_account_sid, accountSid, "ListAccount Failed : SId Missmatch"); 93 | } else { 94 | test:assertFail("ListAccount Failed : Account Dosen't Exists."); 95 | } 96 | } else { 97 | test:assertFail("ListAccount Failed : Wrong Responce Type."); 98 | } 99 | } 100 | @test:Config { 101 | groups: ["mock_tests"], 102 | enable: true 103 | } 104 | function testCreateAccount() returns error? { 105 | Account? response = check twilio->createAccount(crAccReq); 106 | if (response is Account) { 107 | test:assertEquals(response?.friendly_name, crAccReq.FriendlyName, "CreateAcoount failed : Name Missmatch"); 108 | string? accountSid = response?.sid; 109 | if accountSid is string { 110 | accountSid = accountSid; 111 | } else { 112 | test:assertFail("CreateAccount Failed : Account SID Dosen't Exists."); 113 | } 114 | } else { 115 | test:assertFail("CreateAccount Failed : Account Dosen't Exists."); 116 | } 117 | } 118 | 119 | @test:Config { 120 | groups: ["live_tests", "mock_tests"], 121 | enable: true 122 | } 123 | function testFetchAccount() returns error? { 124 | Account? response = check twilio->fetchAccount(accountSid); 125 | if (response is Account) { 126 | test:assertEquals(response?.owner_account_sid, accountSid, "FetchAcoount failed : SID Missmatch"); 127 | } else { 128 | test:assertFail("FetchAccount Failed : Account Dosen't Exists."); 129 | } 130 | } 131 | 132 | @test:Config { 133 | groups: ["live_tests", "mock_tests"], 134 | enable: true 135 | } 136 | function testUpdateAccount() returns error? { 137 | Account? response = check twilio->updateAccount(accountSid, upAccReq); 138 | if (response is Account) { 139 | test:assertEquals(response?.friendly_name, upAccReq.FriendlyName, "UpdateAcoount failed : Name Missmatch"); 140 | } else { 141 | test:assertFail("UpdateAccount Failed : Account Dosen't Exists."); 142 | } 143 | } 144 | 145 | @test:Config { 146 | groups: ["live_tests", "mock_tests"], 147 | enable: true 148 | } 149 | function testCreateAddress() returns error? { 150 | Address? response = check twilio->createAddress(crAddReq); 151 | if (response is Address) { 152 | test:assertEquals(response?.friendly_name, crAddReq.FriendlyName, "CreateAddress failed : Name Missmatch"); 153 | test:assertEquals(response?.street, crAddReq.Street, "CreateAddress failed : Street Missmatch"); 154 | test:assertEquals(response?.city, crAddReq.City, "CreateAddress failed : City Missmatch"); 155 | test:assertEquals(response?.customer_name, crAddReq.CustomerName, "CreateAddress failed : Customer Name Missmatch"); 156 | test:assertEquals(response?.iso_country, crAddReq.IsoCountry, "CreateAddress failed : Country Missmatch"); 157 | test:assertEquals(response?.postal_code, crAddReq.PostalCode, "CreateAddress failed : PostalCode Missmatch"); 158 | test:assertEquals(response?.region, crAddReq.Region, "CreateAddress failed : Region Missmatch"); 159 | string? addressSid = response?.sid; 160 | if addressSid is string { 161 | globalAddressSid = addressSid; 162 | } else { 163 | test:assertFail("CreateAddress Failed : Address SID Dosen't Exists."); 164 | } 165 | } else { 166 | test:assertFail("CreateAddress Failed : Address Dosen't Exists."); 167 | } 168 | } 169 | 170 | @test:Config { 171 | groups: ["live_tests", "mock_tests"], 172 | enable: true, 173 | dependsOn: [testCreateAddress] 174 | } 175 | function testListAddress() returns error? { 176 | ListAddressResponse? response = check twilio->listAddress(); 177 | if (response is ListAddressResponse) { 178 | Address[]? addresses = response.addresses; 179 | if addresses is Address[] { 180 | Address address = addresses[0]; 181 | test:assertEquals(address?.account_sid, accountSid, "ListAddress Failed : SId Missmatch"); 182 | } else { 183 | test:assertFail("ListAddress Failed : Account Dosen't Exists."); 184 | } 185 | } else { 186 | test:assertFail("ListAddress Failed : Wrong Responce Type."); 187 | } 188 | } 189 | 190 | @test:Config { 191 | groups: ["live_tests", "mock_tests"], 192 | enable: true, 193 | dependsOn: [testCreateAddress] 194 | } 195 | function testFetchAddress() returns error? { 196 | Address? response = check twilio->fetchAddress(globalAddressSid); 197 | if (response is Address) { 198 | test:assertEquals(response?.friendly_name, crAddReq.FriendlyName, "FetchAddress failed : Name Missmatch"); 199 | test:assertEquals(response?.street, crAddReq.Street, "FetchAddress failed : Street Missmatch"); 200 | test:assertEquals(response?.city, crAddReq.City, "FetchAddress failed : City Missmatch"); 201 | test:assertEquals(response?.customer_name, crAddReq.CustomerName, "FetchAddress failed : Customer Name Missmatch"); 202 | test:assertEquals(response?.iso_country, crAddReq.IsoCountry, "FetchAddress failed : Country Missmatch"); 203 | test:assertEquals(response?.postal_code, crAddReq.PostalCode, "FetchAddress failed : PostalCode Missmatch"); 204 | test:assertEquals(response?.region, crAddReq.Region, "FetchAddress failed : Region Missmatch"); 205 | } else { 206 | test:assertFail("FetchAddress Failed : Account Dosen't Exists."); 207 | } 208 | } 209 | 210 | @test:Config { 211 | groups: ["live_tests", "mock_tests"], 212 | enable: true, 213 | dependsOn: [testFetchAddress] 214 | } 215 | function testUpdateAddress() returns error? { 216 | Address? response = check twilio->updateAddress(globalAddressSid, upAddReq); 217 | if (response is Address) { 218 | test:assertEquals(response?.friendly_name, upAddReq.FriendlyName, "UpdateAddress failed : Name Missmatch"); 219 | } else { 220 | test:assertFail("UpdateAddress Failed : Address Dosen't Exists."); 221 | } 222 | } 223 | 224 | @test:Config { 225 | groups: ["live_tests", "mock_tests"], 226 | enable: true, 227 | dependsOn: [testUpdateAddress] 228 | } 229 | function testDeleteAddress() returns error? { 230 | http:Response? response = check twilio->deleteAddress(globalAddressSid); 231 | if (response is http:Response) { 232 | test:assertEquals(response.statusCode, 204, "Delete Address failed"); 233 | } else { 234 | test:assertFail("Delete Address Failed"); 235 | } 236 | } 237 | 238 | @test:Config { 239 | groups: ["live_tests", "mock_tests"], 240 | enable: true 241 | } 242 | function testCreateCall() returns error? { 243 | Call? response = check twilio->createCall(callReq); 244 | if (response is Call) { 245 | test:assertEquals(response?.to, callReq.To, "CreateCall failed : Phone Number Missmatch"); 246 | string? sid = response?.sid; 247 | if sid is string { 248 | globalCallSid = sid; 249 | } else { 250 | test:assertFail("CreateCall Failed : Call SID Dosen't Exists."); 251 | } 252 | } else { 253 | test:assertFail("CreateCall Failed : Call Dosen't Exists."); 254 | } 255 | } 256 | 257 | @test:Config { 258 | groups: ["live_tests", "mock_tests"], 259 | enable: true, 260 | dependsOn: [testCreateCall] 261 | } 262 | function testListCalls() returns error? { 263 | ListCallResponse? response = check twilio->listCall(); 264 | if (response is ListCallResponse) { 265 | Call[]? calls = response.calls; 266 | if calls is Call[] { 267 | Call call = calls[0]; 268 | test:assertEquals(call?.account_sid, accountSid, "ListCall Failed : SId Missmatch"); 269 | } else { 270 | test:assertFail("ListCall Failed : Calls Dosen't Exists."); 271 | } 272 | } else { 273 | test:assertFail("ListCall Failed : Wrong Responce Type."); 274 | } 275 | } 276 | 277 | @test:Config { 278 | groups: ["live_tests", "mock_tests"], 279 | enable: true, 280 | dependsOn: [testCreateCall] 281 | } 282 | function testFetchCall() returns error? { 283 | Call? response = check twilio->fetchCall(globalCallSid); 284 | if (response is Call) { 285 | test:assertEquals(response?.to, callReq.To, "FetchCall failed : To Missmatch"); 286 | test:assertEquals(response?.'from, callReq.From, "FetchCall failed : From Missmatch"); 287 | } else { 288 | test:assertFail("FetchCall Failed : Call Dosen't Exists."); 289 | } 290 | } 291 | @test:Config { 292 | groups: ["live_tests", "mock_tests"], 293 | enable: true, 294 | dependsOn: [testFetchCall,testListCalls] 295 | } 296 | function testDeleteCall() returns error? { 297 | http:Response? response = check twilio->deleteCall(globalCallSid); 298 | if (response is http:Response) { 299 | test:assertEquals(response.statusCode, 409, "Delete Call failed"); 300 | } else { 301 | test:assertFail("Delete Call Failed"); 302 | } 303 | } 304 | 305 | @test:Config { 306 | groups: ["live_tests", "mock_tests"], 307 | enable: true 308 | } 309 | function testCreateMessage() returns error? { 310 | Message? response = check twilio->createMessage(msgReq); 311 | if (response is Message) { 312 | test:assertEquals(response?.to, msgReq.To, "CreateMessage failed : Phone Number Missmatch"); 313 | string? sid = response?.sid; 314 | if sid is string { 315 | globalMsgSid = sid; 316 | } else { 317 | test:assertFail("CreateMessage Failed : Call SID Dosen't Exists."); 318 | } 319 | } else { 320 | test:assertFail("CreateMessage Failed : Call Dosen't Exists."); 321 | } 322 | } 323 | 324 | @test:Config { 325 | groups: ["live_tests", "mock_tests"], 326 | enable: true, 327 | dependsOn: [testCreateMessage] 328 | } 329 | function testListMessages() returns error? { 330 | ListMessageResponse? response = check twilio->listMessage(); 331 | if (response is ListMessageResponse) { 332 | Message[]? msgs = response.messages; 333 | if msgs is Message[] { 334 | Message msg = msgs[0]; 335 | test:assertEquals(msg?.account_sid, accountSid, "ListMessage Failed : SId Missmatch"); 336 | } else { 337 | test:assertFail("ListMessage Failed : Messages Dosen't Exists."); 338 | } 339 | } else { 340 | test:assertFail("ListMessage Failed : Wrong Responce Type."); 341 | } 342 | } 343 | 344 | @test:Config { 345 | groups: ["live_tests", "mock_tests"], 346 | enable: true, 347 | dependsOn: [testCreateMessage] 348 | } 349 | function testFetchMessage() returns error? { 350 | Message? response = check twilio->fetchMessage(globalMsgSid); 351 | if (response is Message) { 352 | test:assertEquals(response?.to, msgReq.To, "FetchMessage failed : To Missmatch"); 353 | test:assertEquals(response?.'from, msgReq.From, "FetchMessage failed : From Missmatch"); 354 | } else { 355 | test:assertFail("FetchMessage Failed : Message Dosen't Exists."); 356 | } 357 | } 358 | @test:Config { 359 | groups: ["live_tests", "mock_tests"], 360 | enable: true, 361 | dependsOn: [testFetchMessage,testListMessages] 362 | } 363 | function testDeleteMessage() returns error? { 364 | http:Response? response = check twilio->deleteMessage(globalMsgSid); 365 | if (response is http:Response) { 366 | test:assertEquals(response.statusCode, 409, "Delete Message failed"); 367 | } else { 368 | test:assertFail("Delete Message Failed"); 369 | } 370 | } --------------------------------------------------------------------------------