├── .github ├── ISSUE_TEMPLATE │ └── config.yml └── workflows │ ├── golangci-lint.yml │ ├── pr-lint.yml │ └── test-and-deploy.yml ├── .gitignore ├── .goreleaser.yaml ├── CHANGES.md ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── ISSUE_TEMPLATE.md ├── LICENSE ├── Makefile ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── UPGRADE.md ├── client └── provider.go ├── core ├── form_encoder.go ├── form_encoder_test.go ├── nullable.go ├── nullable_test.go ├── provider_marshal.go ├── provider_marshal_test.go ├── query_encode_test.go ├── query_encoder.go ├── schema.go ├── schema_test.go ├── sids.go ├── sids_test.go ├── tags.go ├── twilio_error.go ├── types.go └── types_test.go ├── examples ├── api │ └── v2010 │ │ └── apicore.tf ├── autopilot │ └── v1 │ │ └── autopilot.tf ├── bulkexports │ └── v1 │ │ └── bulkexports.tf ├── chat │ └── v2 │ │ └── chat.tf ├── events │ └── v1 │ │ └── events.tf ├── flex │ ├── flex_setup.tf │ └── v1 │ │ ├── README.md │ │ └── flex_import_default.tf ├── notify │ └── v1 │ │ └── notify.tf ├── proxy │ └── v1 │ │ └── proxy.tf ├── serverless │ └── v1 │ │ └── serverless.tf ├── studio │ └── v2 │ │ └── studio.tf ├── sync │ └── v1 │ │ └── sync.tf ├── taskrouter │ └── v1 │ │ └── taskrouter.tf ├── trunking │ └── v1 │ │ └── trunking.tf └── verify │ └── v2 │ └── verify.tf ├── githooks └── pre-commit ├── go.mod ├── go.sum ├── main.go ├── sonar-project.properties ├── twilio ├── provider.go ├── provider_test.go ├── resources │ ├── README.md │ ├── accounts │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── api │ │ └── v2010 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── chat │ │ ├── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ │ └── v2 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── conversations │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── events │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── flex │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── intelligence │ │ └── v2 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── ip_messaging │ │ ├── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ │ └── v2 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── messaging │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── microvisor │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── notify │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── numbers │ │ └── v2 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── proxy │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── resources.go │ ├── serverless │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── studio │ │ ├── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ │ └── v2 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── supersim │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── sync │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── taskrouter │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── trunking │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── trusthub │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── verify │ │ └── v2 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── video │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ ├── voice │ │ └── v1 │ │ │ ├── README.md │ │ │ └── api_default.go │ └── wireless │ │ └── v1 │ │ ├── README.md │ │ └── api_default.go ├── resources_flex_test.go └── resources_serverless_test.go └── usage.md /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: Twilio Support 3 | url: https://twilio.com/help/contact 4 | about: Get Support 5 | - name: Stack Overflow 6 | url: https://stackoverflow.com/questions/tagged/terraform-provider-twilio+or+twilio+terraform 7 | about: Ask questions on Stack Overflow 8 | - name: Documentation 9 | url: https://github.com/twilio/terraform-provider-twilio/blob/main/twilio/resources/README.md 10 | about: View Reference Documentation 11 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: [pull_request] 3 | jobs: 4 | golangci-lint: 5 | name: lint 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Check out code into the Go module directory 9 | uses: actions/checkout@v3 10 | 11 | - name: Set up Go 12 | uses: actions/setup-go@v3 13 | 14 | - name: golangci-lint 15 | uses: golangci/golangci-lint-action@v3 16 | with: 17 | version: latest 18 | args: --timeout=3m 19 | -------------------------------------------------------------------------------- /.github/workflows/pr-lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR 2 | on: 3 | pull_request_target: 4 | types: [ opened, edited, synchronize, reopened ] 5 | 6 | jobs: 7 | validate: 8 | name: Validate title 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: amannn/action-semantic-pull-request@v5 12 | with: 13 | types: | 14 | chore 15 | docs 16 | fix 17 | feat 18 | misc 19 | test 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | -------------------------------------------------------------------------------- /.github/workflows/test-and-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Test and Deploy 2 | on: 3 | push: 4 | branches: [ '*' ] 5 | tags: [ 'v*' ] 6 | pull_request: 7 | branches: [ main ] 8 | schedule: 9 | # Run automatically at 8AM PST Monday-Friday 10 | - cron: '0 15 * * 1-5' 11 | workflow_dispatch: 12 | 13 | jobs: 14 | test: 15 | name: Test 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 20 18 | strategy: 19 | matrix: 20 | go: [ '1.18', '1.19', '1.20' ] 21 | env: 22 | TF_INPUT: false 23 | steps: 24 | - name: Checkout terraform-provider-twilio 25 | uses: actions/checkout@v3 26 | with: 27 | # Disabling shallow clone is recommended for improving relevancy of reporting 28 | fetch-depth: 0 29 | 30 | - name: Set up Go 31 | uses: actions/setup-go@v3 32 | with: 33 | go-version: ${{ matrix.go }} 34 | id: go 35 | 36 | - name: Set up Terraform 37 | uses: hashicorp/setup-terraform@v2 38 | with: 39 | terraform_version: 1.0.0 40 | terraform_wrapper: false 41 | 42 | - name: Run tests 43 | run: make install test 44 | 45 | - name: Run Cluster Tests 46 | if: ${{ (github.ref == 'refs/heads/main' || github.ref_type == 'tag') && github.event_name != 'pull_request' }} 47 | env: 48 | TWILIO_ACCOUNT_SID: ${{ secrets.ACCOUNT_SID }} 49 | TWILIO_API_SECRET: ${{ secrets.TWILIO_CLUSTER_TEST_API_KEY_SECRET }} 50 | TWILIO_API_KEY: ${{ secrets.TWILIO_CLUSTER_TEST_API_KEY }} 51 | run: make testacc 52 | 53 | - name: Run Test Coverage 54 | if: ${{ (github.event_name == 'pull_request' || github.ref_type == 'branch') && !github.event.pull_request.head.repo.fork && matrix.go == '1.18'}} 55 | run: make test-cover 56 | 57 | - name: Install SonarCloud scanner and run analysis 58 | if: ${{ (github.event_name == 'pull_request' || github.ref_type == 'branch') && !github.event.pull_request.head.repo.fork && matrix.go == '1.18' }} 59 | uses: SonarSource/sonarcloud-github-action@master 60 | env: 61 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 62 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 63 | 64 | deploy: 65 | name: Deploy 66 | if: success() && github.ref_type == 'tag' 67 | needs: [ test ] 68 | runs-on: ubuntu-latest 69 | steps: 70 | - name: Checkout 71 | uses: actions/checkout@v3 72 | - name: Unshallow 73 | run: git fetch --prune --unshallow 74 | - name: Set up Go 75 | uses: actions/setup-go@v3 76 | with: 77 | go-version: 1.18 78 | - name: Import GPG key 79 | id: import_gpg 80 | uses: crazy-max/ghaction-import-gpg@v5 81 | with: 82 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 83 | passphrase: ${{ secrets.PASSPHRASE }} 84 | - name: Create GitHub Release 85 | uses: sendgrid/dx-automator/actions/release@main 86 | env: 87 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 88 | - name: Run GoReleaser 89 | uses: goreleaser/goreleaser-action@v2.5.0 90 | with: 91 | version: '~> v1' 92 | args: release --clean 93 | env: 94 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} 95 | # GitHub sets this automatically 96 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 97 | - name: Submit metric to Datadog 98 | uses: sendgrid/dx-automator/actions/datadog-release-metric@main 99 | env: 100 | DD_API_KEY: ${{ secrets.DATADOG_API_KEY }} 101 | 102 | notify-on-failure: 103 | name: Slack notify on failure 104 | if: failure() && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref_type == 'tag') 105 | needs: [ test, deploy ] 106 | runs-on: ubuntu-latest 107 | steps: 108 | - uses: rtCamp/action-slack-notify@v2 109 | env: 110 | SLACK_COLOR: failure 111 | SLACK_ICON_EMOJI: ':github:' 112 | SLACK_MESSAGE: ${{ format('Test *{0}*, Deploy *{1}*, {2}/{3}/actions/runs/{4}', needs.test.result, needs.deploy.result, github.server_url, github.repository, github.run_id) }} 113 | SLACK_TITLE: Action Failure - ${{ github.repository }} 114 | SLACK_USERNAME: GitHub Actions 115 | SLACK_MSG_AUTHOR: twilio-dx 116 | SLACK_FOOTER: Posted automatically using GitHub Actions 117 | SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} 118 | MSG_MINIMAL: true 119 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDEs 2 | .idea/ 3 | 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | __debug__bin 11 | 12 | # Test binary, built with `go test -c` 13 | *.test 14 | 15 | # Output of the go coverage tool, specifically when used with LiteIDE 16 | *.out 17 | *.log 18 | 19 | # Terraform files for testing 20 | terraform-provider-twilio 21 | .terraform* 22 | *.tfstate 23 | *.tfstate.backup 24 | 25 | docs/ 26 | **/.openapi-generator 27 | .openapi-generator-ignore 28 | 29 | coverage.out 30 | test-report.out 31 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | builds: 4 | - env: 5 | # goreleaser does not work with CGO, it could also complicate 6 | # usage by users in CI/CD systems like Terraform Cloud where 7 | # they are unable to install libraries. 8 | - CGO_ENABLED=0 9 | mod_timestamp: '{{ .CommitTimestamp }}' 10 | flags: 11 | - -trimpath 12 | ldflags: 13 | - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' 14 | goos: 15 | - freebsd 16 | - windows 17 | - linux 18 | - darwin 19 | goarch: 20 | - amd64 21 | - '386' 22 | - arm 23 | - arm64 24 | ignore: 25 | - goos: darwin 26 | goarch: '386' 27 | binary: '{{ .ProjectName }}_v{{ .Version }}' 28 | archives: 29 | - format: zip 30 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 31 | checksum: 32 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 33 | algorithm: sha256 34 | signs: 35 | - artifacts: checksum 36 | args: 37 | # if you are using this in a GitHub action or some other automated pipeline, you 38 | # need to pass the batch flag to indicate its not interactive. 39 | - "--batch" 40 | - "--local-user" 41 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 42 | - "--output" 43 | - "${signature}" 44 | - "--detach-sign" 45 | - "${artifact}" 46 | release: 47 | # If you want to manually examine the release before its live, uncomment this line: 48 | # draft: true 49 | changelog: 50 | skip: true 51 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at open-source@twilio.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.18 2 | 3 | RUN mkdir /twilio 4 | WORKDIR /twilio 5 | 6 | COPY client ./client 7 | COPY core ./core 8 | COPY twilio ./twilio 9 | COPY main.go . 10 | COPY Makefile . 11 | 12 | # Fetch dependencies 13 | COPY go.mod . 14 | COPY go.sum . 15 | RUN go mod download 16 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ### Issue Summary 10 | A summary of the issue and the environment in which it occurs. If suitable, include the steps required to reproduce the bug. Please feel free to include screenshots, screencasts, or code examples. 11 | 12 | ### Steps to Reproduce 13 | 1. This is the first step 14 | 2. This is the second step 15 | 3. Further steps, etc. 16 | 17 | ### Code Snippet 18 | ```terraform 19 | # paste code here 20 | ``` 21 | 22 | ### Exception/Log 23 | ``` 24 | # paste exception/log here 25 | ``` 26 | 27 | ### Technical details: 28 | * terraform-provider-twilio version: 29 | * terraform version: 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2023, Twilio, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: default githooks build goimports govet golint terrafmt install test test-docker testacc 2 | 3 | TEST?=$$(go list ./... |grep -v 'vendor') 4 | REGISTRY=local 5 | NAMESPACE=twilio 6 | NAME=twilio 7 | BINARY=terraform-provider-${NAME} 8 | VERSION=0.18.46 9 | OS_ARCH=darwin_amd64 10 | 11 | default: build 12 | 13 | githooks: 14 | ln -sf ../../githooks/pre-commit .git/hooks/pre-commit 15 | 16 | build: goimports terrafmt 17 | go build -o ${BINARY} 18 | 19 | goimports: 20 | go install golang.org/x/tools/cmd/goimports@v0.24.0 21 | goimports -w . 22 | go mod tidy 23 | 24 | govet: goimports 25 | go vet ./... 26 | 27 | golint: govet 28 | go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest 29 | golangci-lint run 30 | 31 | terrafmt: 32 | terraform fmt -recursive 33 | 34 | install: build 35 | mkdir -p ~/.terraform.d/plugins/${REGISTRY}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} 36 | mv ${BINARY} ~/.terraform.d/plugins/${REGISTRY}/${NAMESPACE}/${NAME}/${VERSION}/${OS_ARCH} 37 | 38 | test: build 39 | go test $(TEST) || exit 1 40 | echo $(TEST) | \ 41 | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 42 | 43 | test-docker: 44 | docker build -t terraform-provider-${NAME} . 45 | docker run terraform-provider-twilio make test -o build 46 | 47 | testacc: 48 | TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 120m 49 | 50 | GO_DIRS = $(shell go list ./... | grep -v /resources/) 51 | test-cover: 52 | go test ${GO_DIRS} -coverprofile coverage.out 53 | go test ${GO_DIRS} -json > test-report.out 54 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 16 | 17 | # Fixes # 18 | 19 | A short description of what this PR does. 20 | 21 | ### Checklist 22 | - [x] I acknowledge that all my contributions will be made under the project's license 23 | - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) 24 | - [ ] I have read the [Contribution Guidelines](https://github.com/twilio/terraform-provider-twilio/blob/main/CONTRIBUTING.md) and my PR follows them 25 | - [ ] I have titled the PR appropriately 26 | - [ ] I have updated my branch with the main branch 27 | - [ ] I have added tests that prove my fix is effective or that my feature works 28 | - [ ] I have added the necessary documentation about the functionality in the appropriate .md file 29 | - [ ] I have added inline documentation to the code I modified 30 | 31 | If you have questions, please file a [support ticket](https://twilio.com/help/contact), or create a GitHub Issue in this repository. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Twilio Terraform Provider 2 | [![Tests](https://github.com/twilio/terraform-provider-twilio/actions/workflows/test-and-deploy.yml/badge.svg)](https://github.com/twilio/terraform-provider-twilio/actions/workflows/test-and-deploy.yml) 3 | [![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/twilio/terraform-provider-twilio?)](https://github.com/Twilio/terraform-provider-twilio/releases/latest) 4 | [![Terraform Registry](https://img.shields.io/badge/registry-twilio-green?logo=terraform&style=flat)](https://registry.terraform.io/providers/twilio/twilio/latest) 5 | 6 | ## Project Status 7 | 8 | :warning: This project is currently in **PILOT** and NOT under active development and maintenance. 9 | 10 | ## Requirements 11 | 12 | - [Terraform](https://www.terraform.io/downloads.html) v0.15.x 13 | - [Go](https://golang.org/doc/install) 1.18+ (to build the provider plugin) 14 | 15 | ## Resource Documentation 16 | 17 | Documentation on the available resources that can be managed by this provider and their parameters can be found [here](twilio/resources/README.md). 18 | 19 | Note that file upload resources are currently not available. 20 | 21 | ## Building The Provider 22 | 23 | Clone repository: 24 | 25 | ```sh 26 | git clone git@github.com:twilio/terraform-provider-twilio 27 | ``` 28 | 29 | Enter the provider directory and build the provider: 30 | 31 | ```sh 32 | make build 33 | ``` 34 | 35 | ## Installing and Using the Provider 36 | 37 | 1. Run `make install` to install and build the twilio-terraform-provider. 38 | 2. Configure the Twilio provider with your twilio credentials in your Terraform configuration file (e.g. main.tf). These can also be set via `TWILIO_ACCOUNT_SID` and `TWILIO_AUTH_TOKEN` environment variables. 39 | 3. Add your resource configurations to your Terraform configuration file (e.g. main.tf). 40 | 41 | ```terraform 42 | terraform { 43 | required_providers { 44 | twilio = { 45 | source = "twilio/twilio" 46 | version = "0.18.46" 47 | } 48 | } 49 | } 50 | 51 | # Credentials can be found at www.twilio.com/console. 52 | provider "twilio" { 53 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 54 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 55 | } 56 | 57 | resource "twilio_api_accounts_keys" "key_name" { 58 | friendly_name = "terraform key" 59 | } 60 | 61 | output "messages" { 62 | value = twilio_api_accounts_keys.key_name 63 | } 64 | ``` 65 | 66 | 4. Run `terraform init` and `terraform apply` to initialize and apply changes to your Twilio infrastructure. 67 | 68 | ### Using environment variables 69 | 70 | You can use credentials stored in environment variables for your setup: 71 | 72 | #### OPTION 1 (recommended) 73 | * `TWILIO_ACCOUNT_SID` = your Account SID from [your console](https://www.twilio.com/console) 74 | * `TWILIO_API_KEY` = an API Key created in [your console](https://twil.io/get-api-key) 75 | * `TWILIO_API_SECRET` = the secret for the API Key (you would have received this when you created an API key) 76 | * _(optional)_ `TWILIO_REGION` = the Region for the account 77 | 78 | #### OPTION 2 79 | * `TWILIO_ACCOUNT_SID` = your Account SID from [your console](https://www.twilio.com/console) 80 | * `TWILIO_AUTH_TOKEN` = your Auth Token from [your console](https://www.twilio.com/console) 81 | * _(optional)_ `TWILIO_REGION` = the Region for the account 82 | 83 | ## Examples 84 | 85 | For usage examples, checkout the [documentation in usage.md](usage.md) and the [examples folder](examples). 86 | 87 | ## Developing the Provider 88 | 89 | The boilerplate includes the following: 90 | 91 | - `Makefile` contains helper functions used to build, package and install the Twilio Terraform Provider. It's currently written for MacOS Terraform provider development, but you can change the variables at the top of the file to match your OS_ARCH. 92 | 93 | The `install` function is configured to install the provider into the ~/.terraform.d/plugins/ folder. To use the locally installed provider, prefix the source path with `local` in your Terraform configuration file (i.e., `source = "local/twilio/twilio"`). Then run `terraform init` to use the locally built provider. 94 | 95 | - `examples` contains sample Terraform configuration that can be used to test the Twilio provider 96 | - `twilio` contains the main provider code. This will be where the provider's resources and data source implementations will be defined. 97 | 98 | If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (version 1.18+ is _required_). 99 | 100 | To compile the provider, run `make build`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory. 101 | 102 | ```sh 103 | make build 104 | ... 105 | $GOPATH/bin/terraform-provider-twilio 106 | ... 107 | ``` 108 | 109 | In order to run the full suite of Acceptance tests, run `make testacc`. Provide your Account SID and Auth Token as environment variables to properly configure the test suite. 110 | 111 | _Note:_ Acceptance tests create real resources, and often cost money to run. 112 | 113 | ```sh 114 | make testacc TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN 115 | ``` 116 | 117 | You can also specify a particular suite to run like so: 118 | 119 | ```shell 120 | make testacc TEST=./twilio/ TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID TWILIO_AUTH_TOKEN=YOUR_AUTH_TOKEN 121 | ``` 122 | 123 | An example test file can be found [here](https://github.com/twilio/terraform-provider-twilio/blob/main/twilio/resources_flex_test.go). 124 | 125 | ## Debugging 126 | 127 | First: 128 | 129 | ```sh 130 | export TF_LOG=TRACE 131 | ``` 132 | 133 | then refer to the [Terraform Debugging Documentation](https://www.terraform.io/docs/internals/debugging.html). 134 | 135 | ### Debugging with Delve 136 | 137 | You can build and debug the provider locally. When using Goland you can set break point and step through code: 138 | 139 | ```sh 140 | $ dlv debug main.go -- -debug 141 | Type 'help' for list of commands. 142 | (dlv) c 143 | Provider started, to attach Terraform set the TF_REATTACH_PROVIDERS env var: 144 | 145 | TF_REATTACH_PROVIDERS='{"registry.terraform.io/twilio/twilio":{...}}}' 146 | ``` 147 | 148 | Copy the `TF_REATTACH_PROVIDERS` and run Terraform with this value set: 149 | 150 | ```sh 151 | $ TF_REATTACH_PROVIDERS='...' terraform init 152 | $ TF_REATTACH_PROVIDERS='...' terraform plan 153 | ... 154 | ``` 155 | 156 | Terraform will use the binary running under `dlv` instead of the `twilio/twilio` registry version. For further details 157 | refer to the [Terraform Debugging Providers](https://www.terraform.io/docs/extend/debugging.html) documentation. 158 | 159 | ### Debugging with Goland 160 | 161 | - Set up GOROOT (initially opening `main.go` should show this option) 162 | - Select `Modify Run Configuration...` on `main.go` and then add `--debug` as `Program arguments` 163 | - Select `Debug "go build main.go"` and then copy the `TF_REATTACH_PROVIDERS` to the shell where `terraform` will be run 164 | - Set breakpoints in Goland as needed and run `terraform`, it will use plugin the process running under the Goland debugger 165 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | # Upgrade guide 2 | 3 | [2022-06-01] 0.17.x to 0.18.x 4 | ------------------------------ 5 | 6 | ### CHANGED - Use the full resource names for AWS, SIP, and Usa2p resources. 7 | 8 | Multiple resources were missing the full resource name when an acronym was used. These parts have been added to the 9 | resource name. 10 | 11 | #### Create a SIP domain 12 | 13 | ```terraform 14 | // 0.17.x 15 | resource "twilio_api_accounts_domains" "sip_domain" { 16 | domain_name = "my-domain-sip.twilio.com" 17 | } 18 | ``` 19 | 20 | ```terraform 21 | // 0.18.x 22 | resource "twilio_api_accounts_sip_domains" "sip_domain" { 23 | domain_name = "my-domain-sip.twilio.com" 24 | } 25 | ``` 26 | 27 | [2022-05-20] 0.16.x to 0.17.x 28 | ------------------------------ 29 | ### CHANGED - Renamed ApiV2010 to Api. 30 | ApiV2010 has now been renamed to Api. This has caused a breaking change for all endpoints located under `rest/api/2010`. 31 | 32 | #### Buy and Configure a Phone Number 33 | ```terraform 34 | // 0.16.x 35 | terraform { 36 | required_providers { 37 | twilio = { 38 | source = "twilio/twilio" 39 | version = "0.16.0" 40 | } 41 | } 42 | } 43 | 44 | # Credentials can be found at www.twilio.com/console. 45 | provider "twilio" { 46 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 47 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 48 | } 49 | 50 | resource "twilio_api_accounts_incoming_phone_numbers_v2010" "phone_number" { 51 | area_code = "415" 52 | friendly_name = "terraform phone number" 53 | sms_url = "https://demo.twilio.com/welcome/sms/reply" 54 | voice_url = "https://demo.twilio.com/docs/voice.xml" 55 | } 56 | 57 | output "phone_numbers" { 58 | value = twilio_api_accounts_incoming_phone_numbers_v2010.phone_number 59 | } 60 | ``` 61 | ```terraform 62 | // 0.17.x 63 | terraform { 64 | required_providers { 65 | twilio = { 66 | source = "twilio/twilio" 67 | version = "0.17.0" 68 | } 69 | } 70 | } 71 | 72 | # Credentials can be found at www.twilio.com/console. 73 | provider "twilio" { 74 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 75 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 76 | } 77 | 78 | resource "twilio_api_accounts_incoming_phone_numbers" "phone_number" { 79 | area_code = "415" 80 | friendly_name = "terraform phone number" 81 | sms_url = "https://demo.twilio.com/welcome/sms/reply" 82 | voice_url = "https://demo.twilio.com/docs/voice.xml" 83 | } 84 | 85 | output "phone_numbers" { 86 | value = twilio_api_accounts_incoming_phone_numbers.phone_number 87 | } 88 | ``` 89 | -------------------------------------------------------------------------------- /client/provider.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | client "github.com/twilio/twilio-go" 5 | ) 6 | 7 | // Config is provided as context to the underlying resources. 8 | type Config struct { 9 | Client *client.RestClient 10 | } 11 | -------------------------------------------------------------------------------- /core/form_encoder.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/url" 7 | "reflect" 8 | "strconv" 9 | ) 10 | 11 | func processParamValue(paramType string, form *url.Values, field reflect.StructField, value reflect.Value) error { 12 | tag := field.Tag.Get(paramType) 13 | name, opts := ParseTag(tag) 14 | if name == "" { 15 | name = field.Name 16 | } 17 | 18 | if opts.Contains("ignore") { 19 | return nil 20 | } 21 | 22 | if value.Kind() == reflect.Ptr && value.IsNil() { 23 | if opts.Contains("omitempty") { 24 | return nil 25 | } else { 26 | return CreateErrorGeneric(fmt.Sprintf("Field: %s value cannot be empty or nil", name)) 27 | } 28 | } 29 | 30 | if value.Kind() == reflect.Ptr { 31 | value = value.Elem() 32 | } 33 | 34 | switch value.Kind() { 35 | case reflect.Bool: 36 | form.Add(name, strconv.FormatBool(value.Bool())) 37 | 38 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 39 | form.Add(name, strconv.FormatInt(value.Int(), 10)) 40 | 41 | case reflect.Float32, reflect.Float64: 42 | form.Add(name, fmt.Sprintf("%v", value)) 43 | 44 | case reflect.String: 45 | form.Add(name, value.String()) 46 | 47 | case reflect.Slice: 48 | for i := 0; i < value.Len(); i++ { 49 | if err := processParamValue(paramType, form, field, value.Index(i)); err != nil { 50 | return nil 51 | } 52 | } 53 | 54 | case reflect.Interface: 55 | bytes, err := json.Marshal(value.Interface()) 56 | if err != nil { 57 | return WrapErrorGeneric(err, "Error marshalling "+name) 58 | } 59 | form.Add(name, string(bytes)) 60 | 61 | case reflect.Struct: 62 | if basic, ok := value.Interface().(DecoratedBasicTypeGetterInterface); ok { 63 | if value, ok := basic.GetNativePresentation(); ok { 64 | if err := processParamValue(paramType, form, field, reflect.ValueOf(value)); err != nil { 65 | return nil 66 | } 67 | } 68 | } else if opts.Contains("flatten") { 69 | for i := 0; i < field.Type.NumField(); i++ { 70 | subField := field.Type.Field(i) 71 | subValue := value.Field(i) 72 | 73 | if err := processParamValue(paramType, form, subField, subValue); err != nil { 74 | return err 75 | } 76 | } 77 | } else { 78 | return CreateErrorGeneric(fmt.Sprintf("Field: %s is of invalid struct type", name)) 79 | } 80 | 81 | default: 82 | return CreateErrorGeneric(fmt.Sprintf("Field: %s is of invalid type", name)) 83 | } 84 | return nil 85 | } 86 | 87 | func FormEncoder(src interface{}) (url.Values, error) { 88 | if src == nil { 89 | return nil, CreateErrorGeneric("Nil form provided") 90 | } 91 | 92 | srcType := reflect.TypeOf(src) 93 | if srcType.Kind() != reflect.Struct { 94 | return nil, CreateErrorGeneric(fmt.Sprintf("FormEncoder expects struct input. Got %v", srcType.Kind())) 95 | } 96 | 97 | form := url.Values{} 98 | srcValue := reflect.ValueOf(src) 99 | for i := 0; i < srcType.NumField(); i++ { 100 | field := srcType.Field(i) 101 | fieldValue := srcValue.Field(i) 102 | 103 | if err := processParamValue("form", &form, field, fieldValue); err != nil { 104 | return nil, err 105 | } 106 | } 107 | return form, nil 108 | } 109 | -------------------------------------------------------------------------------- /core/form_encoder_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "net/url" 5 | "reflect" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestProcessFormValueBool(t *testing.T) { 12 | form := url.Values{} 13 | 14 | type testStruct struct { 15 | a bool 16 | } 17 | 18 | testValue := testStruct{a: true} 19 | 20 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 21 | assert.Nil(t, err, "ProcessFormValue failed") 22 | assert.Equal(t, []string{"true"}, form["a"]) 23 | } 24 | 25 | func TestProcessFormValueInt(t *testing.T) { 26 | form := url.Values{} 27 | 28 | type testStruct struct { 29 | a int 30 | } 31 | 32 | testValue := testStruct{a: 1} 33 | 34 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 35 | assert.Nil(t, err, "ProcessFormValue failed") 36 | assert.Equal(t, []string{"1"}, form["a"]) 37 | } 38 | 39 | func TestProcessFormValueFloat(t *testing.T) { 40 | form := url.Values{} 41 | 42 | type testStruct struct { 43 | a float64 44 | } 45 | 46 | testValue := testStruct{a: 1} 47 | 48 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 49 | assert.Nil(t, err, "ProcessFormValue failed") 50 | assert.Equal(t, []string{"1"}, form["a"]) 51 | } 52 | 53 | func TestProcessFormValueString(t *testing.T) { 54 | form := url.Values{} 55 | 56 | type testStruct struct { 57 | a string 58 | } 59 | 60 | testValue := testStruct{a: "str"} 61 | 62 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 63 | assert.Nil(t, err, "ProcessFormValue failed") 64 | assert.Equal(t, []string{"str"}, form["a"]) 65 | } 66 | 67 | func TestProcessFormValueIntList(t *testing.T) { 68 | form := url.Values{} 69 | 70 | type testStruct struct { 71 | a []int 72 | } 73 | 74 | testValue := testStruct{a: []int{1, 2, 3}} 75 | 76 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 77 | assert.Nil(t, err, "ProcessFormValue failed") 78 | assert.Equal(t, []string{"1", "2", "3"}, form["a"]) 79 | } 80 | 81 | func TestProcessFormValueArray(t *testing.T) { 82 | form := url.Values{} 83 | 84 | type testStruct struct { 85 | a [1]int 86 | } 87 | 88 | testValue := testStruct{a: [1]int{1}} 89 | 90 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 91 | assert.NotNil(t, err, "ProcessFormValue Succeeded (failure expected)") 92 | } 93 | 94 | func TestProcessFormValueBasic(t *testing.T) { 95 | form := url.Values{} 96 | 97 | type testStruct struct { 98 | A Sid 99 | } 100 | 101 | sid, _ := CreateSid("XX00112233445566778899aabbccddeeff") 102 | testValue := testStruct{A: sid} 103 | 104 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 105 | assert.Nil(t, err, "ProcessFormValue failed") 106 | assert.Equal(t, []string{"XX00112233445566778899aabbccddeeff"}, form["A"]) 107 | } 108 | 109 | func TestProcessFormValuePtrNil(t *testing.T) { 110 | form := url.Values{} 111 | 112 | type testStruct struct { 113 | A *Sid 114 | } 115 | 116 | testValue := testStruct{A: nil} 117 | 118 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 119 | assert.NotNil(t, err, "ProcessFormValue Succeeded (failure expected)") 120 | } 121 | 122 | func TestProcessFormValuePtrBasic(t *testing.T) { 123 | form := url.Values{} 124 | 125 | type testStruct struct { 126 | A *Sid 127 | } 128 | 129 | sid, _ := CreateSid("XX00112233445566778899aabbccddeeff") 130 | testValue := testStruct{A: &sid} 131 | 132 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 133 | assert.Nil(t, err, "ProcessFormValue failed") 134 | assert.Equal(t, []string{"XX00112233445566778899aabbccddeeff"}, form["A"]) 135 | } 136 | 137 | func TestProcessFormValueJson(t *testing.T) { 138 | form := url.Values{} 139 | 140 | type testStruct struct { 141 | A interface{} 142 | } 143 | 144 | testValue := testStruct{A: map[string]interface{}{"a": 1, "b": "str"}} 145 | 146 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 147 | assert.Nil(t, err, "ProcessFormValue failed") 148 | assert.Equal(t, []string{"{\"a\":1,\"b\":\"str\"}"}, form["A"]) 149 | } 150 | 151 | func TestProcessFormValueName(t *testing.T) { 152 | form := url.Values{} 153 | 154 | type testStruct struct { 155 | a int `form:"b"` 156 | } 157 | 158 | testValue := testStruct{a: 1} 159 | 160 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 161 | assert.Nil(t, err, "ProcessFormValue failed") 162 | assert.Equal(t, []string{"1"}, form["b"]) 163 | } 164 | 165 | func TestProcessFormValueIgnore(t *testing.T) { 166 | form := url.Values{} 167 | 168 | type testStruct struct { 169 | a int `form:",ignore"` 170 | } 171 | 172 | testValue := testStruct{a: 1} 173 | 174 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 175 | assert.Nil(t, err, "ProcessFormValue failed") 176 | _, ok := form["a"] 177 | assert.Equal(t, false, ok, "form is not empty") 178 | } 179 | 180 | func TestProcessFormValueOmitEmpty(t *testing.T) { 181 | form := url.Values{} 182 | 183 | type testStruct struct { 184 | A *Sid `form:",omitempty"` 185 | } 186 | 187 | testValue := testStruct{A: nil} 188 | 189 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 190 | assert.Nil(t, err, "ProcessFormValue failed") 191 | _, ok := form["A"] 192 | assert.Equal(t, false, ok, "form is not empty") 193 | } 194 | 195 | func TestProcessFormValueFlatten(t *testing.T) { 196 | form := url.Values{} 197 | 198 | type testStruct2 struct { 199 | B int 200 | } 201 | 202 | type testStruct struct { 203 | A testStruct2 `form:",flatten"` 204 | } 205 | 206 | testValue := testStruct{A: testStruct2{B: 3}} 207 | 208 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 209 | assert.Nil(t, err, "ProcessFormValue failed") 210 | assert.Equal(t, []string{"3"}, form["B"]) 211 | } 212 | 213 | func TestProcessFormValueNoFlatten(t *testing.T) { 214 | form := url.Values{} 215 | 216 | type testStruct2 struct { 217 | B int 218 | } 219 | 220 | type testStruct struct { 221 | A testStruct2 222 | } 223 | 224 | testValue := testStruct{A: testStruct2{B: 3}} 225 | 226 | err := processParamValue("form", &form, reflect.TypeOf(testValue).Field(0), reflect.ValueOf(testValue).Field(0)) 227 | assert.NotNil(t, err, "ProcessFormValue Succeeded") 228 | } 229 | 230 | func TestFormEncoderSimple(t *testing.T) { 231 | 232 | type testStruct struct { 233 | a int 234 | b int 235 | } 236 | 237 | testValue := testStruct{a: 2, b: 3} 238 | 239 | form, err := FormEncoder(testValue) 240 | assert.Nil(t, err, "FormEncoder failed") 241 | assert.Equal(t, []string{"2"}, form["a"]) 242 | assert.Equal(t, []string{"3"}, form["b"]) 243 | } 244 | 245 | func TestFormEncoderNil(t *testing.T) { 246 | _, err := FormEncoder(nil) 247 | assert.NotNil(t, err, "FormEncoder succeeded") 248 | } 249 | 250 | func TestFormEncoderArray(t *testing.T) { 251 | testValue := []int{1, 2} 252 | _, err := FormEncoder(testValue) 253 | assert.NotNil(t, err, "FormEncoder succeeded") 254 | } 255 | -------------------------------------------------------------------------------- /core/nullable.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | ) 9 | 10 | type NullableString struct { 11 | Valid bool 12 | Value string 13 | } 14 | 15 | type NullableBool struct { 16 | Valid bool 17 | Value bool 18 | } 19 | 20 | type NullableInt struct { 21 | Valid bool 22 | Value int64 23 | } 24 | 25 | type NullableFloat struct { 26 | Valid bool 27 | Value float64 28 | } 29 | 30 | // --- 31 | 32 | // DecoratedBasicTypeInterface 33 | func (nullable NullableString) Get() (interface{}, bool) { 34 | if !nullable.Valid { 35 | return nil, false 36 | } 37 | return "[" + nullable.Value + "]", true 38 | } 39 | 40 | func (nullable NullableString) GetNativePresentation() (interface{}, bool) { 41 | if !nullable.Valid { 42 | return nil, false 43 | } 44 | return nullable.Value, true 45 | } 46 | 47 | func (nullable *NullableString) Set(value interface{}) error { 48 | str, ok := value.(string) 49 | if !ok { 50 | return CreateErrorGeneric(fmt.Sprintf("Invalid type for Set NullablString '%v'", reflect.TypeOf(value))) 51 | } 52 | if str == "" { 53 | nullable.Valid = false 54 | nullable.Value = "" 55 | return nil 56 | } 57 | if len(str) < 2 || str[0] != '[' || str[len(str)-1] != ']' { 58 | nullable.Valid = false 59 | nullable.Value = "" 60 | return CreateErrorGeneric(fmt.Sprintf("Invalid value for Set NullableString '%s'", str)) 61 | } 62 | nullable.Valid = true 63 | nullable.Value = str[1 : len(str)-1] 64 | return nil 65 | } 66 | 67 | // json marshaling 68 | func (nullable NullableString) MarshalJSON() ([]byte, error) { 69 | if !nullable.Valid { 70 | return json.Marshal(nil) 71 | } 72 | return json.Marshal(nullable.Value) 73 | } 74 | 75 | func (nullable *NullableString) UnmarshalJSON(buffer []byte) error { 76 | nullable.Valid = false 77 | nullable.Value = "" 78 | 79 | var value interface{} 80 | if err := json.Unmarshal(buffer, &value); err != nil { 81 | return err 82 | } 83 | if value == nil { 84 | return nil 85 | } 86 | if conv, ok := value.(string); ok { 87 | nullable.Valid = true 88 | nullable.Value = conv 89 | return nil 90 | } 91 | return CreateErrorGeneric(fmt.Sprintf("Invalid type for UnmarshalJSON NullableString '%v'", reflect.TypeOf(value))) 92 | } 93 | 94 | // --- 95 | 96 | func (nullable NullableBool) Get() (interface{}, bool) { 97 | if !nullable.Valid { 98 | return nil, false 99 | } 100 | return strconv.FormatBool(nullable.Value), true 101 | } 102 | 103 | func (nullable NullableBool) GetNativePresentation() (interface{}, bool) { 104 | if !nullable.Valid { 105 | return nil, false 106 | } 107 | return nullable.Value, true 108 | } 109 | 110 | func (nullable *NullableBool) Set(value interface{}) error { 111 | str, ok := value.(string) 112 | if !ok { 113 | return CreateErrorGeneric(fmt.Sprintf("Invalid type for Set NullableBool '%v'", reflect.TypeOf(value))) 114 | } 115 | if str == "" { 116 | nullable.Valid = false 117 | nullable.Value = false 118 | return nil 119 | } 120 | if str == "false" { 121 | nullable.Valid = true 122 | nullable.Value = false 123 | return nil 124 | 125 | } 126 | if str == "true" { 127 | nullable.Valid = true 128 | nullable.Value = true 129 | return nil 130 | 131 | } 132 | return CreateErrorGeneric(fmt.Sprintf("Invalid value for Set NullableBool '%s'", str)) 133 | } 134 | 135 | // json marshaling 136 | func (nullable NullableBool) MarshalJSON() ([]byte, error) { 137 | if !nullable.Valid { 138 | return json.Marshal(nil) 139 | } 140 | return json.Marshal(nullable.Value) 141 | } 142 | 143 | func (nullable *NullableBool) UnmarshalJSON(buffer []byte) error { 144 | nullable.Valid = false 145 | nullable.Value = false 146 | 147 | var value interface{} 148 | if err := json.Unmarshal(buffer, &value); err != nil { 149 | return err 150 | } 151 | if value == nil { 152 | return nil 153 | } 154 | if conv, ok := value.(bool); ok { 155 | nullable.Valid = true 156 | nullable.Value = conv 157 | return nil 158 | } 159 | return CreateErrorGeneric(fmt.Sprintf("Invalid type for UnmarshalJSON NullableBool '%v'", reflect.TypeOf(value))) 160 | } 161 | 162 | // --- 163 | 164 | func (nullable NullableInt) Get() (interface{}, bool) { 165 | if !nullable.Valid { 166 | return nil, false 167 | } 168 | return strconv.FormatInt(nullable.Value, 10), true 169 | } 170 | 171 | func (nullable NullableInt) GetNativePresentation() (interface{}, bool) { 172 | if !nullable.Valid { 173 | return nil, false 174 | } 175 | return nullable.Value, true 176 | } 177 | 178 | func (nullable *NullableInt) Set(value interface{}) error { 179 | str, ok := value.(string) 180 | if !ok { 181 | return CreateErrorGeneric(fmt.Sprintf("Invalid type for Set NullableInt '%v'", reflect.TypeOf(value))) 182 | } 183 | if str == "" { 184 | nullable.Valid = false 185 | nullable.Value = 0 186 | return nil 187 | } 188 | conv, err := strconv.ParseInt(str, 10, 0) 189 | if err != nil { 190 | nullable.Valid = false 191 | nullable.Value = 0 192 | return WrapErrorGeneric(err, "Failed to convert integer value for NullableInt") 193 | } 194 | nullable.Valid = true 195 | nullable.Value = conv 196 | return nil 197 | } 198 | 199 | // json marshaling 200 | func (nullable NullableInt) MarshalJSON() ([]byte, error) { 201 | if !nullable.Valid { 202 | return json.Marshal(nil) 203 | } 204 | return json.Marshal(nullable.Value) 205 | } 206 | 207 | func (nullable *NullableInt) UnmarshalJSON(buffer []byte) error { 208 | nullable.Valid = false 209 | nullable.Value = 0 210 | 211 | var value interface{} 212 | if err := json.Unmarshal(buffer, &value); err != nil { 213 | return err 214 | } 215 | if value == nil { 216 | return nil 217 | } 218 | if conv, ok := value.(float64); ok { 219 | nullable.Valid = true 220 | nullable.Value = (int64)(conv) 221 | return nil 222 | } 223 | return CreateErrorGeneric(fmt.Sprintf("Invalid type for UnmarshalJSON NullableInt '%v'", reflect.TypeOf(value))) 224 | } 225 | 226 | // --- 227 | 228 | func (nullable NullableFloat) Get() (interface{}, bool) { 229 | if !nullable.Valid { 230 | return nil, false 231 | } 232 | return fmt.Sprintf("%v", nullable.Value), true 233 | } 234 | 235 | func (nullable NullableFloat) GetNativePresentation() (interface{}, bool) { 236 | if !nullable.Valid { 237 | return nil, false 238 | } 239 | return nullable.Value, true 240 | } 241 | 242 | func (nullable *NullableFloat) Set(value interface{}) error { 243 | str, ok := value.(string) 244 | if !ok { 245 | return CreateErrorGeneric(fmt.Sprintf("Invalid type for Set NullableFloat '%v'", reflect.TypeOf(value))) 246 | } 247 | if str == "" { 248 | nullable.Valid = false 249 | nullable.Value = 0 250 | return nil 251 | } 252 | conv, err := strconv.ParseFloat(str, 64) 253 | if err != nil { 254 | nullable.Valid = false 255 | nullable.Value = 0 256 | return WrapErrorGeneric(err, "Failed to convert integer value for NullableFloat") 257 | } 258 | nullable.Valid = true 259 | nullable.Value = conv 260 | return nil 261 | } 262 | 263 | // json marshaling 264 | func (nullable NullableFloat) MarshalJSON() ([]byte, error) { 265 | if !nullable.Valid { 266 | return json.Marshal(nil) 267 | } 268 | return json.Marshal(nullable.Value) 269 | } 270 | 271 | func (nullable *NullableFloat) UnmarshalJSON(buffer []byte) error { 272 | nullable.Valid = false 273 | nullable.Value = 0 274 | 275 | var value interface{} 276 | if err := json.Unmarshal(buffer, &value); err != nil { 277 | return err 278 | } 279 | if value == nil { 280 | return nil 281 | } 282 | if conv, ok := value.(float64); ok { 283 | nullable.Valid = true 284 | nullable.Value = conv 285 | return nil 286 | } 287 | return CreateErrorGeneric(fmt.Sprintf("Invalid type for UnmarshalJSON NullableFloat '%v'", reflect.TypeOf(value))) 288 | } 289 | -------------------------------------------------------------------------------- /core/query_encode_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestQueryEncoderSimple(t *testing.T) { 10 | 11 | type testStruct struct { 12 | a int 13 | b int 14 | } 15 | 16 | testValue := testStruct{a: 2, b: 3} 17 | 18 | queryString, err := QueryEncoder(testValue) 19 | assert.Nil(t, err, "QueryEncoder failed") 20 | assert.Contains(t, []string{"?a=2&b=3", "?b=3&a=2"}, queryString) 21 | } 22 | 23 | func TestQueryEncoderNil(t *testing.T) { 24 | _, err := FormEncoder(nil) 25 | assert.NotNil(t, err, "FormEncoder succeeded") 26 | } 27 | 28 | func TestQueryEncoderArray(t *testing.T) { 29 | testValue := []int{1, 2} 30 | _, err := FormEncoder(testValue) 31 | assert.NotNil(t, err, "FormEncoder succeeded") 32 | } 33 | -------------------------------------------------------------------------------- /core/query_encoder.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "reflect" 7 | ) 8 | 9 | func QueryEncoder(src interface{}) (string, error) { 10 | if src == nil { 11 | return "", CreateErrorGeneric("Nil query provided") 12 | } 13 | 14 | srcType := reflect.TypeOf(src) 15 | if srcType.Kind() != reflect.Struct { 16 | return "", CreateErrorGeneric(fmt.Sprintf("QueryEncoder expects struct input. Got %v", srcType.Kind())) 17 | } 18 | 19 | values := url.Values{} 20 | srcValue := reflect.ValueOf(src) 21 | for i := 0; i < srcType.NumField(); i++ { 22 | field := srcType.Field(i) 23 | fieldValue := srcValue.Field(i) 24 | 25 | if err := processParamValue("query", &values, field, fieldValue); err != nil { 26 | return "", err 27 | } 28 | } 29 | 30 | paramString := "" 31 | for key, value := range values { 32 | if len(paramString) > 0 { 33 | paramString += "&" 34 | } else { 35 | paramString = "?" 36 | } 37 | paramString += key + "=" + url.PathEscape(value[0]) 38 | } 39 | return paramString, nil 40 | } 41 | -------------------------------------------------------------------------------- /core/schema.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/go-cty/cty" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | ) 10 | 11 | var ( 12 | SchemaRequired = &options{ 13 | Required: true, 14 | } 15 | 16 | SchemaOptional = &options{ 17 | Optional: true, 18 | } 19 | 20 | SchemaComputed = &options{ 21 | Computed: true, 22 | } 23 | 24 | SchemaComputedOptional = &options{ 25 | Computed: true, 26 | Optional: true, 27 | } 28 | 29 | SchemaComputedSensitive = &options{ 30 | Computed: true, 31 | Sensitive: true, 32 | } 33 | 34 | SchemaForceNewRequired = &options{ 35 | Required: true, 36 | ForceNew: true, 37 | } 38 | 39 | SchemaForceNewOptional = &options{ 40 | ForceNew: true, 41 | Computed: true, 42 | Optional: true, 43 | } 44 | ) 45 | 46 | type options struct { 47 | Optional bool 48 | Required bool 49 | Computed bool 50 | ForceNew bool 51 | Sensitive bool 52 | } 53 | 54 | type SchemaPlus struct { 55 | *schema.Schema 56 | } 57 | 58 | func AsList(obj interface{}, conf *options) *schema.Schema { 59 | var ret *schema.Schema 60 | if item, ok := obj.(*schema.Schema); ok { 61 | // scalar type 62 | // validation is not supported for list items 63 | ret = &schema.Schema{ 64 | Type: schema.TypeList, 65 | Elem: &schema.Schema{ 66 | Type: item.Type, 67 | }, 68 | } 69 | } 70 | if item, ok := obj.(map[string]*schema.Schema); ok { 71 | ret = &schema.Schema{ 72 | Type: schema.TypeList, 73 | Elem: &schema.Resource{ 74 | Schema: item, 75 | }, 76 | } 77 | } 78 | return addSchemaOptions(ret, conf) 79 | } 80 | 81 | func AsString(conf *options) *schema.Schema { 82 | ret := &schema.Schema{ 83 | Type: schema.TypeString, 84 | } 85 | return addSchemaOptions(ret, conf) 86 | } 87 | 88 | func AsMap(obj interface{}, conf *options) *schema.Schema { 89 | var ret *schema.Schema 90 | if item, ok := obj.(*schema.Schema); ok { 91 | ret = &schema.Schema{ 92 | Type: schema.TypeMap, 93 | Elem: &schema.Schema{ 94 | Type: item.Type, 95 | }, 96 | } 97 | } 98 | if item, ok := obj.(map[string]*schema.Schema); ok { 99 | ret = &schema.Schema{ 100 | Type: schema.TypeMap, 101 | Elem: &schema.Resource{ 102 | Schema: item, 103 | }, 104 | } 105 | } 106 | return addSchemaOptions(ret, conf) 107 | } 108 | 109 | func AsBool(conf *options) *schema.Schema { 110 | ret := &schema.Schema{ 111 | Type: schema.TypeBool, 112 | } 113 | return addSchemaOptions(ret, conf) 114 | } 115 | 116 | func AsInt(conf *options) *schema.Schema { 117 | ret := &schema.Schema{ 118 | Type: schema.TypeInt, 119 | } 120 | return addSchemaOptions(ret, conf) 121 | } 122 | 123 | func AsFloat(conf *options) *schema.Schema { 124 | ret := &schema.Schema{ 125 | Type: schema.TypeFloat, 126 | } 127 | return addSchemaOptions(ret, conf) 128 | } 129 | 130 | func AsSid(sid SidInterface, conf *options) *schema.Schema { 131 | ret := &schema.Schema{ 132 | Type: schema.TypeString, 133 | } 134 | if !conf.Computed { 135 | ret.ValidateDiagFunc = func(val interface{}, path cty.Path) diag.Diagnostics { 136 | if err := sid.Set(val); err != nil { 137 | return diag.FromErr(err) 138 | } 139 | return nil 140 | } 141 | } 142 | return addSchemaOptions(ret, conf) 143 | } 144 | 145 | // helper method for schema definition, for each schema item, one of optional, required, or computed must be set 146 | func addSchemaOptions(s *schema.Schema, conf *options) *schema.Schema { 147 | if conf.Computed { 148 | if conf.Required { 149 | panic(fmt.Errorf("computed parameter can't be Required")) 150 | } 151 | } else { 152 | if conf.Optional == conf.Required { 153 | panic(fmt.Errorf("computed and Required are mutually exclusive")) 154 | } 155 | } 156 | s.Optional = conf.Optional 157 | s.Required = conf.Required 158 | s.Computed = conf.Computed 159 | s.ForceNew = conf.ForceNew 160 | s.Sensitive = conf.Sensitive 161 | return s 162 | } 163 | -------------------------------------------------------------------------------- /core/schema_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestRequiredSchema(t *testing.T) { 11 | testSchema := AsInt(SchemaRequired) 12 | assert.Equal(t, false, testSchema.Optional, "Invalid options") 13 | assert.Equal(t, true, testSchema.Required, "Invalid options") 14 | assert.Equal(t, false, testSchema.Computed, "Invalid options") 15 | assert.Equal(t, false, testSchema.ForceNew, "Invalid options") 16 | } 17 | 18 | func TestOptionalSchema(t *testing.T) { 19 | testSchema := AsInt(SchemaOptional) 20 | assert.Equal(t, true, testSchema.Optional, "Invalid options") 21 | assert.Equal(t, false, testSchema.Required, "Invalid options") 22 | assert.Equal(t, false, testSchema.Computed, "Invalid options") 23 | assert.Equal(t, false, testSchema.ForceNew, "Invalid options") 24 | assert.Equal(t, false, testSchema.Sensitive, "Invalid options") 25 | } 26 | 27 | func TestComputedSchema(t *testing.T) { 28 | testSchema := AsInt(SchemaComputed) 29 | assert.Equal(t, false, testSchema.Optional, "Invalid options") 30 | assert.Equal(t, false, testSchema.Required, "Invalid options") 31 | assert.Equal(t, true, testSchema.Computed, "Invalid options") 32 | assert.Equal(t, false, testSchema.ForceNew, "Invalid options") 33 | assert.Equal(t, false, testSchema.Sensitive, "Invalid options") 34 | } 35 | 36 | func TestComputedOptionalSchema(t *testing.T) { 37 | testSchema := AsInt(SchemaComputedOptional) 38 | assert.Equal(t, true, testSchema.Optional, "Invalid options") 39 | assert.Equal(t, false, testSchema.Required, "Invalid options") 40 | assert.Equal(t, true, testSchema.Computed, "Invalid options") 41 | assert.Equal(t, false, testSchema.ForceNew, "Invalid options") 42 | assert.Equal(t, false, testSchema.Sensitive, "Invalid options") 43 | } 44 | 45 | func TestComputedSensitiveSchema(t *testing.T) { 46 | testSchema := AsInt(SchemaComputedSensitive) 47 | assert.Equal(t, false, testSchema.Optional, "Invalid options") 48 | assert.Equal(t, false, testSchema.Required, "Invalid options") 49 | assert.Equal(t, true, testSchema.Computed, "Invalid options") 50 | assert.Equal(t, false, testSchema.ForceNew, "Invalid options") 51 | assert.Equal(t, true, testSchema.Sensitive, "Invalid options") 52 | } 53 | 54 | func TestForceNewRequiredSchemaSchema(t *testing.T) { 55 | testSchema := AsInt(SchemaForceNewRequired) 56 | assert.Equal(t, false, testSchema.Optional, "Invalid options") 57 | assert.Equal(t, true, testSchema.Required, "Invalid options") 58 | assert.Equal(t, false, testSchema.Computed, "Invalid options") 59 | assert.Equal(t, true, testSchema.ForceNew, "Invalid options") 60 | assert.Equal(t, false, testSchema.Sensitive, "Invalid options") 61 | } 62 | 63 | func TestForceNewRequiredOptionalSchema(t *testing.T) { 64 | testSchema := AsInt(SchemaForceNewOptional) 65 | assert.Equal(t, true, testSchema.Optional, "Invalid options") 66 | assert.Equal(t, false, testSchema.Required, "Invalid options") 67 | assert.Equal(t, true, testSchema.ForceNew, "Invalid options") 68 | assert.Equal(t, false, testSchema.Sensitive, "Invalid options") 69 | } 70 | 71 | func TestInvalidEmptySchema(t *testing.T) { 72 | defer func() { _ = recover() }() 73 | AsInt(&options{}) 74 | t.Errorf("Invalid schema allowed") 75 | } 76 | 77 | func TestInvalidComputedRequiredSchema(t *testing.T) { 78 | defer func() { _ = recover() }() 79 | AsInt(&options{Required: true, Computed: true}) 80 | t.Errorf("Invalid schema allowed") 81 | } 82 | 83 | func TestStringSchema(t *testing.T) { 84 | s := AsString(SchemaRequired) 85 | assert.Equal(t, schema.TypeString, s.Type, "Invalid type") 86 | } 87 | 88 | func TestStringBool(t *testing.T) { 89 | s := AsBool(SchemaRequired) 90 | assert.Equal(t, schema.TypeBool, s.Type, "Invalid type") 91 | } 92 | 93 | func TestIntSchema(t *testing.T) { 94 | s := AsInt(SchemaRequired) 95 | assert.Equal(t, schema.TypeInt, s.Type, "Invalid type") 96 | } 97 | 98 | func TestFloatSchema(t *testing.T) { 99 | s := AsFloat(SchemaRequired) 100 | assert.Equal(t, schema.TypeFloat, s.Type, "Invalid type") 101 | } 102 | 103 | func TestSidSchema(t *testing.T) { 104 | s := AsSid(&Sid{}, SchemaRequired) 105 | assert.Equal(t, schema.TypeString, s.Type, "Invalid type") 106 | 107 | err := s.ValidateDiagFunc("XX00112233445566778899aabbccddeeff", nil) 108 | assert.Empty(t, err, "Sid errored") 109 | 110 | err = s.ValidateDiagFunc("abc", nil) 111 | assert.NotEmpty(t, err, "Sid validate did not error") 112 | } 113 | 114 | func TestListSchemaScalar(t *testing.T) { 115 | s := AsList(AsInt(SchemaRequired), SchemaRequired) 116 | assert.Equal(t, schema.TypeList, s.Type, "Invalid type") 117 | assert.Equal(t, schema.TypeInt, s.Elem.(*schema.Schema).Type, "Invalid type") 118 | } 119 | 120 | func TestListSchemaComplex(t *testing.T) { 121 | mapSchema := map[string]*schema.Schema{"test1": AsInt(SchemaRequired)} 122 | s := AsList(mapSchema, SchemaRequired) 123 | assert.Equal(t, schema.TypeList, s.Type, "Invalid type") 124 | assert.Equal(t, mapSchema, s.Elem.(*schema.Resource).Schema, "Invalid type") 125 | } 126 | -------------------------------------------------------------------------------- /core/tags.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "strings" 4 | 5 | type TagOptions []string 6 | 7 | func ParseTag(tag string) (string, TagOptions) { 8 | ret := strings.Split(tag, ",") 9 | return ret[0], ret[1:] 10 | } 11 | 12 | func (o TagOptions) Contains(option string) bool { 13 | for _, tag := range o { 14 | if tag == option { 15 | return true 16 | } 17 | } 18 | return false 19 | } 20 | -------------------------------------------------------------------------------- /core/twilio_error.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var TwilioErrorGeneric = errTwilio() 9 | 10 | func errTwilio() error { 11 | return TwilioError{} 12 | } 13 | 14 | // TwilioError provides information about an unsuccessful request. 15 | type TwilioError struct { 16 | Cause error 17 | Status int 18 | Code int `json:"code"` 19 | Message string `json:"message"` 20 | } 21 | 22 | func (err TwilioError) Error() string { 23 | return fmt.Sprintf("Status: %d - Error %d: %s", 24 | err.Status, err.Code, err.Message) 25 | } 26 | 27 | func (err TwilioError) Is(target error) bool { 28 | _, ok := target.(TwilioError) 29 | return ok 30 | } 31 | 32 | func WrapError(err error, status int, code int, message string) error { 33 | return TwilioError{ 34 | Cause: err, 35 | Status: status, 36 | Code: code, 37 | Message: message, 38 | } 39 | } 40 | 41 | func WrapErrorStatus(err error, status int, message string) error { 42 | return WrapError(err, status, 45001, message) 43 | } 44 | 45 | func WrapErrorGeneric(err error, message string) error { 46 | return WrapError(err, 500, 45001, message) 47 | } 48 | 49 | func CreateErrorGeneric(message string) error { 50 | return WrapError(errors.New(""), 500, 45001, message) 51 | } 52 | -------------------------------------------------------------------------------- /core/types.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "strconv" 4 | 5 | func IntToString(input int) string { 6 | return strconv.Itoa(input) 7 | } 8 | 9 | func StringToInt(input string) (int, error) { 10 | return strconv.Atoi(input) 11 | } 12 | -------------------------------------------------------------------------------- /core/types_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIntToString(t *testing.T) { 10 | assert.Equal(t, "123", IntToString(123)) 11 | assert.Equal(t, "0", IntToString(0)) 12 | assert.Equal(t, "-123", IntToString(-123)) 13 | } 14 | 15 | func TestStringToInt(t *testing.T) { 16 | value, err := StringToInt("123") 17 | assert.Nil(t, err) 18 | assert.Equal(t, 123, value) 19 | 20 | value, err = StringToInt("0") 21 | assert.Nil(t, err) 22 | assert.Equal(t, 0, value) 23 | 24 | value, err = StringToInt("-123") 25 | assert.Nil(t, err) 26 | assert.Equal(t, -123, value) 27 | 28 | _, err = StringToInt("blurg") 29 | assert.NotNil(t, err) 30 | } 31 | -------------------------------------------------------------------------------- /examples/api/v2010/apicore.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | // account_sid defaults to TWILIO_SUBACCOUNT_SID with TWILIO_ACCOUNT_SID as the fallback env var 14 | } 15 | 16 | 17 | resource "twilio_api_accounts_incoming_phone_numbers" "phone_number" { 18 | area_code = "415" 19 | friendly_name = "terraform phone number" 20 | sms_url = "https://demo.twilio.com/welcome/sms/reply" 21 | voice_url = "https://demo.twilio.com/docs/voice.xml" 22 | } 23 | 24 | 25 | resource "twilio_api_accounts_messages" "message" { 26 | path_account_sid = "AC123456123456123456123456123456" 27 | from = twilio_api_accounts_incoming_phone_numbers.phone_number.phone_number 28 | to = "4444444444" 29 | body = "Hello from Twilio Terraform!" 30 | } 31 | 32 | resource "twilio_api_accounts_calls" "call" { 33 | from = twilio_api_accounts_incoming_phone_numbers.phone_number.phone_number 34 | to = "4444444444" 35 | twiml = "Hello World" 36 | } 37 | 38 | output "phone_numbers" { 39 | value = twilio_api_accounts_incoming_phone_numbers.phone_number 40 | } 41 | 42 | output "messages" { 43 | value = twilio_api_accounts_messages.message 44 | } 45 | 46 | output "calls" { 47 | value = twilio_api_accounts_calls.call 48 | } 49 | 50 | -------------------------------------------------------------------------------- /examples/autopilot/v1/autopilot.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | resource "twilio_autopilot_assistants_v1" "assistant" { 16 | unique_name = "GreetingsBot" 17 | development_stage = "in-production" 18 | } 19 | 20 | resource "twilio_autopilot_assistants_tasks_v1" "greeting" { 21 | unique_name = "greeting" 22 | assistant_sid = twilio_autopilot_assistants_v1.assistant.sid 23 | actions = jsonencode( 24 | { 25 | actions : [ 26 | { 27 | collect : { 28 | name : "get_name", 29 | questions : [ 30 | { 31 | name : "name", 32 | question : "Hi! Who do I have the pleasure of speaking to?" 33 | } 34 | ], 35 | on_complete : { 36 | redirect : "https://example.com/collect" 37 | } 38 | } 39 | } 40 | ] 41 | }) 42 | } 43 | 44 | variable "greeting_samples" { 45 | type = list(string) 46 | default = [ 47 | "hi", 48 | "hello", 49 | ] 50 | } 51 | 52 | resource "twilio_autopilot_assistants_tasks_samples_v1" "greeting_sample" { 53 | for_each = toset(var.greeting_samples) 54 | assistant_sid = twilio_autopilot_assistants_v1.assistant.sid 55 | task_sid = twilio_autopilot_assistants_tasks_v1.greeting.sid 56 | language = "en-US" 57 | tagged_text = each.value 58 | } 59 | 60 | resource "twilio_autopilot_assistants_model_builds_v1" "build" { 61 | assistant_sid = twilio_autopilot_assistants_v1.assistant.sid 62 | depends_on = [ 63 | twilio_autopilot_assistants_tasks_samples_v1.greeting_sample 64 | ] 65 | } 66 | 67 | output "assistant" { 68 | value = twilio_autopilot_assistants_v1.assistant 69 | } 70 | -------------------------------------------------------------------------------- /examples/bulkexports/v1/bulkexports.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // account_sid defaults to TWILIO_ACCOUNT_SID env var 12 | // auth_token defaults to TWILIO_AUTH_TOKEN env var 13 | } 14 | 15 | 16 | resource "twilio_bulkexports_exports_jobs_v1" "job" { 17 | resource_type = "Messages" 18 | end_day = "2021-09-09" 19 | friendly_name = "Bulk test" 20 | start_day = "2021-04-04" 21 | } 22 | 23 | 24 | output "jobs" { 25 | value = twilio_bulkexports_exports_jobs_v1.job 26 | } 27 | 28 | -------------------------------------------------------------------------------- /examples/chat/v2/chat.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | # Configure chat service 16 | resource "twilio_chat_services_v2" "chat_service" { 17 | friendly_name = "Chat Service" 18 | read_status_enabled = false 19 | reachability_enabled = true 20 | typing_indicator_timeout = 60 21 | notifications_new_message_enabled = true 22 | notifications_new_message_badge_count_enabled = true 23 | notifications_added_to_channel_enabled = true 24 | notifications_added_to_channel_template = true 25 | media_compatibility_message = "Media message has no text!" 26 | limits_user_channels = 50 27 | limits_channel_members = 50 28 | webhook_filters = ["onMessageSend", "onMessageSent"] 29 | } 30 | 31 | # Create channels 32 | resource "twilio_chat_services_channels_v2" "customer_channel" { 33 | service_sid = twilio_chat_services_v2.chat_service.sid 34 | friendly_name = "Customer Chat" 35 | } 36 | resource "twilio_chat_services_channels_v2" "employee_channel" { 37 | service_sid = twilio_chat_services_v2.chat_service.sid 38 | friendly_name = "Employee Chat" 39 | } 40 | 41 | # Create an employee role 42 | resource "twilio_chat_services_roles_v2" "employee_role" { 43 | service_sid = twilio_chat_services_v2.chat_service.sid 44 | friendly_name = "Employee" 45 | type = "deployment" 46 | permission = ["createChannel", "deleteAnyMessage", "destroyChannel", "removeMember"] 47 | } 48 | 49 | # Create members 50 | resource "twilio_chat_services_users_v2" "alice_chat_member" { 51 | service_sid = twilio_chat_services_v2.chat_service.sid 52 | identity = "Alice" 53 | friendly_name = "Alice Smith" 54 | } 55 | 56 | resource "twilio_chat_services_users_v2" "bob_chat_member" { 57 | service_sid = twilio_chat_services_v2.chat_service.sid 58 | role_sid = twilio_chat_services_roles_v2.employee_role.sid 59 | identity = "Bob" 60 | friendly_name = "Bob Williams" 61 | } 62 | 63 | resource "twilio_chat_services_users_v2" "lisa_chat_member" { 64 | service_sid = twilio_chat_services_v2.chat_service.sid 65 | role_sid = twilio_chat_services_roles_v2.employee_role.sid 66 | identity = "Lisa" 67 | friendly_name = "Lisa Doe" 68 | } 69 | 70 | # Add members to Customer Chat channel 71 | resource "twilio_chat_services_channels_members_v2" "add_alice_to_customer_channel" { 72 | service_sid = twilio_chat_services_v2.chat_service.sid 73 | channel_sid = twilio_chat_services_channels_v2.customer_channel.sid 74 | identity = "Alice" 75 | } 76 | 77 | resource "twilio_chat_services_channels_members_v2" "add_bob_to_customer_channel" { 78 | service_sid = twilio_chat_services_v2.chat_service.sid 79 | channel_sid = twilio_chat_services_channels_v2.customer_channel.sid 80 | identity = "Bob" 81 | } 82 | 83 | # Add members to Employee Chat channel 84 | resource "twilio_chat_services_channels_members_v2" "add_bob_to_employee_channel" { 85 | service_sid = twilio_chat_services_v2.chat_service.sid 86 | channel_sid = twilio_chat_services_channels_v2.employee_channel.sid 87 | identity = "Bob" 88 | } 89 | 90 | resource "twilio_chat_services_channels_members_v2" "add_lisa_to_employee_channel" { 91 | service_sid = twilio_chat_services_v2.chat_service.sid 92 | channel_sid = twilio_chat_services_channels_v2.employee_channel.sid 93 | identity = "Lisa" 94 | } 95 | 96 | # Populate with initial chat 97 | resource "twilio_chat_services_channels_messages_v2" "initial_message" { 98 | service_sid = twilio_chat_services_v2.chat_service.sid 99 | channel_sid = twilio_chat_services_channels_v2.customer_channel.sid 100 | body = "Welcome to our service chat! How can I help you today?" 101 | from = "Bob" 102 | } 103 | -------------------------------------------------------------------------------- /examples/events/v1/events.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | # Step 1: Create an Event Sink 16 | # There are two types of Sinks you can create: Kinesis and Webhook 17 | 18 | # Type 1: Kinesis Sink 19 | resource "twilio_events_sinks_v1" "kinesis" { 20 | description = "Kinesis Sink" 21 | sink_configuration = jsonencode({ 22 | arn : "arn:aws:kinesis:us-east-1:111111111:stream/test", 23 | role_arn : "arn:aws:iam::111111111:role/Role", 24 | external_id : "1234567890" 25 | }) 26 | sink_type = "kinesis" 27 | } 28 | 29 | # Type 2: Webhook Sink 30 | resource "twilio_events_sinks_v1" "webhook" { 31 | description = "Webhook Sink" 32 | sink_configuration = jsonencode({ 33 | destination : "http://example.org/webhook", 34 | method : "POST", 35 | batch_events : false 36 | }) 37 | sink_type = "webhook" 38 | } 39 | 40 | # Step 2: Subscribe to Twilio Events 41 | # For simplicity, this example will continue with our Webhook sink 42 | resource "twilio_events_subscriptions_v1" "message_status" { 43 | description = "Message Status Events Subscription" 44 | sink_sid = twilio_events_sinks_v1.webhook.sid 45 | types = [jsonencode({ 46 | type = "com.twilio.messaging.message.queued" 47 | })] 48 | } 49 | 50 | resource "twilio_events_subscriptions_v1" "call_summary" { 51 | description = "Call Summary Events Subscription" 52 | sink_sid = twilio_events_sinks_v1.webhook.sid 53 | types = [jsonencode({ 54 | type = "com.twilio.voice.insights.call-summary.partial" 55 | })] 56 | } 57 | 58 | variable "message_status_event_types" { 59 | type = list(string) 60 | default = [ 61 | "com.twilio.messaging.message.sent", 62 | "com.twilio.messaging.message.delivered", 63 | "com.twilio.messaging.message.failed", 64 | "com.twilio.messaging.message.undelivered", 65 | "com.twilio.messaging.message.read", 66 | ] 67 | } 68 | 69 | resource "twilio_events_subscriptions_subscribed_events_v1" "message_status_event" { 70 | subscription_sid = twilio_events_subscriptions_v1.message_status.sid 71 | for_each = toset(var.message_status_event_types) 72 | type = each.key 73 | } 74 | 75 | variable "call_summary_event_types" { 76 | type = list(string) 77 | default = [ 78 | "com.twilio.voice.insights.call-summary.predicted-complete", 79 | "com.twilio.voice.insights.call-summary.complete", 80 | ] 81 | } 82 | 83 | resource "twilio_events_subscriptions_subscribed_events_v1" "call_summary_event" { 84 | subscription_sid = twilio_events_subscriptions_v1.call_summary.sid 85 | for_each = toset(var.call_summary_event_types) 86 | type = each.key 87 | } 88 | 89 | output "sink" { 90 | value = twilio_events_sinks_v1.webhook 91 | } 92 | 93 | output "message_subscription" { 94 | value = twilio_events_subscriptions_v1.message_status 95 | } 96 | 97 | output "call_subscription" { 98 | value = twilio_events_subscriptions_v1.call_summary 99 | } 100 | -------------------------------------------------------------------------------- /examples/flex/flex_setup.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | resource "twilio_chat_services_v2" "chat_service" { 16 | friendly_name = "Flex Chat Service" 17 | webhook_filters = [ 18 | "onMessageSent", 19 | "onChannelDestroyed", 20 | "onChannelUpdated"] 21 | reachability_enabled = true 22 | read_status_enabled = true 23 | } 24 | 25 | resource "twilio_studio_flows_v2" "flow" { 26 | commit_message = "first draft" 27 | friendly_name = "terraform flow 1" 28 | status = "draft" 29 | definition = jsonencode({ 30 | description = "A New Flow", 31 | states = [ 32 | { 33 | name = "Trigger" 34 | type = "trigger" 35 | transitions = [] 36 | properties = { 37 | offset = { 38 | x = 0 39 | y = 0 40 | } 41 | } 42 | }] 43 | initial_state = "Trigger" 44 | flags = { 45 | allow_concurrent_calls = true 46 | } 47 | }) 48 | } 49 | 50 | resource "twilio_flex_flex_flows_v1" "flows" { 51 | friendly_name = "Test Twilio flex flow" 52 | chat_service_sid = twilio_chat_services_v2.chat_service.id 53 | channel_type = "sms" 54 | integration_flow_sid = twilio_studio_flows_v2.flow.id 55 | contact_identity = "true" 56 | enabled = true 57 | } 58 | 59 | output "flex_flows" { 60 | value = twilio_flex_flex_flows_v1.flows 61 | } 62 | 63 | output "studio_flows" { 64 | value = twilio_studio_flows_v2.flow 65 | } 66 | 67 | output "chat_service" { 68 | value = twilio_chat_services_v2.chat_service 69 | } 70 | -------------------------------------------------------------------------------- /examples/flex/v1/README.md: -------------------------------------------------------------------------------- 1 | # Configuring Flex with Terraform 2 | 3 | ## Importing an existing Flex project 4 | 5 | To import existing Flex resources into terraform, we need to know the SIDs of the default resources that are created for you when a new Flex instance is created. Start by exporting your Flex configuration using the Twilio CLI: 6 | ```bash 7 | twilio api:flex:v1:configuration:fetch \ 8 | --properties=chatServiceInstanceSid,taskrouterWorkspaceSid,taskrouterTargetTaskqueueSid,taskrouterTargetWorkflowSid,taskrouterOfflineActivitySid 9 | ``` 10 | 11 | Next, we need to add placeholders for these resources in our Twilio Terraform configuration file 12 | ```terraform 13 | resource "twilio_chat_services_v2" "flex_chat_service" {} 14 | 15 | resource "twilio_taskrouter_workspaces_v1" "flex_task_assignment" {} 16 | 17 | resource "twilio_taskrouter_workspaces_task_queues_v1" "everyone" { 18 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 19 | } 20 | 21 | resource "twilio_taskrouter_workspaces_workflows_v1" "assign_to_anyone" { 22 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 23 | } 24 | 25 | resource "twilio_taskrouter_workspaces_activities_v1" "offline" { 26 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 27 | } 28 | 29 | ``` 30 | 31 | Taskrouter also creates some other default Activities. We'll need to import these as well to our configuration: 32 | ```terraform 33 | resource "twilio_taskrouter_workspaces_activities_v1" "available" { 34 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 35 | } 36 | 37 | resource "twilio_taskrouter_workspaces_activities_v1" "unavailable" { 38 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 39 | } 40 | 41 | resource "twilio_taskrouter_workspaces_activities_v1" "break" { 42 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 43 | } 44 | ``` 45 | 46 | We can use the Twilio CLI to obtain the SIDs for these resources: 47 | ```bash 48 | twilio api:taskrouter:v1:workspaces:activities:list --workspace-sid= 49 | ``` 50 | Note that the `` used in this command is the "Taskrouter Workspace SID" value obtained from the CLI call above. 51 | 52 | Once you have configurations for each of your existing resources, you'll need to import each resource using `terraform import`, mapping each one its corresponding SID from the CLI output: 53 | ```bash 54 | terraform import twilio_chat_services_v2.flex_chat_service 55 | terraform import twilio_taskrouter_workspaces_v1.flex_task_assignment 56 | terraform import twilio_taskrouter_workspaces_task_queues_v1.everyone / 57 | terraform import twilio_taskrouter_workspaces_workflows_v1.assign_to_everyone / 58 | terraform import twilio_taskrouter_workspaces_activities_v1.offline / 59 | terraform import twilio_taskrouter_workspaces_activities_v1.available / 60 | terraform import twilio_taskrouter_workspaces_activities_v1.unavailable / 61 | terraform import twilio_taskrouter_workspaces_activities_v1.break / 62 | ``` 63 | 64 | Repeat these steps as necessary for any other resources you've already created for your Flex workspace. You can inspect your imported resources by running `terraform show` 65 | -------------------------------------------------------------------------------- /examples/flex/v1/flex_import_default.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | resource "twilio_chat_services_v2" "flex_chat_service" {} 16 | 17 | resource "twilio_taskrouter_workspaces_v1" "flex_task_assignment" {} 18 | 19 | resource "twilio_taskrouter_workspaces_task_queues_v1" "everyone" { 20 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 21 | } 22 | 23 | resource "twilio_taskrouter_workspaces_workflows_v1" "assign_to_anyone" { 24 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 25 | } 26 | 27 | resource "twilio_taskrouter_workspaces_activities_v1" "offline" { 28 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 29 | } 30 | 31 | resource "twilio_taskrouter_workspaces_activities_v1" "available" { 32 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 33 | } 34 | 35 | resource "twilio_taskrouter_workspaces_activities_v1" "unavailable" { 36 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 37 | } 38 | 39 | resource "twilio_taskrouter_workspaces_activities_v1" "break" { 40 | workspace_sid = twilio_taskrouter_workspaces_v1.flex_task_assignment.sid 41 | } 42 | -------------------------------------------------------------------------------- /examples/notify/v1/notify.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // account_sid defaults to TWILIO_ACCOUNT_SID env var 12 | // auth_token defaults to TWILIO_AUTH_TOKEN env var 13 | } 14 | 15 | resource "twilio_notify_services_v1" "service" { 16 | } 17 | 18 | resource "twilio_notify_services_bindings_v1" "binding" { 19 | service_sid = twilio_notify_services_v1.service.sid 20 | address = "9999999999" 21 | binding_type = "apn" 22 | identity = "test" 23 | } 24 | 25 | 26 | output "services" { 27 | value = twilio_notify_services_v1.service 28 | } 29 | 30 | output "jobs" { 31 | value = twilio_notify_services_bindings_v1.binding 32 | } 33 | 34 | -------------------------------------------------------------------------------- /examples/proxy/v1/proxy.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | # Step 1: Purchase 2 phone numbers -- these are going to be the participants 16 | resource "twilio_api_accounts_incoming_phone_numbers" "alice_phone" { 17 | area_code = "415" 18 | friendly_name = "Alice's Phone" 19 | } 20 | 21 | resource "twilio_api_accounts_incoming_phone_numbers" "bob_phone" { 22 | area_code = "908" 23 | friendly_name = "Bob's Phone" 24 | } 25 | 26 | # Create some proxy phone numbers to be added into the service/session pool 27 | resource "twilio_api_accounts_incoming_phone_numbers" "proxy_phone_dev_1" { 28 | area_code = "908" 29 | friendly_name = "Proxy Phone Dev 1" 30 | } 31 | 32 | resource "twilio_api_accounts_incoming_phone_numbers" "proxy_phone_dev_2" { 33 | area_code = "908" 34 | friendly_name = "Proxy Phone Dev 2" 35 | } 36 | 37 | resource "twilio_api_accounts_incoming_phone_numbers" "proxy_phone_stage_1" { 38 | area_code = "415" 39 | friendly_name = "Proxy Phone Stage 1" 40 | } 41 | 42 | resource "twilio_api_accounts_incoming_phone_numbers" "proxy_phone_stage_2" { 43 | area_code = "415" 44 | friendly_name = "Proxy Phone Stage 2" 45 | } 46 | 47 | # Create chat services 48 | resource "twilio_chat_services_v2" "chat_service_dev" { 49 | friendly_name = "Chat Dev" 50 | read_status_enabled = true 51 | reachability_enabled = true 52 | typing_indicator_timeout = 60 53 | notifications_new_message_enabled = true 54 | notifications_new_message_badge_count_enabled = true 55 | notifications_added_to_channel_enabled = true 56 | notifications_added_to_channel_template = true 57 | media_compatibility_message = "Media message has no text!" 58 | limits_user_channels = 50 59 | limits_channel_members = 50 60 | webhook_filters = ["onMessageSend", "onMessageSent"] 61 | } 62 | 63 | resource "twilio_chat_services_v2" "chat_service_stage" { 64 | friendly_name = "Chat Stage" 65 | read_status_enabled = true 66 | reachability_enabled = true 67 | typing_indicator_timeout = 60 68 | notifications_new_message_enabled = true 69 | notifications_new_message_badge_count_enabled = true 70 | notifications_added_to_channel_enabled = true 71 | notifications_added_to_channel_template = true 72 | media_compatibility_message = "Media message has no text!" 73 | limits_user_channels = 50 74 | limits_channel_members = 50 75 | webhook_filters = ["onMessageSend", "onMessageSent"] 76 | } 77 | 78 | 79 | # Create 2 proxy services for both 80 | resource "twilio_proxy_services_v1" "dev_proxy_service" { 81 | unique_name = "Dev Proxy Service" 82 | chat_instance_sid = twilio_chat_services_v2.chat_service_dev.sid 83 | number_selection_behavior = "prefer-sticky" 84 | geo_match_level = "country" 85 | default_ttl = 3600 86 | } 87 | 88 | resource "twilio_proxy_services_v1" "stage_proxy_service" { 89 | unique_name = "Stage Proxy Service" 90 | chat_instance_sid = twilio_chat_services_v2.chat_service_stage.sid 91 | number_selection_behavior = "avoid-sticky" 92 | geo_match_level = "country" 93 | default_ttl = 3600 94 | } 95 | 96 | # Add the proxy phone numbers to the service 97 | resource "twilio_proxy_services_phone_numbers_v1" "proxy_phone_dev_service_1" { 98 | service_sid = twilio_proxy_services_v1.dev_proxy_service.sid 99 | phone_number = twilio_api_accounts_incoming_phone_numbers.proxy_phone_dev_1.phone_number 100 | is_reserved = false 101 | } 102 | 103 | resource "twilio_proxy_services_phone_numbers_v1" "proxy_phone_dev_service_2" { 104 | service_sid = twilio_proxy_services_v1.dev_proxy_service.sid 105 | phone_number = twilio_api_accounts_incoming_phone_numbers.proxy_phone_dev_2.phone_number 106 | is_reserved = false 107 | } 108 | 109 | resource "twilio_proxy_services_phone_numbers_v1" "proxy_phone_stage_service_1" { 110 | service_sid = twilio_proxy_services_v1.stage_proxy_service.sid 111 | phone_number = twilio_api_accounts_incoming_phone_numbers.proxy_phone_stage_1.phone_number 112 | is_reserved = false 113 | } 114 | 115 | resource "twilio_proxy_services_phone_numbers_v1" "proxy_phone_stage_service_2" { 116 | service_sid = twilio_proxy_services_v1.stage_proxy_service.sid 117 | phone_number = twilio_api_accounts_incoming_phone_numbers.proxy_phone_stage_2.phone_number 118 | is_reserved = false 119 | } 120 | 121 | # Create a session and add Alice and Bob as participants so they can talk to each other via the proxy phone numbers 122 | resource "twilio_proxy_services_sessions_v1" "dev_session" { 123 | service_sid = twilio_proxy_services_v1.dev_proxy_service.sid 124 | unique_name = "Alice Proxy Session" 125 | depends_on = [ 126 | twilio_proxy_services_phone_numbers_v1.proxy_phone_dev_service_1, 127 | twilio_proxy_services_phone_numbers_v1.proxy_phone_dev_service_2 128 | ] 129 | participants = [ 130 | jsonencode({ 131 | friendly_name : "Alice" 132 | identifier : twilio_api_accounts_incoming_phone_numbers.alice_phone.phone_number 133 | }), 134 | jsonencode({ 135 | friendly_name : "Bob" 136 | identifier : twilio_api_accounts_incoming_phone_numbers.bob_phone.phone_number 137 | }), 138 | ] 139 | } 140 | 141 | resource "twilio_proxy_services_sessions_v1" "stage_session" { 142 | service_sid = twilio_proxy_services_v1.stage_proxy_service.sid 143 | unique_name = "Bob Proxy Session" 144 | depends_on = [ 145 | twilio_proxy_services_phone_numbers_v1.proxy_phone_stage_service_1, 146 | twilio_proxy_services_phone_numbers_v1.proxy_phone_stage_service_2 147 | ] 148 | participants = [ 149 | jsonencode({ 150 | friendly_name : "Alice" 151 | identifier : twilio_api_accounts_incoming_phone_numbers.alice_phone.phone_number 152 | }), 153 | jsonencode({ 154 | friendly_name : "Bob" 155 | identifier : twilio_api_accounts_incoming_phone_numbers.bob_phone.phone_number 156 | }), 157 | ] 158 | } 159 | 160 | output "dev_service" { 161 | value = twilio_proxy_services_v1.dev_proxy_service 162 | } 163 | 164 | output "stage_service" { 165 | value = twilio_proxy_services_v1.stage_proxy_service 166 | } 167 | -------------------------------------------------------------------------------- /examples/serverless/v1/serverless.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | resource "twilio_serverless_services_v1" "service" { 16 | friendly_name = "Terraform service" 17 | unique_name = "uniqueName" 18 | } 19 | 20 | resource "twilio_serverless_services_functions_v1" "function" { 21 | service_sid = twilio_serverless_services_v1.service.sid //service_sid from new service 22 | friendly_name = "My serverless func" 23 | } 24 | 25 | resource "twilio_serverless_services_environments_v1" "environment" { 26 | service_sid = twilio_serverless_services_v1.service.sid 27 | unique_name = "environment-dummy" 28 | domain_suffix = "com" 29 | } 30 | 31 | output "services" { 32 | value = twilio_serverless_services_v1.service 33 | } 34 | 35 | output "functions" { 36 | value = twilio_serverless_services_functions_v1.function 37 | } 38 | 39 | output "environments" { 40 | value = twilio_serverless_services_environments_v1.environment 41 | } 42 | -------------------------------------------------------------------------------- /examples/studio/v2/studio.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | resource "twilio_studio_flows_v2" "flow" { 16 | commit_message = "first draft" 17 | friendly_name = "terraform flow" 18 | status = "draft" 19 | definition = jsonencode({ 20 | description = "A New Flow", 21 | states = [ 22 | { 23 | name = "Trigger" 24 | type = "trigger" 25 | transitions = [] 26 | properties = { 27 | offset = { 28 | x = 0 29 | y = 0 30 | } 31 | } 32 | }] 33 | initial_state = "Trigger" 34 | flags = { 35 | allow_concurrent_calls = true 36 | } 37 | }) 38 | } 39 | 40 | output "flows" { 41 | value = twilio_studio_flows_v2.flow 42 | } 43 | -------------------------------------------------------------------------------- /examples/taskrouter/v1/taskrouter.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | resource "twilio_taskrouter_workspaces_v1" "demo" { 16 | friendly_name = "demoWorkspace" 17 | } 18 | 19 | resource "twilio_taskrouter_workspaces_activities_v1" "offline" { 20 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 21 | friendly_name = "OfflineCustom" 22 | available = false 23 | } 24 | 25 | resource "twilio_taskrouter_workspaces_activities_v1" "idle" { 26 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 27 | friendly_name = "Idle" 28 | available = true 29 | } 30 | 31 | resource "twilio_taskrouter_workspaces_activities_v1" "busy" { 32 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 33 | friendly_name = "Busy" 34 | available = false 35 | } 36 | 37 | resource "twilio_taskrouter_workspaces_activities_v1" "reserved" { 38 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 39 | friendly_name = "Reserved" 40 | available = false 41 | } 42 | 43 | resource "twilio_taskrouter_workspaces_workers_v1" "alice" { 44 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 45 | friendly_name = "Alice" 46 | activity_sid = twilio_taskrouter_workspaces_activities_v1.offline.sid 47 | attributes = jsonencode({ 48 | "languages" : [ 49 | "en", 50 | "es" 51 | ] 52 | }) 53 | } 54 | 55 | resource "twilio_taskrouter_workspaces_workers_v1" "bob" { 56 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 57 | friendly_name = "Bob" 58 | activity_sid = twilio_taskrouter_workspaces_activities_v1.offline.sid 59 | attributes = jsonencode({ 60 | "languages" : [ 61 | "en" 62 | ] 63 | }) 64 | } 65 | 66 | resource "twilio_taskrouter_workspaces_task_queues_v1" "spanish" { 67 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 68 | friendly_name = "Spanish" 69 | target_workers = "languages HAS \"es\"" 70 | } 71 | 72 | resource "twilio_taskrouter_workspaces_task_queues_v1" "english" { 73 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 74 | friendly_name = "English" 75 | target_workers = "languages HAS \"en\"" 76 | } 77 | 78 | resource "twilio_taskrouter_workspaces_workflows_v1" "flow" { 79 | workspace_sid = twilio_taskrouter_workspaces_v1.demo.sid 80 | friendly_name = "Flow" 81 | configuration = jsonencode({ 82 | task_routing : { 83 | filters : [ 84 | { 85 | filter_friendly_name : "Language - Spanish", 86 | expression : "selected_language == \"es\"", 87 | targets : [ 88 | { 89 | queue : twilio_taskrouter_workspaces_task_queues_v1.spanish.sid 90 | } 91 | ] 92 | }, 93 | { 94 | filter_friendly_name : "Language - English", 95 | expression : "selected_language == \"en\"", 96 | targets : [ 97 | { 98 | queue : twilio_taskrouter_workspaces_task_queues_v1.english.sid 99 | } 100 | ] 101 | }, 102 | ] 103 | } 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /examples/trunking/v1/trunking.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | resource "twilio_trunking_trunks_v1" "trunk" { 16 | friendly_name = "ElasticTrunk" 17 | disaster_recovery_method = "GET" 18 | disaster_recovery_url = "https://www.twilio.com/docs/sip-trunking/api/trunk-resource" 19 | cnam_lookup_enabled = true 20 | secure = true 21 | transfer_mode = "enable-all" 22 | } 23 | 24 | # can only associate original url and not Credential lists/ IP Access Control Lists or Phone Numbers since they do not support an Update 25 | resource "twilio_trunking_trunks_origination_urls_v1" "origination_urls" { 26 | trunk_sid = twilio_trunking_trunks_v1.trunk.sid 27 | enabled = true 28 | friendly_name = "TrunkOriginationUrl" 29 | priority = 50 30 | sip_url = "sip:username@host" 31 | weight = 50 32 | } 33 | 34 | output "trunk" { 35 | value = twilio_trunking_trunks_v1.trunk 36 | } 37 | 38 | output "origination_url" { 39 | value = twilio_trunking_trunks_origination_urls_v1.origination_urls 40 | } 41 | -------------------------------------------------------------------------------- /examples/verify/v2/verify.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | twilio = { 4 | source = "twilio/twilio" 5 | version = ">=0.4.0" 6 | } 7 | } 8 | } 9 | 10 | provider "twilio" { 11 | // username defaults to TWILIO_API_KEY with TWILIO_ACCOUNT_SID as the fallback env var 12 | // password defaults to TWILIO_API_SECRET with TWILIO_AUTH_TOKEN as the fallback env var 13 | } 14 | 15 | resource "twilio_verify_services_v2" "verify" { 16 | friendly_name = "Verify" 17 | code_length = 8 18 | do_not_share_warning_enabled = false 19 | psd2_enabled = false 20 | push_include_date = false 21 | lookup_enabled = false 22 | skip_sms_to_landlines = false 23 | } 24 | 25 | output "verification" { 26 | value = twilio_verify_services_v2.verify 27 | } 28 | -------------------------------------------------------------------------------- /githooks/pre-commit: -------------------------------------------------------------------------------- 1 | make golint terrafmt test 2 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/twilio/terraform-provider-twilio 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637 7 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0 8 | github.com/joho/godotenv v1.5.1 9 | github.com/stretchr/testify v1.7.2 10 | github.com/twilio/twilio-go v1.21.1 11 | ) 12 | 13 | require ( 14 | github.com/agext/levenshtein v1.2.3 // indirect 15 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/fatih/color v1.14.1 // indirect 18 | github.com/golang/mock v1.6.0 // indirect 19 | github.com/golang/protobuf v1.5.2 // indirect 20 | github.com/google/go-cmp v0.5.9 // indirect 21 | github.com/hashicorp/errwrap v1.1.0 // indirect 22 | github.com/hashicorp/go-checkpoint v0.5.0 // indirect 23 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 24 | github.com/hashicorp/go-hclog v1.4.0 // indirect 25 | github.com/hashicorp/go-multierror v1.1.1 // indirect 26 | github.com/hashicorp/go-plugin v1.4.8 // indirect 27 | github.com/hashicorp/go-uuid v1.0.3 // indirect 28 | github.com/hashicorp/go-version v1.6.0 // indirect 29 | github.com/hashicorp/hc-install v0.5.0 // indirect 30 | github.com/hashicorp/hcl/v2 v2.16.1 // indirect 31 | github.com/hashicorp/logutils v1.0.0 // indirect 32 | github.com/hashicorp/terraform-exec v0.17.3 // indirect 33 | github.com/hashicorp/terraform-json v0.15.0 // indirect 34 | github.com/hashicorp/terraform-plugin-go v0.14.3 // indirect 35 | github.com/hashicorp/terraform-plugin-log v0.8.0 // indirect 36 | github.com/hashicorp/terraform-registry-address v0.1.0 // indirect 37 | github.com/hashicorp/terraform-svchost v0.1.0 // indirect 38 | github.com/hashicorp/yamux v0.1.1 // indirect 39 | github.com/mattn/go-colorable v0.1.13 // indirect 40 | github.com/mattn/go-isatty v0.0.17 // indirect 41 | github.com/mitchellh/copystructure v1.2.0 // indirect 42 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 43 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 44 | github.com/mitchellh/mapstructure v1.5.0 // indirect 45 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 46 | github.com/oklog/run v1.1.0 // indirect 47 | github.com/pkg/errors v0.9.1 // indirect 48 | github.com/pmezard/go-difflib v1.0.0 // indirect 49 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect 50 | github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect 51 | github.com/vmihailenco/tagparser v0.1.2 // indirect 52 | github.com/zclconf/go-cty v1.12.1 // indirect 53 | golang.org/x/crypto v0.6.0 // indirect 54 | golang.org/x/mod v0.7.0 // indirect 55 | golang.org/x/net v0.7.0 // indirect 56 | golang.org/x/sys v0.5.0 // indirect 57 | golang.org/x/text v0.7.0 // indirect 58 | google.golang.org/appengine v1.6.7 // indirect 59 | google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec // indirect 60 | google.golang.org/grpc v1.53.0 // indirect 61 | google.golang.org/protobuf v1.28.1 // indirect 62 | gopkg.in/yaml.v3 v3.0.1 // indirect 63 | ) 64 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" 9 | "github.com/joho/godotenv" 10 | "github.com/twilio/terraform-provider-twilio/twilio" 11 | ) 12 | 13 | func main() { 14 | var debugMode bool 15 | 16 | flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve") 17 | flag.Parse() 18 | 19 | if fileExists("./conf/.env") { 20 | err := godotenv.Load(`./conf/.env`) 21 | if err != nil { 22 | _ = fmt.Errorf("error on loading env %s", err) 23 | os.Exit(-1) 24 | } 25 | } 26 | 27 | opts := &plugin.ServeOpts{ 28 | ProviderFunc: twilio.Provider, 29 | } 30 | 31 | if debugMode { 32 | opts.Debug = debugMode 33 | opts.ProviderAddr = "registry.terraform.io/twilio/twilio" 34 | } 35 | 36 | plugin.Serve(opts) 37 | } 38 | 39 | func fileExists(filename string) bool { 40 | info, err := os.Stat(filename) 41 | if os.IsNotExist(err) { 42 | return false 43 | } 44 | return !info.IsDir() 45 | } 46 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=twilio_terraform-provider-twilio 2 | sonar.projectName=terraform-provider-twilio 3 | sonar.organization=twilio 4 | 5 | sonar.sources=. 6 | # Exclude any auto-generated source code 7 | sonar.exclusions=**/resources/**, **/*_test.go, examples/**, main.go 8 | 9 | sonar.tests=. 10 | sonar.test.inclusions=**/*_test.go 11 | 12 | # For Code Coverage analysis 13 | sonar.go.tests.reportPaths=test-report.out 14 | sonar.go.coverage.reportPaths=coverage.out 15 | -------------------------------------------------------------------------------- /twilio/provider.go: -------------------------------------------------------------------------------- 1 | // Package twilio provides bindings for Twilio's REST APIs. 2 | package twilio 3 | 4 | import ( 5 | "context" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | 10 | twilio "github.com/twilio/terraform-provider-twilio/client" 11 | "github.com/twilio/terraform-provider-twilio/twilio/resources" 12 | client "github.com/twilio/twilio-go" 13 | ) 14 | 15 | const ( 16 | AccountSid = "TWILIO_ACCOUNT_SID" 17 | AuthToken = "TWILIO_AUTH_TOKEN" 18 | ApiKey = "TWILIO_API_KEY" 19 | ApiSecret = "TWILIO_API_SECRET" 20 | SubAccountSid = "TWILIO_SUBACCOUNT_SID" 21 | Edge = "TWILIO_EDGE" 22 | Region = "TWILIO_REGION" 23 | ) 24 | 25 | // Provider initializes terraform-provider-twilio. 26 | func Provider() *schema.Provider { 27 | p := &schema.Provider{ 28 | Schema: map[string]*schema.Schema{ 29 | "username": { 30 | Type: schema.TypeString, 31 | DefaultFunc: schema.MultiEnvDefaultFunc([]string{ApiKey, AccountSid}, nil), 32 | Required: true, 33 | Description: "Your Account SID/ API Key can be found on the Twilio dashboard at www.twilio.com/console.", 34 | }, 35 | "password": { 36 | Type: schema.TypeString, 37 | DefaultFunc: schema.MultiEnvDefaultFunc([]string{ApiSecret, AuthToken}, nil), 38 | Description: "Your Auth Token/ API Secret can be found on the Twilio dashboard at www.twilio.com/console.", 39 | Required: true, 40 | }, 41 | "account_sid": { 42 | Type: schema.TypeString, 43 | DefaultFunc: schema.MultiEnvDefaultFunc([]string{SubAccountSid, AccountSid}, nil), 44 | Description: "Your SubAccount SID can be found on the Twilio dashboard at www.twilio.com/console.", 45 | Optional: true, 46 | }, 47 | "edge": { 48 | Type: schema.TypeString, 49 | DefaultFunc: schema.EnvDefaultFunc(Edge, nil), 50 | Description: "https://www.twilio.com/docs/global-infrastructure/edge-locations#public-edge-locations", 51 | Optional: true, 52 | }, 53 | "region": { 54 | Type: schema.TypeString, 55 | DefaultFunc: schema.EnvDefaultFunc(Region, nil), 56 | Description: "https://www.twilio.com/docs/global-infrastructure/edge-locations/legacy-regions", 57 | Optional: true, 58 | }, 59 | }, 60 | DataSourcesMap: map[string]*schema.Resource{}, 61 | ResourcesMap: resources.NewTwilioResources().Map, 62 | } 63 | 64 | p.ConfigureContextFunc = providerClient(p) 65 | 66 | return p 67 | } 68 | 69 | func providerClient(p *schema.Provider) schema.ConfigureContextFunc { 70 | return func(c context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) { 71 | var TwilioClient *client.RestClient 72 | 73 | username := d.Get("username").(string) 74 | password := d.Get("password").(string) 75 | region := d.Get("region").(string) 76 | edge := d.Get("edge").(string) 77 | 78 | params := client.ClientParams{ 79 | Username: username, 80 | Password: password, 81 | } 82 | 83 | if d.Get("account_sid") != nil { 84 | params.AccountSid = d.Get("account_sid").(string) 85 | } 86 | 87 | TwilioClient = client.NewRestClientWithParams(params) 88 | 89 | TwilioClient.SetRegion(region) 90 | TwilioClient.SetEdge(edge) 91 | 92 | config := &twilio.Config{ 93 | Client: TwilioClient, 94 | } 95 | 96 | return config, nil 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /twilio/provider_test.go: -------------------------------------------------------------------------------- 1 | package twilio 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/twilio/terraform-provider-twilio/twilio/resources" 9 | 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 12 | ) 13 | 14 | const ProviderName = "twilio" 15 | 16 | var testAccProviderFactories map[string]func() (*schema.Provider, error) 17 | 18 | func init() { 19 | testAccProviderFactories = map[string]func() (*schema.Provider, error){ 20 | ProviderName: func() (*schema.Provider, error) { return Provider(), nil }, 21 | } 22 | } 23 | 24 | func TestMain(m *testing.M) { 25 | resource.TestMain(m) 26 | } 27 | 28 | func TestTwilioResourcesMap(t *testing.T) { 29 | twilioResources := resources.NewTwilioResources() 30 | assert.NotNil(t, twilioResources.Map["twilio_api_accounts_messages"]) 31 | } 32 | 33 | func testAccPreCheck(t *testing.T) { 34 | if v := os.Getenv(AccountSid); v == "" { 35 | t.Fatal("TWILIO_ACCOUNT_SID must be set for acceptance tests") 36 | } 37 | if v := os.Getenv(ApiKey); v == "" { 38 | t.Fatal("TWILIO_API_KEY must be set for acceptance tests") 39 | } 40 | if v := os.Getenv(ApiSecret); v == "" { 41 | t.Fatal("TWILIO_API_SECRET must be set for acceptance tests") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /twilio/resources/accounts/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_accounts_credentials_aws_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **credentials** | string | **Required** | A string that contains the AWS access credentials in the format `:`. For example, `AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY` 9 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It can be up to 64 characters long. 10 | **account_sid** | string | Optional | The SID of the Subaccount that this Credential should be associated with. Must be a valid Subaccount of the account issuing the request. 11 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the AWS resource to update. 12 | 13 | ## twilio_accounts_credentials_public_keys_v1 14 | 15 | ### Parameters 16 | 17 | Name | Type | Requirement | Description 18 | --- | --- | --- | --- 19 | **public_key** | string | **Required** | A URL encoded representation of the public key. For example, `-----BEGIN PUBLIC KEY-----MIIBIjANB.pa9xQIDAQAB-----END PUBLIC KEY-----` 20 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It can be up to 64 characters long. 21 | **account_sid** | string | Optional | The SID of the Subaccount that this Credential should be associated with. Must be a valid Subaccount of the account issuing the request 22 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the PublicKey resource to update. 23 | 24 | ## twilio_accounts_safe_list_numbers_v1 25 | 26 | ### Parameters 27 | 28 | Name | Type | Requirement | Description 29 | --- | --- | --- | --- 30 | **phone_number** | string | **Required** | The phone number to be added in SafeList. Phone numbers must be in [E.164 format](https://www.twilio.com/docs/glossary/what-e164). 31 | 32 | -------------------------------------------------------------------------------- /twilio/resources/events/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_events_sinks_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **description** | string | **Required** | A human readable description for the Sink **This value should not contain PII.** 9 | **sink_configuration** | string | **Required** | The information required for Twilio to connect to the provided Sink encoded as JSON. 10 | **sink_type** | string | **Required** | 11 | **sid** | string | *Computed* | A 34 character string that uniquely identifies this Sink. 12 | 13 | ## twilio_events_subscriptions_subscribed_events_v1 14 | 15 | ### Parameters 16 | 17 | Name | Type | Requirement | Description 18 | --- | --- | --- | --- 19 | **subscription_sid** | string | **Required** | The unique SID identifier of the Subscription. 20 | **type** | string | **Required** | Type of event being subscribed to. 21 | **schema_version** | int | Optional | The schema version that the Subscription should use. 22 | 23 | ## twilio_events_subscriptions_v1 24 | 25 | ### Parameters 26 | 27 | Name | Type | Requirement | Description 28 | --- | --- | --- | --- 29 | **description** | string | **Required** | A human readable description for the Subscription **This value should not contain PII.** 30 | **sink_sid** | string | **Required** | The SID of the sink that events selected by this subscription should be sent to. Sink must be active for the subscription to be created. 31 | **types** | list(string) | **Required** | An array of objects containing the subscribed Event Types 32 | **sid** | string | *Computed* | A 34 character string that uniquely identifies this Subscription. 33 | 34 | -------------------------------------------------------------------------------- /twilio/resources/flex/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_flex_channels_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **flex_flow_sid** | string | **Required** | The SID of the Flex Flow. 9 | **identity** | string | **Required** | The `identity` value that uniquely identifies the new resource's chat User. 10 | **chat_user_friendly_name** | string | **Required** | The chat participant's friendly name. 11 | **chat_friendly_name** | string | **Required** | The chat channel's friendly name. 12 | **target** | string | Optional | The Target Contact Identity, for example the phone number of an SMS. 13 | **chat_unique_name** | string | Optional | The chat channel's unique name. 14 | **pre_engagement_data** | string | Optional | The pre-engagement data. 15 | **task_sid** | string | Optional | The SID of the TaskRouter Task. Only valid when integration type is `task`. `null` for integration types `studio` & `external` 16 | **task_attributes** | string | Optional | The Task attributes to be added for the TaskRouter Task. 17 | **long_lived** | bool | Optional | Whether to create the channel as long-lived. 18 | **sid** | string | *Computed* | The SID of the Flex chat channel resource to fetch. 19 | 20 | ## twilio_flex_flex_flows_v1 21 | 22 | ### Parameters 23 | 24 | Name | Type | Requirement | Description 25 | --- | --- | --- | --- 26 | **friendly_name** | string | **Required** | A descriptive string that you create to describe the Flex Flow resource. 27 | **chat_service_sid** | string | **Required** | The SID of the chat service. 28 | **channel_type** | string | **Required** | 29 | **contact_identity** | string | Optional | The channel contact's Identity. 30 | **enabled** | bool | Optional | Whether the new Flex Flow is enabled. 31 | **integration_type** | string | Optional | 32 | **integration_flow_sid** | string | Optional | The SID of the Studio Flow. Required when `integrationType` is `studio`. 33 | **integration_url** | string | Optional | The URL of the external webhook. Required when `integrationType` is `external`. 34 | **integration_workspace_sid** | string | Optional | The Workspace SID for a new Task. Required when `integrationType` is `task`. 35 | **integration_workflow_sid** | string | Optional | The Workflow SID for a new Task. Required when `integrationType` is `task`. 36 | **integration_channel** | string | Optional | The Task Channel SID (TCXXXX) or unique name (e.g., `sms`) to use for the Task that will be created. Applicable and required when `integrationType` is `task`. The default value is `default`. 37 | **integration_timeout** | int | Optional | The Task timeout in seconds for a new Task. Default is 86,400 seconds (24 hours). Optional when `integrationType` is `task`, not applicable otherwise. 38 | **integration_priority** | int | Optional | The Task priority of a new Task. The default priority is 0. Optional when `integrationType` is `task`, not applicable otherwise. 39 | **integration_creation_on_message** | bool | Optional | In the context of outbound messaging, defines whether to create a Task immediately (and therefore reserve the conversation to current agent), or delay Task creation until the customer sends the first response. Set to false to create immediately, true to delay Task creation. This setting is only applicable for outbound messaging. 40 | **long_lived** | bool | Optional | When enabled, Flex will keep the chat channel active so that it may be used for subsequent interactions with a contact identity. Defaults to `false`. 41 | **janitor_enabled** | bool | Optional | When enabled, the Messaging Channel Janitor will remove active Proxy sessions if the associated Task is deleted outside of the Flex UI. Defaults to `false`. 42 | **integration_retry_count** | int | Optional | The number of times to retry the Studio Flow or webhook in case of failure. Takes integer values from 0 to 3 with the default being 3. Optional when `integrationType` is `studio` or `external`, not applicable otherwise. 43 | **sid** | string | *Computed* | The SID of the Flex Flow resource to update. 44 | 45 | ## twilio_flex_insights_quality_management_questionnaires_v1 46 | 47 | ### Parameters 48 | 49 | Name | Type | Requirement | Description 50 | --- | --- | --- | --- 51 | **name** | string | **Required** | The name of this questionnaire 52 | **authorization** | string | Optional | The Authorization HTTP request header 53 | **description** | string | Optional | The description of this questionnaire 54 | **active** | bool | Optional | The flag to enable or disable questionnaire 55 | **question_sids** | list(string) | Optional | The list of questions sids under a questionnaire 56 | **questionnaire_sid** | string | *Computed* | The SID of the questionnaire 57 | 58 | ## twilio_flex_web_channels_v1 59 | 60 | ### Parameters 61 | 62 | Name | Type | Requirement | Description 63 | --- | --- | --- | --- 64 | **flex_flow_sid** | string | **Required** | The SID of the Flex Flow. 65 | **identity** | string | **Required** | The chat identity. 66 | **customer_friendly_name** | string | **Required** | The chat participant's friendly name. 67 | **chat_friendly_name** | string | **Required** | The chat channel's friendly name. 68 | **chat_unique_name** | string | Optional | The chat channel's unique name. 69 | **pre_engagement_data** | string | Optional | The pre-engagement data. 70 | **sid** | string | *Computed* | The SID of the WebChannel resource to update. 71 | **chat_status** | string | Optional | 72 | **post_engagement_data** | string | Optional | The post-engagement data. 73 | 74 | -------------------------------------------------------------------------------- /twilio/resources/intelligence/v2/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_intelligence_operators_custom_v2 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **friendly_name** | string | **Required** | A human readable description of the new Operator, up to 64 characters. 9 | **operator_type** | string | **Required** | Operator Type for this Operator. References an existing Operator Type resource. 10 | **config** | string | **Required** | Operator configuration, following the schema defined by the Operator Type. 11 | **sid** | string | *Computed* | A 34 character string that uniquely identifies this Custom Operator. 12 | **if_match** | string | Optional | The If-Match HTTP request header 13 | 14 | ## twilio_intelligence_services_operators_v2 15 | 16 | ### Parameters 17 | 18 | Name | Type | Requirement | Description 19 | --- | --- | --- | --- 20 | **service_sid** | string | **Required** | The unique SID identifier of the Service. 21 | **operator_sid** | string | **Required** | The unique SID identifier of the Operator. Allows both Custom and Pre-built Operators. 22 | 23 | ## twilio_intelligence_services_v2 24 | 25 | ### Parameters 26 | 27 | Name | Type | Requirement | Description 28 | --- | --- | --- | --- 29 | **unique_name** | string | **Required** | Provides a unique and addressable name to be assigned to this Service, assigned by the developer, to be optionally used in addition to SID. 30 | **auto_transcribe** | bool | Optional | Instructs the Speech Recognition service to automatically transcribe all recordings made on the account. 31 | **data_logging** | bool | Optional | Data logging allows Twilio to improve the quality of the speech recognition & language understanding services through using customer data to refine, fine tune and evaluate machine learning models. Note: Data logging cannot be activated via API, only via www.twilio.com, as it requires additional consent. 32 | **friendly_name** | string | Optional | A human readable description of this resource, up to 64 characters. 33 | **language_code** | string | Optional | The language code set during Service creation determines the Transcription language for all call recordings processed by that Service. The default is en-US if no language code is set. A Service can only support one language code, and it cannot be updated once it's set. 34 | **auto_redaction** | bool | Optional | Instructs the Speech Recognition service to automatically redact PII from all transcripts made on this service. 35 | **media_redaction** | bool | Optional | Instructs the Speech Recognition service to automatically redact PII from all transcripts media made on this service. The auto_redaction flag must be enabled, results in error otherwise. 36 | **webhook_url** | string | Optional | The URL Twilio will request when executing the Webhook. 37 | **webhook_http_method** | string | Optional | 38 | **sid** | string | *Computed* | A 34 character string that uniquely identifies this Service. 39 | **if_match** | string | Optional | The If-Match HTTP request header 40 | 41 | ## twilio_intelligence_transcripts_v2 42 | 43 | ### Parameters 44 | 45 | Name | Type | Requirement | Description 46 | --- | --- | --- | --- 47 | **service_sid** | string | **Required** | The unique SID identifier of the Service. 48 | **channel** | string | **Required** | JSON object describing Media Channel including Source and Participants 49 | **customer_key** | string | Optional | Used to store client provided metadata. Maximum of 64 double-byte UTF8 characters. 50 | **media_start_time** | string | Optional | The date that this Transcript's media was started, given in ISO 8601 format. 51 | **sid** | string | *Computed* | A 34 character string that uniquely identifies this Transcript. 52 | 53 | -------------------------------------------------------------------------------- /twilio/resources/ip_messaging/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_ip_messaging_services_channels_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **service_sid** | string | **Required** | 9 | **friendly_name** | string | Optional | 10 | **unique_name** | string | Optional | 11 | **attributes** | string | Optional | 12 | **type** | string | Optional | 13 | **sid** | string | *Computed* | 14 | 15 | ## twilio_ip_messaging_credentials_v1 16 | 17 | ### Parameters 18 | 19 | Name | Type | Requirement | Description 20 | --- | --- | --- | --- 21 | **type** | string | **Required** | 22 | **friendly_name** | string | Optional | 23 | **certificate** | string | Optional | 24 | **private_key** | string | Optional | 25 | **sandbox** | bool | Optional | 26 | **api_key** | string | Optional | 27 | **secret** | string | Optional | 28 | **sid** | string | *Computed* | 29 | 30 | ## twilio_ip_messaging_services_channels_invites_v1 31 | 32 | ### Parameters 33 | 34 | Name | Type | Requirement | Description 35 | --- | --- | --- | --- 36 | **service_sid** | string | **Required** | 37 | **channel_sid** | string | **Required** | 38 | **identity** | string | **Required** | 39 | **role_sid** | string | Optional | 40 | **sid** | string | *Computed* | 41 | 42 | ## twilio_ip_messaging_services_channels_members_v1 43 | 44 | ### Parameters 45 | 46 | Name | Type | Requirement | Description 47 | --- | --- | --- | --- 48 | **service_sid** | string | **Required** | 49 | **channel_sid** | string | **Required** | 50 | **identity** | string | **Required** | 51 | **role_sid** | string | Optional | 52 | **sid** | string | *Computed* | 53 | **last_consumed_message_index** | int | Optional | 54 | 55 | ## twilio_ip_messaging_services_channels_messages_v1 56 | 57 | ### Parameters 58 | 59 | Name | Type | Requirement | Description 60 | --- | --- | --- | --- 61 | **service_sid** | string | **Required** | 62 | **channel_sid** | string | **Required** | 63 | **body** | string | **Required** | 64 | **from** | string | Optional | 65 | **attributes** | string | Optional | 66 | **sid** | string | *Computed* | 67 | 68 | ## twilio_ip_messaging_services_roles_v1 69 | 70 | ### Parameters 71 | 72 | Name | Type | Requirement | Description 73 | --- | --- | --- | --- 74 | **service_sid** | string | **Required** | 75 | **friendly_name** | string | **Required** | 76 | **type** | string | **Required** | 77 | **permission** | list(string) | **Required** | 78 | **sid** | string | *Computed* | 79 | 80 | ## twilio_ip_messaging_services_v1 81 | 82 | ### Parameters 83 | 84 | Name | Type | Requirement | Description 85 | --- | --- | --- | --- 86 | **friendly_name** | string | **Required** | 87 | **sid** | string | *Computed* | 88 | **default_service_role_sid** | string | Optional | 89 | **default_channel_role_sid** | string | Optional | 90 | **default_channel_creator_role_sid** | string | Optional | 91 | **read_status_enabled** | bool | Optional | 92 | **reachability_enabled** | bool | Optional | 93 | **typing_indicator_timeout** | int | Optional | 94 | **consumption_report_interval** | int | Optional | 95 | **notifications_new_message_enabled** | bool | Optional | 96 | **notifications_new_message_template** | string | Optional | 97 | **notifications_added_to_channel_enabled** | bool | Optional | 98 | **notifications_added_to_channel_template** | string | Optional | 99 | **notifications_removed_from_channel_enabled** | bool | Optional | 100 | **notifications_removed_from_channel_template** | string | Optional | 101 | **notifications_invited_to_channel_enabled** | bool | Optional | 102 | **notifications_invited_to_channel_template** | string | Optional | 103 | **pre_webhook_url** | string | Optional | 104 | **post_webhook_url** | string | Optional | 105 | **webhook_method** | string | Optional | 106 | **webhook_filters** | list(string) | Optional | 107 | **webhooks_on_message_send_url** | string | Optional | 108 | **webhooks_on_message_send_method** | string | Optional | 109 | **webhooks_on_message_update_url** | string | Optional | 110 | **webhooks_on_message_update_method** | string | Optional | 111 | **webhooks_on_message_remove_url** | string | Optional | 112 | **webhooks_on_message_remove_method** | string | Optional | 113 | **webhooks_on_channel_add_url** | string | Optional | 114 | **webhooks_on_channel_add_method** | string | Optional | 115 | **webhooks_on_channel_destroy_url** | string | Optional | 116 | **webhooks_on_channel_destroy_method** | string | Optional | 117 | **webhooks_on_channel_update_url** | string | Optional | 118 | **webhooks_on_channel_update_method** | string | Optional | 119 | **webhooks_on_member_add_url** | string | Optional | 120 | **webhooks_on_member_add_method** | string | Optional | 121 | **webhooks_on_member_remove_url** | string | Optional | 122 | **webhooks_on_member_remove_method** | string | Optional | 123 | **webhooks_on_message_sent_url** | string | Optional | 124 | **webhooks_on_message_sent_method** | string | Optional | 125 | **webhooks_on_message_updated_url** | string | Optional | 126 | **webhooks_on_message_updated_method** | string | Optional | 127 | **webhooks_on_message_removed_url** | string | Optional | 128 | **webhooks_on_message_removed_method** | string | Optional | 129 | **webhooks_on_channel_added_url** | string | Optional | 130 | **webhooks_on_channel_added_method** | string | Optional | 131 | **webhooks_on_channel_destroyed_url** | string | Optional | 132 | **webhooks_on_channel_destroyed_method** | string | Optional | 133 | **webhooks_on_channel_updated_url** | string | Optional | 134 | **webhooks_on_channel_updated_method** | string | Optional | 135 | **webhooks_on_member_added_url** | string | Optional | 136 | **webhooks_on_member_added_method** | string | Optional | 137 | **webhooks_on_member_removed_url** | string | Optional | 138 | **webhooks_on_member_removed_method** | string | Optional | 139 | **limits_channel_members** | int | Optional | 140 | **limits_user_channels** | int | Optional | 141 | 142 | ## twilio_ip_messaging_services_users_v1 143 | 144 | ### Parameters 145 | 146 | Name | Type | Requirement | Description 147 | --- | --- | --- | --- 148 | **service_sid** | string | **Required** | 149 | **identity** | string | **Required** | 150 | **role_sid** | string | Optional | 151 | **attributes** | string | Optional | 152 | **friendly_name** | string | Optional | 153 | **sid** | string | *Computed* | 154 | 155 | -------------------------------------------------------------------------------- /twilio/resources/ip_messaging/v2/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_ip_messaging_services_channels_v2 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **service_sid** | string | **Required** | 9 | **x_twilio_webhook_enabled** | string | Optional | The X-Twilio-Webhook-Enabled HTTP request header 10 | **friendly_name** | string | Optional | 11 | **unique_name** | string | Optional | 12 | **attributes** | string | Optional | 13 | **type** | string | Optional | 14 | **date_created** | string | Optional | 15 | **date_updated** | string | Optional | 16 | **created_by** | string | Optional | 17 | **sid** | string | *Computed* | 18 | 19 | ## twilio_ip_messaging_services_channels_webhooks_v2 20 | 21 | ### Parameters 22 | 23 | Name | Type | Requirement | Description 24 | --- | --- | --- | --- 25 | **service_sid** | string | **Required** | 26 | **channel_sid** | string | **Required** | 27 | **type** | string | **Required** | 28 | **configuration_url** | string | Optional | 29 | **configuration_method** | string | Optional | 30 | **configuration_filters** | list(string) | Optional | 31 | **configuration_triggers** | list(string) | Optional | 32 | **configuration_flow_sid** | string | Optional | 33 | **configuration_retry_count** | int | Optional | 34 | **sid** | string | *Computed* | 35 | 36 | ## twilio_ip_messaging_credentials_v2 37 | 38 | ### Parameters 39 | 40 | Name | Type | Requirement | Description 41 | --- | --- | --- | --- 42 | **type** | string | **Required** | 43 | **friendly_name** | string | Optional | 44 | **certificate** | string | Optional | 45 | **private_key** | string | Optional | 46 | **sandbox** | bool | Optional | 47 | **api_key** | string | Optional | 48 | **secret** | string | Optional | 49 | **sid** | string | *Computed* | 50 | 51 | ## twilio_ip_messaging_services_channels_invites_v2 52 | 53 | ### Parameters 54 | 55 | Name | Type | Requirement | Description 56 | --- | --- | --- | --- 57 | **service_sid** | string | **Required** | 58 | **channel_sid** | string | **Required** | 59 | **identity** | string | **Required** | 60 | **role_sid** | string | Optional | 61 | **sid** | string | *Computed* | 62 | 63 | ## twilio_ip_messaging_services_channels_members_v2 64 | 65 | ### Parameters 66 | 67 | Name | Type | Requirement | Description 68 | --- | --- | --- | --- 69 | **service_sid** | string | **Required** | 70 | **channel_sid** | string | **Required** | 71 | **identity** | string | **Required** | 72 | **x_twilio_webhook_enabled** | string | Optional | The X-Twilio-Webhook-Enabled HTTP request header 73 | **role_sid** | string | Optional | 74 | **last_consumed_message_index** | int | Optional | 75 | **last_consumption_timestamp** | string | Optional | 76 | **date_created** | string | Optional | 77 | **date_updated** | string | Optional | 78 | **attributes** | string | Optional | 79 | **sid** | string | *Computed* | 80 | 81 | ## twilio_ip_messaging_services_channels_messages_v2 82 | 83 | ### Parameters 84 | 85 | Name | Type | Requirement | Description 86 | --- | --- | --- | --- 87 | **service_sid** | string | **Required** | 88 | **channel_sid** | string | **Required** | 89 | **x_twilio_webhook_enabled** | string | Optional | The X-Twilio-Webhook-Enabled HTTP request header 90 | **from** | string | Optional | 91 | **attributes** | string | Optional | 92 | **date_created** | string | Optional | 93 | **date_updated** | string | Optional | 94 | **last_updated_by** | string | Optional | 95 | **body** | string | Optional | 96 | **media_sid** | string | Optional | 97 | **sid** | string | *Computed* | 98 | 99 | ## twilio_ip_messaging_services_roles_v2 100 | 101 | ### Parameters 102 | 103 | Name | Type | Requirement | Description 104 | --- | --- | --- | --- 105 | **service_sid** | string | **Required** | 106 | **friendly_name** | string | **Required** | 107 | **type** | string | **Required** | 108 | **permission** | list(string) | **Required** | 109 | **sid** | string | *Computed* | 110 | 111 | ## twilio_ip_messaging_services_v2 112 | 113 | ### Parameters 114 | 115 | Name | Type | Requirement | Description 116 | --- | --- | --- | --- 117 | **friendly_name** | string | **Required** | 118 | **sid** | string | *Computed* | 119 | **default_service_role_sid** | string | Optional | 120 | **default_channel_role_sid** | string | Optional | 121 | **default_channel_creator_role_sid** | string | Optional | 122 | **read_status_enabled** | bool | Optional | 123 | **reachability_enabled** | bool | Optional | 124 | **typing_indicator_timeout** | int | Optional | 125 | **consumption_report_interval** | int | Optional | 126 | **notifications_new_message_enabled** | bool | Optional | 127 | **notifications_new_message_template** | string | Optional | 128 | **notifications_new_message_sound** | string | Optional | 129 | **notifications_new_message_badge_count_enabled** | bool | Optional | 130 | **notifications_added_to_channel_enabled** | bool | Optional | 131 | **notifications_added_to_channel_template** | string | Optional | 132 | **notifications_added_to_channel_sound** | string | Optional | 133 | **notifications_removed_from_channel_enabled** | bool | Optional | 134 | **notifications_removed_from_channel_template** | string | Optional | 135 | **notifications_removed_from_channel_sound** | string | Optional | 136 | **notifications_invited_to_channel_enabled** | bool | Optional | 137 | **notifications_invited_to_channel_template** | string | Optional | 138 | **notifications_invited_to_channel_sound** | string | Optional | 139 | **pre_webhook_url** | string | Optional | 140 | **post_webhook_url** | string | Optional | 141 | **webhook_method** | string | Optional | 142 | **webhook_filters** | list(string) | Optional | 143 | **limits_channel_members** | int | Optional | 144 | **limits_user_channels** | int | Optional | 145 | **media_compatibility_message** | string | Optional | 146 | **pre_webhook_retry_count** | int | Optional | 147 | **post_webhook_retry_count** | int | Optional | 148 | **notifications_log_enabled** | bool | Optional | 149 | 150 | ## twilio_ip_messaging_services_users_v2 151 | 152 | ### Parameters 153 | 154 | Name | Type | Requirement | Description 155 | --- | --- | --- | --- 156 | **service_sid** | string | **Required** | 157 | **identity** | string | **Required** | 158 | **x_twilio_webhook_enabled** | string | Optional | The X-Twilio-Webhook-Enabled HTTP request header 159 | **role_sid** | string | Optional | 160 | **attributes** | string | Optional | 161 | **friendly_name** | string | Optional | 162 | **sid** | string | *Computed* | 163 | 164 | -------------------------------------------------------------------------------- /twilio/resources/microvisor/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_microvisor_configs_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **key** | string | **Required** | The config key; up to 100 characters. 9 | **value** | string | **Required** | The config value; up to 4096 characters. 10 | 11 | ## twilio_microvisor_secrets_v1 12 | 13 | ### Parameters 14 | 15 | Name | Type | Requirement | Description 16 | --- | --- | --- | --- 17 | **key** | string | **Required** | The secret key; up to 100 characters. 18 | **value** | string | **Required** | The secret value; up to 4096 characters. 19 | 20 | ## twilio_microvisor_devices_configs_v1 21 | 22 | ### Parameters 23 | 24 | Name | Type | Requirement | Description 25 | --- | --- | --- | --- 26 | **device_sid** | string | **Required** | A 34-character string that uniquely identifies the Device. 27 | **key** | string | **Required** | The config key; up to 100 characters. 28 | **value** | string | **Required** | The config value; up to 4096 characters. 29 | 30 | ## twilio_microvisor_devices_secrets_v1 31 | 32 | ### Parameters 33 | 34 | Name | Type | Requirement | Description 35 | --- | --- | --- | --- 36 | **device_sid** | string | **Required** | A 34-character string that uniquely identifies the Device. 37 | **key** | string | **Required** | The secret key; up to 100 characters. 38 | **value** | string | **Required** | The secret value; up to 4096 characters. 39 | 40 | -------------------------------------------------------------------------------- /twilio/resources/notify/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_notify_services_bindings_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **service_sid** | string | **Required** | The SID of the [Service](https://www.twilio.com/docs/notify/api/service-resource) to create the resource under. 9 | **identity** | string | **Required** | The `identity` value that uniquely identifies the new resource's [User](https://www.twilio.com/docs/chat/rest/user-resource) within the [Service](https://www.twilio.com/docs/notify/api/service-resource). Up to 20 Bindings can be created for the same Identity in a given Service. 10 | **binding_type** | string | **Required** | 11 | **address** | string | **Required** | The channel-specific address. For APNS, the device token. For FCM and GCM, the registration token. For SMS, a phone number in E.164 format. For Facebook Messenger, the Messenger ID of the user or a phone number in E.164 format. 12 | **tag** | list(string) | Optional | A tag that can be used to select the Bindings to notify. Repeat this parameter to specify more than one tag, up to a total of 20 tags. 13 | **notification_protocol_version** | string | Optional | The protocol version to use to send the notification. This defaults to the value of `default_xxxx_notification_protocol_version` for the protocol in the [Service](https://www.twilio.com/docs/notify/api/service-resource). The current version is `\\\"3\\\"` for `apn`, `fcm`, and `gcm` type Bindings. The parameter is not applicable to `sms` and `facebook-messenger` type Bindings as the data format is fixed. 14 | **credential_sid** | string | Optional | The SID of the [Credential](https://www.twilio.com/docs/notify/api/credential-resource) resource to be used to send notifications to this Binding. If present, this overrides the Credential specified in the Service resource. Applies to only `apn`, `fcm`, and `gcm` type Bindings. 15 | **endpoint** | string | Optional | Deprecated. 16 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the Binding resource to fetch. 17 | 18 | ## twilio_notify_credentials_v1 19 | 20 | ### Parameters 21 | 22 | Name | Type | Requirement | Description 23 | --- | --- | --- | --- 24 | **type** | string | **Required** | 25 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It can be up to 64 characters long. 26 | **certificate** | string | Optional | [APN only] The URL-encoded representation of the certificate. Strip everything outside of the headers, e.g. `-----BEGIN CERTIFICATE-----MIIFnTCCBIWgAwIBAgIIAjy9H849+E8wDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV.....A==-----END CERTIFICATE-----` 27 | **private_key** | string | Optional | [APN only] The URL-encoded representation of the private key. Strip everything outside of the headers, e.g. `-----BEGIN RSA PRIVATE KEY-----MIIEpQIBAAKCAQEAuyf/lNrH9ck8DmNyo3fGgvCI1l9s+cmBY3WIz+cUDqmxiieR\\\\n.-----END RSA PRIVATE KEY-----` 28 | **sandbox** | bool | Optional | [APN only] Whether to send the credential to sandbox APNs. Can be `true` to send to sandbox APNs or `false` to send to production. 29 | **api_key** | string | Optional | [GCM only] The `Server key` of your project from Firebase console under Settings / Cloud messaging. 30 | **secret** | string | Optional | [FCM only] The `Server key` of your project from Firebase console under Settings / Cloud messaging. 31 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the Credential resource to update. 32 | 33 | ## twilio_notify_services_v1 34 | 35 | ### Parameters 36 | 37 | Name | Type | Requirement | Description 38 | --- | --- | --- | --- 39 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It can be up to 64 characters long. 40 | **apn_credential_sid** | string | Optional | The SID of the [Credential](https://www.twilio.com/docs/notify/api/credential-resource) to use for APN Bindings. 41 | **gcm_credential_sid** | string | Optional | The SID of the [Credential](https://www.twilio.com/docs/notify/api/credential-resource) to use for GCM Bindings. 42 | **messaging_service_sid** | string | Optional | The SID of the [Messaging Service](https://www.twilio.com/docs/sms/quickstart#messaging-services) to use for SMS Bindings. This parameter must be set in order to send SMS notifications. 43 | **facebook_messenger_page_id** | string | Optional | Deprecated. 44 | **default_apn_notification_protocol_version** | string | Optional | The protocol version to use for sending APNS notifications. Can be overridden on a Binding by Binding basis when creating a [Binding](https://www.twilio.com/docs/notify/api/binding-resource) resource. 45 | **default_gcm_notification_protocol_version** | string | Optional | The protocol version to use for sending GCM notifications. Can be overridden on a Binding by Binding basis when creating a [Binding](https://www.twilio.com/docs/notify/api/binding-resource) resource. 46 | **fcm_credential_sid** | string | Optional | The SID of the [Credential](https://www.twilio.com/docs/notify/api/credential-resource) to use for FCM Bindings. 47 | **default_fcm_notification_protocol_version** | string | Optional | The protocol version to use for sending FCM notifications. Can be overridden on a Binding by Binding basis when creating a [Binding](https://www.twilio.com/docs/notify/api/binding-resource) resource. 48 | **log_enabled** | bool | Optional | Whether to log notifications. Can be: `true` or `false` and the default is `true`. 49 | **alexa_skill_id** | string | Optional | Deprecated. 50 | **default_alexa_notification_protocol_version** | string | Optional | Deprecated. 51 | **delivery_callback_url** | string | Optional | URL to send delivery status callback. 52 | **delivery_callback_enabled** | bool | Optional | Callback configuration that enables delivery callbacks, default false 53 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the Service resource to update. 54 | 55 | -------------------------------------------------------------------------------- /twilio/resources/numbers/v2/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_numbers_hosted_number_authorization_documents_v2 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **address_sid** | string | **Required** | A 34 character string that uniquely identifies the Address resource that is associated with this AuthorizationDocument. 9 | **email** | string | **Required** | Email that this AuthorizationDocument will be sent to for signing. 10 | **contact_phone_number** | string | **Required** | The contact phone number of the person authorized to sign the Authorization Document. 11 | **hosted_number_order_sids** | list(string) | **Required** | A list of HostedNumberOrder sids that this AuthorizationDocument will authorize for hosting phone number capabilities on Twilio's platform. 12 | **contact_title** | string | Optional | The title of the person authorized to sign the Authorization Document for this phone number. 13 | **cc_emails** | list(string) | Optional | Email recipients who will be informed when an Authorization Document has been sent and signed. 14 | **sid** | string | *Computed* | A 34 character string that uniquely identifies this AuthorizationDocument. 15 | 16 | ## twilio_numbers_regulatory_compliance_bundles_v2 17 | 18 | ### Parameters 19 | 20 | Name | Type | Requirement | Description 21 | --- | --- | --- | --- 22 | **friendly_name** | string | **Required** | The string that you assigned to describe the resource. 23 | **email** | string | **Required** | The email address that will receive updates when the Bundle resource changes status. 24 | **status_callback** | string | Optional | The URL we call to inform your application of status changes. 25 | **regulation_sid** | string | Optional | The unique string of a regulation that is associated to the Bundle resource. 26 | **iso_country** | string | Optional | The [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the Bundle's phone number country ownership request. 27 | **end_user_type** | string | Optional | 28 | **number_type** | string | Optional | The type of phone number of the Bundle's ownership request. Can be `local`, `mobile`, `national`, or `toll free`. 29 | **sid** | string | *Computed* | The unique string that we created to identify the Bundle resource. 30 | **status** | string | Optional | 31 | 32 | ## twilio_numbers_regulatory_compliance_end_users_v2 33 | 34 | ### Parameters 35 | 36 | Name | Type | Requirement | Description 37 | --- | --- | --- | --- 38 | **friendly_name** | string | **Required** | The string that you assigned to describe the resource. 39 | **type** | string | **Required** | 40 | **attributes** | string | Optional | The set of parameters that are the attributes of the End User resource which are derived End User Types. 41 | **sid** | string | *Computed* | The unique string created by Twilio to identify the End User resource. 42 | 43 | ## twilio_numbers_hosted_number_orders_v2 44 | 45 | ### Parameters 46 | 47 | Name | Type | Requirement | Description 48 | --- | --- | --- | --- 49 | **phone_number** | string | **Required** | The number to host in [+E.164](https://en.wikipedia.org/wiki/E.164) format 50 | **contact_phone_number** | string | **Required** | The contact phone number of the person authorized to sign the Authorization Document. 51 | **address_sid** | string | **Required** | Optional. A 34 character string that uniquely identifies the Address resource that represents the address of the owner of this phone number. 52 | **email** | string | **Required** | Optional. Email of the owner of this phone number that is being hosted. 53 | **account_sid** | string | Optional | This defaults to the AccountSid of the authorization the user is using. This can be provided to specify a subaccount to add the HostedNumberOrder to. 54 | **friendly_name** | string | Optional | A 128 character string that is a human readable text that describes this resource. 55 | **cc_emails** | list(string) | Optional | Optional. A list of emails that the LOA document for this HostedNumberOrder will be carbon copied to. 56 | **sms_url** | string | Optional | The URL that Twilio should request when somebody sends an SMS to the phone number. This will be copied onto the IncomingPhoneNumber resource. 57 | **sms_method** | string | Optional | The HTTP method that should be used to request the SmsUrl. Must be either `GET` or `POST`. This will be copied onto the IncomingPhoneNumber resource. 58 | **sms_fallback_url** | string | Optional | A URL that Twilio will request if an error occurs requesting or executing the TwiML defined by SmsUrl. This will be copied onto the IncomingPhoneNumber resource. 59 | **sms_capability** | bool | Optional | Used to specify that the SMS capability will be hosted on Twilio's platform. 60 | **sms_fallback_method** | string | Optional | The HTTP method that should be used to request the SmsFallbackUrl. Must be either `GET` or `POST`. This will be copied onto the IncomingPhoneNumber resource. 61 | **status_callback_url** | string | Optional | Optional. The Status Callback URL attached to the IncomingPhoneNumber resource. 62 | **status_callback_method** | string | Optional | Optional. The Status Callback Method attached to the IncomingPhoneNumber resource. 63 | **sms_application_sid** | string | Optional | Optional. The 34 character sid of the application Twilio should use to handle SMS messages sent to this number. If a `SmsApplicationSid` is present, Twilio will ignore all of the SMS urls above and use those set on the application. 64 | **contact_title** | string | Optional | The title of the person authorized to sign the Authorization Document for this phone number. 65 | **sid** | string | *Computed* | A 34 character string that uniquely identifies this HostedNumberOrder. 66 | 67 | ## twilio_numbers_regulatory_compliance_bundles_item_assignments_v2 68 | 69 | ### Parameters 70 | 71 | Name | Type | Requirement | Description 72 | --- | --- | --- | --- 73 | **bundle_sid** | string | **Required** | The unique string that we created to identify the Bundle resource. 74 | **object_sid** | string | **Required** | The SID of an object bag that holds information of the different items. 75 | **sid** | string | *Computed* | The unique string that we created to identify the Identity resource. 76 | 77 | ## twilio_numbers_regulatory_compliance_supporting_documents_v2 78 | 79 | ### Parameters 80 | 81 | Name | Type | Requirement | Description 82 | --- | --- | --- | --- 83 | **friendly_name** | string | **Required** | The string that you assigned to describe the resource. 84 | **type** | string | **Required** | The type of the Supporting Document. 85 | **attributes** | string | Optional | The set of parameters that are the attributes of the Supporting Documents resource which are derived Supporting Document Types. 86 | **sid** | string | *Computed* | The unique string created by Twilio to identify the Supporting Document resource. 87 | 88 | -------------------------------------------------------------------------------- /twilio/resources/proxy/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_proxy_services_sessions_participants_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **service_sid** | string | **Required** | The SID of the parent [Service](https://www.twilio.com/docs/proxy/api/service) resource. 9 | **session_sid** | string | **Required** | The SID of the parent [Session](https://www.twilio.com/docs/proxy/api/session) resource. 10 | **identifier** | string | **Required** | The phone number of the Participant. 11 | **friendly_name** | string | Optional | The string that you assigned to describe the participant. This value must be 255 characters or fewer. **This value should not have PII.** 12 | **proxy_identifier** | string | Optional | The proxy phone number to use for the Participant. If not specified, Proxy will select a number from the pool. 13 | **proxy_identifier_sid** | string | Optional | The SID of the Proxy Identifier to assign to the Participant. 14 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the Participant resource to fetch. 15 | 16 | ## twilio_proxy_services_phone_numbers_v1 17 | 18 | ### Parameters 19 | 20 | Name | Type | Requirement | Description 21 | --- | --- | --- | --- 22 | **service_sid** | string | **Required** | The SID parent [Service](https://www.twilio.com/docs/proxy/api/service) resource of the new PhoneNumber resource. 23 | **sid** | string | Optional | The SID of a Twilio [IncomingPhoneNumber](https://www.twilio.com/docs/phone-numbers/api/incomingphonenumber-resource) resource that represents the Twilio Number you would like to assign to your Proxy Service. 24 | **phone_number** | string | Optional | The phone number in [E.164](https://www.twilio.com/docs/glossary/what-e164) format. E.164 phone numbers consist of a + followed by the country code and subscriber number without punctuation characters. For example, +14155551234. 25 | **is_reserved** | bool | Optional | Whether the new phone number should be reserved and not be assigned to a participant using proxy pool logic. See [Reserved Phone Numbers](https://www.twilio.com/docs/proxy/reserved-phone-numbers) for more information. 26 | 27 | ## twilio_proxy_services_v1 28 | 29 | ### Parameters 30 | 31 | Name | Type | Requirement | Description 32 | --- | --- | --- | --- 33 | **unique_name** | string | **Required** | An application-defined string that uniquely identifies the resource. This value must be 191 characters or fewer in length and be unique. **This value should not have PII.** 34 | **default_ttl** | int | Optional | The default `ttl` value to set for Sessions created in the Service. The TTL (time to live) is measured in seconds after the Session's last create or last Interaction. The default value of `0` indicates an unlimited Session length. You can override a Session's default TTL value by setting its `ttl` value. 35 | **callback_url** | string | Optional | The URL we should call when the interaction status changes. 36 | **geo_match_level** | string | Optional | 37 | **number_selection_behavior** | string | Optional | 38 | **intercept_callback_url** | string | Optional | The URL we call on each interaction. If we receive a 403 status, we block the interaction; otherwise the interaction continues. 39 | **out_of_session_callback_url** | string | Optional | The URL we should call when an inbound call or SMS action occurs on a closed or non-existent Session. If your server (or a Twilio [function](https://www.twilio.com/en-us/serverless/functions)) responds with valid [TwiML](https://www.twilio.com/docs/voice/twiml), we will process it. This means it is possible, for example, to play a message for a call, send an automated text message response, or redirect a call to another Phone Number. See [Out-of-Session Callback Response Guide](https://www.twilio.com/docs/proxy/out-session-callback-response-guide) for more information. 40 | **chat_instance_sid** | string | Optional | The SID of the Chat Service Instance managed by Proxy Service. The Chat Service enables Proxy to forward SMS and channel messages to this chat instance. This is a one-to-one relationship. 41 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the Service resource to update. 42 | 43 | ## twilio_proxy_services_sessions_v1 44 | 45 | ### Parameters 46 | 47 | Name | Type | Requirement | Description 48 | --- | --- | --- | --- 49 | **service_sid** | string | **Required** | The SID of the parent [Service](https://www.twilio.com/docs/proxy/api/service) resource. 50 | **unique_name** | string | Optional | An application-defined string that uniquely identifies the resource. This value must be 191 characters or fewer in length and be unique. **This value should not have PII.** 51 | **date_expiry** | string | Optional | The [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date when the Session should expire. If this is value is present, it overrides the `ttl` value. 52 | **ttl** | int | Optional | The time, in seconds, when the session will expire. The time is measured from the last Session create or the Session's last Interaction. 53 | **mode** | string | Optional | 54 | **status** | string | Optional | 55 | **participants** | list(string) | Optional | The Participant objects to include in the new session. 56 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the Session resource to update. 57 | 58 | ## twilio_proxy_services_short_codes_v1 59 | 60 | ### Parameters 61 | 62 | Name | Type | Requirement | Description 63 | --- | --- | --- | --- 64 | **service_sid** | string | **Required** | The SID of the parent [Service](https://www.twilio.com/docs/proxy/api/service) resource. 65 | **sid** | string | **Required** | The SID of a Twilio [ShortCode](https://www.twilio.com/en-us/messaging/channels/sms/short-codes) resource that represents the short code you would like to assign to your Proxy Service. 66 | **is_reserved** | bool | Optional | Whether the short code should be reserved and not be assigned to a participant using proxy pool logic. See [Reserved Phone Numbers](https://www.twilio.com/docs/proxy/reserved-phone-numbers) for more information. 67 | 68 | -------------------------------------------------------------------------------- /twilio/resources/serverless/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_serverless_services_assets_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **service_sid** | string | **Required** | The SID of the Service to create the Asset resource under. 9 | **friendly_name** | string | **Required** | A descriptive string that you create to describe the Asset resource. It can be a maximum of 255 characters. 10 | **sid** | string | *Computed* | The SID that identifies the Asset resource to update. 11 | 12 | ## twilio_serverless_services_builds_v1 13 | 14 | ### Parameters 15 | 16 | Name | Type | Requirement | Description 17 | --- | --- | --- | --- 18 | **service_sid** | string | **Required** | The SID of the Service to create the Build resource under. 19 | **asset_versions** | list(string) | Optional | The list of Asset Version resource SIDs to include in the Build. 20 | **function_versions** | list(string) | Optional | The list of the Function Version resource SIDs to include in the Build. 21 | **dependencies** | string | Optional | A list of objects that describe the Dependencies included in the Build. Each object contains the `name` and `version` of the dependency. 22 | **runtime** | string | Optional | The Runtime version that will be used to run the Build resource when it is deployed. 23 | **sid** | string | *Computed* | The SID of the Build resource to fetch. 24 | 25 | ## twilio_serverless_services_environments_v1 26 | 27 | ### Parameters 28 | 29 | Name | Type | Requirement | Description 30 | --- | --- | --- | --- 31 | **service_sid** | string | **Required** | The SID of the Service to create the Environment resource under. 32 | **unique_name** | string | **Required** | A user-defined string that uniquely identifies the Environment resource. It can be a maximum of 100 characters. 33 | **domain_suffix** | string | Optional | A URL-friendly name that represents the environment and forms part of the domain name. It can be a maximum of 16 characters. 34 | **sid** | string | *Computed* | The SID of the Environment resource to fetch. 35 | 36 | ## twilio_serverless_services_functions_v1 37 | 38 | ### Parameters 39 | 40 | Name | Type | Requirement | Description 41 | --- | --- | --- | --- 42 | **service_sid** | string | **Required** | The SID of the Service to create the Function resource under. 43 | **friendly_name** | string | **Required** | A descriptive string that you create to describe the Function resource. It can be a maximum of 255 characters. 44 | **sid** | string | *Computed* | The SID of the Function resource to update. 45 | 46 | ## twilio_serverless_services_v1 47 | 48 | ### Parameters 49 | 50 | Name | Type | Requirement | Description 51 | --- | --- | --- | --- 52 | **unique_name** | string | **Required** | A user-defined string that uniquely identifies the Service resource. It can be used as an alternative to the `sid` in the URL path to address the Service resource. This value must be 50 characters or less in length and be unique. 53 | **friendly_name** | string | **Required** | A descriptive string that you create to describe the Service resource. It can be a maximum of 255 characters. 54 | **include_credentials** | bool | Optional | Whether to inject Account credentials into a function invocation context. The default value is `true`. 55 | **ui_editable** | bool | Optional | Whether the Service's properties and subresources can be edited via the UI. The default value is `false`. 56 | **sid** | string | *Computed* | The `sid` or `unique_name` of the Service resource to update. 57 | 58 | ## twilio_serverless_services_environments_variables_v1 59 | 60 | ### Parameters 61 | 62 | Name | Type | Requirement | Description 63 | --- | --- | --- | --- 64 | **service_sid** | string | **Required** | The SID of the Service to create the Variable resource under. 65 | **environment_sid** | string | **Required** | The SID of the Environment in which the Variable resource exists. 66 | **key** | string | **Required** | A string by which the Variable resource can be referenced. It can be a maximum of 128 characters. 67 | **value** | string | **Required** | A string that contains the actual value of the Variable. It can be a maximum of 450 bytes in size. 68 | **sid** | string | *Computed* | The SID of the Variable resource to update. 69 | 70 | -------------------------------------------------------------------------------- /twilio/resources/studio/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_studio_flows_engagements_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **flow_sid** | string | **Required** | The SID of the Flow. 9 | **to** | string | **Required** | The Contact phone number to start a Studio Flow Engagement, available as variable `{{contact.channel.address}}`. 10 | **from** | string | **Required** | The Twilio phone number to send messages or initiate calls from during the Flow Engagement. Available as variable `{{flow.channel.address}}` 11 | **parameters** | string | Optional | A JSON string we will add to your flow's context and that you can access as variables inside your flow. For example, if you pass in `Parameters={'name':'Zeke'}` then inside a widget you can reference the variable `{{flow.data.name}}` which will return the string 'Zeke'. Note: the JSON value must explicitly be passed as a string, not as a hash object. Depending on your particular HTTP library, you may need to add quotes or URL encode your JSON string. 12 | **sid** | string | *Computed* | The SID of the Engagement resource to fetch. 13 | 14 | ## twilio_studio_flows_executions_v1 15 | 16 | ### Parameters 17 | 18 | Name | Type | Requirement | Description 19 | --- | --- | --- | --- 20 | **flow_sid** | string | **Required** | The SID of the Excecution's Flow. 21 | **to** | string | **Required** | The Contact phone number to start a Studio Flow Execution, available as variable `{{contact.channel.address}}`. 22 | **from** | string | **Required** | The Twilio phone number to send messages or initiate calls from during the Flow's Execution. Available as variable `{{flow.channel.address}}`. For SMS, this can also be a Messaging Service SID. 23 | **parameters** | string | Optional | JSON data that will be added to the Flow's context and that can be accessed as variables inside your Flow. For example, if you pass in `Parameters={\\\"name\\\":\\\"Zeke\\\"}`, a widget in your Flow can reference the variable `{{flow.data.name}}`, which returns \\\"Zeke\\\". Note: the JSON value must explicitly be passed as a string, not as a hash object. Depending on your particular HTTP library, you may need to add quotes or URL encode the JSON string. 24 | **sid** | string | *Computed* | The SID of the Execution resource to update. 25 | **status** | string | Optional | 26 | 27 | -------------------------------------------------------------------------------- /twilio/resources/studio/v1/api_default.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This code was generated by 3 | * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ 4 | * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ 5 | * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ 6 | * 7 | * Twilio - Studio 8 | * This is the public Twilio REST API. 9 | * 10 | * NOTE: This class is auto generated by OpenAPI Generator. 11 | * https://openapi-generator.tech 12 | * Do not edit the class manually. 13 | */ 14 | 15 | package openapi 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | "strings" 21 | 22 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 23 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 24 | "github.com/twilio/terraform-provider-twilio/client" 25 | . "github.com/twilio/terraform-provider-twilio/core" 26 | . "github.com/twilio/twilio-go/rest/studio/v1" 27 | ) 28 | 29 | func ResourceFlowsEngagements() *schema.Resource { 30 | return &schema.Resource{ 31 | CreateContext: createFlowsEngagements, 32 | ReadContext: readFlowsEngagements, 33 | DeleteContext: deleteFlowsEngagements, 34 | Schema: map[string]*schema.Schema{ 35 | "flow_sid": AsString(SchemaForceNewRequired), 36 | "to": AsString(SchemaForceNewRequired), 37 | "from": AsString(SchemaForceNewRequired), 38 | "parameters": AsString(SchemaForceNewOptional), 39 | "sid": AsString(SchemaComputed), 40 | }, 41 | Importer: &schema.ResourceImporter{ 42 | StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { 43 | err := parseFlowsEngagementsImportId(d.Id(), d) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | return []*schema.ResourceData{d}, nil 49 | }, 50 | }, 51 | } 52 | } 53 | 54 | func createFlowsEngagements(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 55 | params := CreateEngagementParams{} 56 | if err := UnmarshalSchema(¶ms, d); err != nil { 57 | return diag.FromErr(err) 58 | } 59 | 60 | flowSid := d.Get("flow_sid").(string) 61 | 62 | r, err := m.(*client.Config).Client.StudioV1.CreateEngagement(flowSid, ¶ms) 63 | if err != nil { 64 | return diag.FromErr(err) 65 | } 66 | 67 | idParts := []string{flowSid} 68 | idParts = append(idParts, (*r.Sid)) 69 | d.SetId(strings.Join(idParts, "/")) 70 | 71 | err = MarshalSchema(d, r) 72 | if err != nil { 73 | return diag.FromErr(err) 74 | } 75 | 76 | return nil 77 | } 78 | 79 | func deleteFlowsEngagements(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 80 | 81 | flowSid := d.Get("flow_sid").(string) 82 | sid := d.Get("sid").(string) 83 | 84 | err := m.(*client.Config).Client.StudioV1.DeleteEngagement(flowSid, sid) 85 | if err != nil { 86 | return diag.FromErr(err) 87 | } 88 | 89 | d.SetId("") 90 | 91 | return nil 92 | } 93 | 94 | func readFlowsEngagements(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 95 | 96 | flowSid := d.Get("flow_sid").(string) 97 | sid := d.Get("sid").(string) 98 | 99 | r, err := m.(*client.Config).Client.StudioV1.FetchEngagement(flowSid, sid) 100 | if err != nil { 101 | return diag.FromErr(err) 102 | } 103 | 104 | err = MarshalSchema(d, r) 105 | if err != nil { 106 | return diag.FromErr(err) 107 | } 108 | 109 | return nil 110 | } 111 | 112 | func parseFlowsEngagementsImportId(importId string, d *schema.ResourceData) error { 113 | importParts := strings.Split(importId, "/") 114 | errStr := "invalid import ID (%q), expected flow_sid/sid" 115 | 116 | if len(importParts) != 2 { 117 | return fmt.Errorf(errStr, importId) 118 | } 119 | 120 | d.Set("flow_sid", importParts[0]) 121 | d.Set("sid", importParts[1]) 122 | 123 | return nil 124 | } 125 | func ResourceFlowsExecutions() *schema.Resource { 126 | return &schema.Resource{ 127 | CreateContext: createFlowsExecutions, 128 | ReadContext: readFlowsExecutions, 129 | UpdateContext: updateFlowsExecutions, 130 | DeleteContext: deleteFlowsExecutions, 131 | Schema: map[string]*schema.Schema{ 132 | "flow_sid": AsString(SchemaRequired), 133 | "to": AsString(SchemaForceNewRequired), 134 | "from": AsString(SchemaForceNewRequired), 135 | "parameters": AsString(SchemaForceNewOptional), 136 | "sid": AsString(SchemaComputed), 137 | "status": AsString(SchemaComputedOptional), 138 | }, 139 | Importer: &schema.ResourceImporter{ 140 | StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { 141 | err := parseFlowsExecutionsImportId(d.Id(), d) 142 | if err != nil { 143 | return nil, err 144 | } 145 | 146 | return []*schema.ResourceData{d}, nil 147 | }, 148 | }, 149 | } 150 | } 151 | 152 | func createFlowsExecutions(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 153 | params := CreateExecutionParams{} 154 | if err := UnmarshalSchema(¶ms, d); err != nil { 155 | return diag.FromErr(err) 156 | } 157 | 158 | flowSid := d.Get("flow_sid").(string) 159 | 160 | r, err := m.(*client.Config).Client.StudioV1.CreateExecution(flowSid, ¶ms) 161 | if err != nil { 162 | return diag.FromErr(err) 163 | } 164 | 165 | idParts := []string{flowSid} 166 | idParts = append(idParts, (*r.Sid)) 167 | d.SetId(strings.Join(idParts, "/")) 168 | d.Set("sid", *r.Sid) 169 | 170 | return updateFlowsExecutions(ctx, d, m) 171 | } 172 | 173 | func deleteFlowsExecutions(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 174 | 175 | flowSid := d.Get("flow_sid").(string) 176 | sid := d.Get("sid").(string) 177 | 178 | err := m.(*client.Config).Client.StudioV1.DeleteExecution(flowSid, sid) 179 | if err != nil { 180 | return diag.FromErr(err) 181 | } 182 | 183 | d.SetId("") 184 | 185 | return nil 186 | } 187 | 188 | func readFlowsExecutions(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 189 | 190 | flowSid := d.Get("flow_sid").(string) 191 | sid := d.Get("sid").(string) 192 | 193 | r, err := m.(*client.Config).Client.StudioV1.FetchExecution(flowSid, sid) 194 | if err != nil { 195 | return diag.FromErr(err) 196 | } 197 | 198 | err = MarshalSchema(d, r) 199 | if err != nil { 200 | return diag.FromErr(err) 201 | } 202 | 203 | return nil 204 | } 205 | 206 | func parseFlowsExecutionsImportId(importId string, d *schema.ResourceData) error { 207 | importParts := strings.Split(importId, "/") 208 | errStr := "invalid import ID (%q), expected flow_sid/sid" 209 | 210 | if len(importParts) != 2 { 211 | return fmt.Errorf(errStr, importId) 212 | } 213 | 214 | d.Set("flow_sid", importParts[0]) 215 | d.Set("sid", importParts[1]) 216 | 217 | return nil 218 | } 219 | func updateFlowsExecutions(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 220 | params := UpdateExecutionParams{} 221 | if err := UnmarshalSchema(¶ms, d); err != nil { 222 | return diag.FromErr(err) 223 | } 224 | 225 | flowSid := d.Get("flow_sid").(string) 226 | sid := d.Get("sid").(string) 227 | 228 | r, err := m.(*client.Config).Client.StudioV1.UpdateExecution(flowSid, sid, ¶ms) 229 | if err != nil { 230 | return diag.FromErr(err) 231 | } 232 | 233 | err = MarshalSchema(d, r) 234 | if err != nil { 235 | return diag.FromErr(err) 236 | } 237 | 238 | return nil 239 | } 240 | -------------------------------------------------------------------------------- /twilio/resources/studio/v2/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_studio_flows_executions_v2 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **flow_sid** | string | **Required** | The SID of the Excecution's Flow. 9 | **to** | string | **Required** | The Contact phone number to start a Studio Flow Execution, available as variable `{{contact.channel.address}}`. 10 | **from** | string | **Required** | The Twilio phone number to send messages or initiate calls from during the Flow's Execution. Available as variable `{{flow.channel.address}}`. For SMS, this can also be a Messaging Service SID. 11 | **parameters** | string | Optional | JSON data that will be added to the Flow's context and that can be accessed as variables inside your Flow. For example, if you pass in `Parameters={\\\"name\\\":\\\"Zeke\\\"}`, a widget in your Flow can reference the variable `{{flow.data.name}}`, which returns \\\"Zeke\\\". Note: the JSON value must explicitly be passed as a string, not as a hash object. Depending on your particular HTTP library, you may need to add quotes or URL encode the JSON string. 12 | **sid** | string | *Computed* | The SID of the Execution resource to update. 13 | **status** | string | Optional | 14 | 15 | ## twilio_studio_flows_v2 16 | 17 | ### Parameters 18 | 19 | Name | Type | Requirement | Description 20 | --- | --- | --- | --- 21 | **friendly_name** | string | **Required** | The string that you assigned to describe the Flow. 22 | **status** | string | **Required** | 23 | **definition** | string | **Required** | JSON representation of flow definition. 24 | **commit_message** | string | Optional | Description of change made in the revision. 25 | **sid** | string | *Computed* | The SID of the Flow resource to fetch. 26 | 27 | -------------------------------------------------------------------------------- /twilio/resources/studio/v2/api_default.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This code was generated by 3 | * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ 4 | * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ 5 | * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ 6 | * 7 | * Twilio - Studio 8 | * This is the public Twilio REST API. 9 | * 10 | * NOTE: This class is auto generated by OpenAPI Generator. 11 | * https://openapi-generator.tech 12 | * Do not edit the class manually. 13 | */ 14 | 15 | package openapi 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | "strings" 21 | 22 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 23 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 24 | "github.com/twilio/terraform-provider-twilio/client" 25 | . "github.com/twilio/terraform-provider-twilio/core" 26 | . "github.com/twilio/twilio-go/rest/studio/v2" 27 | ) 28 | 29 | func ResourceFlowsExecutions() *schema.Resource { 30 | return &schema.Resource{ 31 | CreateContext: createFlowsExecutions, 32 | ReadContext: readFlowsExecutions, 33 | UpdateContext: updateFlowsExecutions, 34 | DeleteContext: deleteFlowsExecutions, 35 | Schema: map[string]*schema.Schema{ 36 | "flow_sid": AsString(SchemaRequired), 37 | "to": AsString(SchemaForceNewRequired), 38 | "from": AsString(SchemaForceNewRequired), 39 | "parameters": AsString(SchemaForceNewOptional), 40 | "sid": AsString(SchemaComputed), 41 | "status": AsString(SchemaComputedOptional), 42 | }, 43 | Importer: &schema.ResourceImporter{ 44 | StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { 45 | err := parseFlowsExecutionsImportId(d.Id(), d) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | return []*schema.ResourceData{d}, nil 51 | }, 52 | }, 53 | } 54 | } 55 | 56 | func createFlowsExecutions(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 57 | params := CreateExecutionParams{} 58 | if err := UnmarshalSchema(¶ms, d); err != nil { 59 | return diag.FromErr(err) 60 | } 61 | 62 | flowSid := d.Get("flow_sid").(string) 63 | 64 | r, err := m.(*client.Config).Client.StudioV2.CreateExecution(flowSid, ¶ms) 65 | if err != nil { 66 | return diag.FromErr(err) 67 | } 68 | 69 | idParts := []string{flowSid} 70 | idParts = append(idParts, (*r.Sid)) 71 | d.SetId(strings.Join(idParts, "/")) 72 | d.Set("sid", *r.Sid) 73 | 74 | return updateFlowsExecutions(ctx, d, m) 75 | } 76 | 77 | func deleteFlowsExecutions(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 78 | 79 | flowSid := d.Get("flow_sid").(string) 80 | sid := d.Get("sid").(string) 81 | 82 | err := m.(*client.Config).Client.StudioV2.DeleteExecution(flowSid, sid) 83 | if err != nil { 84 | return diag.FromErr(err) 85 | } 86 | 87 | d.SetId("") 88 | 89 | return nil 90 | } 91 | 92 | func readFlowsExecutions(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 93 | 94 | flowSid := d.Get("flow_sid").(string) 95 | sid := d.Get("sid").(string) 96 | 97 | r, err := m.(*client.Config).Client.StudioV2.FetchExecution(flowSid, sid) 98 | if err != nil { 99 | return diag.FromErr(err) 100 | } 101 | 102 | err = MarshalSchema(d, r) 103 | if err != nil { 104 | return diag.FromErr(err) 105 | } 106 | 107 | return nil 108 | } 109 | 110 | func parseFlowsExecutionsImportId(importId string, d *schema.ResourceData) error { 111 | importParts := strings.Split(importId, "/") 112 | errStr := "invalid import ID (%q), expected flow_sid/sid" 113 | 114 | if len(importParts) != 2 { 115 | return fmt.Errorf(errStr, importId) 116 | } 117 | 118 | d.Set("flow_sid", importParts[0]) 119 | d.Set("sid", importParts[1]) 120 | 121 | return nil 122 | } 123 | func updateFlowsExecutions(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 124 | params := UpdateExecutionParams{} 125 | if err := UnmarshalSchema(¶ms, d); err != nil { 126 | return diag.FromErr(err) 127 | } 128 | 129 | flowSid := d.Get("flow_sid").(string) 130 | sid := d.Get("sid").(string) 131 | 132 | r, err := m.(*client.Config).Client.StudioV2.UpdateExecution(flowSid, sid, ¶ms) 133 | if err != nil { 134 | return diag.FromErr(err) 135 | } 136 | 137 | err = MarshalSchema(d, r) 138 | if err != nil { 139 | return diag.FromErr(err) 140 | } 141 | 142 | return nil 143 | } 144 | 145 | func ResourceFlows() *schema.Resource { 146 | return &schema.Resource{ 147 | CreateContext: createFlows, 148 | ReadContext: readFlows, 149 | UpdateContext: updateFlows, 150 | DeleteContext: deleteFlows, 151 | Schema: map[string]*schema.Schema{ 152 | "friendly_name": AsString(SchemaRequired), 153 | "status": AsString(SchemaRequired), 154 | "definition": AsString(SchemaRequired), 155 | "commit_message": AsString(SchemaComputedOptional), 156 | "sid": AsString(SchemaComputed), 157 | }, 158 | Importer: &schema.ResourceImporter{ 159 | StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { 160 | err := parseFlowsImportId(d.Id(), d) 161 | if err != nil { 162 | return nil, err 163 | } 164 | 165 | return []*schema.ResourceData{d}, nil 166 | }, 167 | }, 168 | } 169 | } 170 | 171 | func createFlows(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 172 | params := CreateFlowParams{} 173 | if err := UnmarshalSchema(¶ms, d); err != nil { 174 | return diag.FromErr(err) 175 | } 176 | 177 | r, err := m.(*client.Config).Client.StudioV2.CreateFlow(¶ms) 178 | if err != nil { 179 | return diag.FromErr(err) 180 | } 181 | 182 | idParts := []string{} 183 | idParts = append(idParts, (*r.Sid)) 184 | d.SetId(strings.Join(idParts, "/")) 185 | 186 | err = MarshalSchema(d, r) 187 | if err != nil { 188 | return diag.FromErr(err) 189 | } 190 | 191 | return nil 192 | } 193 | 194 | func deleteFlows(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 195 | 196 | sid := d.Get("sid").(string) 197 | 198 | err := m.(*client.Config).Client.StudioV2.DeleteFlow(sid) 199 | if err != nil { 200 | return diag.FromErr(err) 201 | } 202 | 203 | d.SetId("") 204 | 205 | return nil 206 | } 207 | 208 | func readFlows(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 209 | 210 | sid := d.Get("sid").(string) 211 | 212 | r, err := m.(*client.Config).Client.StudioV2.FetchFlow(sid) 213 | if err != nil { 214 | return diag.FromErr(err) 215 | } 216 | 217 | err = MarshalSchema(d, r) 218 | if err != nil { 219 | return diag.FromErr(err) 220 | } 221 | 222 | return nil 223 | } 224 | 225 | func parseFlowsImportId(importId string, d *schema.ResourceData) error { 226 | importParts := strings.Split(importId, "/") 227 | errStr := "invalid import ID (%q), expected sid" 228 | 229 | if len(importParts) != 1 { 230 | return fmt.Errorf(errStr, importId) 231 | } 232 | 233 | d.Set("sid", importParts[0]) 234 | 235 | return nil 236 | } 237 | func updateFlows(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 238 | params := UpdateFlowParams{} 239 | if err := UnmarshalSchema(¶ms, d); err != nil { 240 | return diag.FromErr(err) 241 | } 242 | 243 | sid := d.Get("sid").(string) 244 | 245 | r, err := m.(*client.Config).Client.StudioV2.UpdateFlow(sid, ¶ms) 246 | if err != nil { 247 | return diag.FromErr(err) 248 | } 249 | 250 | err = MarshalSchema(d, r) 251 | if err != nil { 252 | return diag.FromErr(err) 253 | } 254 | 255 | return nil 256 | } 257 | -------------------------------------------------------------------------------- /twilio/resources/supersim/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_supersim_network_access_profiles_networks_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **network_access_profile_sid** | string | **Required** | The unique string that identifies the Network Access Profile resource. 9 | **network** | string | **Required** | The SID of the Network resource to be added to the Network Access Profile resource. 10 | **sid** | string | *Computed* | The SID of the Network resource to fetch. 11 | 12 | -------------------------------------------------------------------------------- /twilio/resources/supersim/v1/api_default.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This code was generated by 3 | * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ 4 | * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ 5 | * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ 6 | * 7 | * Twilio - Supersim 8 | * This is the public Twilio REST API. 9 | * 10 | * NOTE: This class is auto generated by OpenAPI Generator. 11 | * https://openapi-generator.tech 12 | * Do not edit the class manually. 13 | */ 14 | 15 | package openapi 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | "strings" 21 | 22 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 23 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 24 | "github.com/twilio/terraform-provider-twilio/client" 25 | . "github.com/twilio/terraform-provider-twilio/core" 26 | . "github.com/twilio/twilio-go/rest/supersim/v1" 27 | ) 28 | 29 | func ResourceNetworkAccessProfilesNetworks() *schema.Resource { 30 | return &schema.Resource{ 31 | CreateContext: createNetworkAccessProfilesNetworks, 32 | ReadContext: readNetworkAccessProfilesNetworks, 33 | DeleteContext: deleteNetworkAccessProfilesNetworks, 34 | Schema: map[string]*schema.Schema{ 35 | "network_access_profile_sid": AsString(SchemaForceNewRequired), 36 | "network": AsString(SchemaForceNewRequired), 37 | "sid": AsString(SchemaComputed), 38 | }, 39 | Importer: &schema.ResourceImporter{ 40 | StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { 41 | err := parseNetworkAccessProfilesNetworksImportId(d.Id(), d) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | return []*schema.ResourceData{d}, nil 47 | }, 48 | }, 49 | } 50 | } 51 | 52 | func createNetworkAccessProfilesNetworks(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 53 | params := CreateNetworkAccessProfileNetworkParams{} 54 | if err := UnmarshalSchema(¶ms, d); err != nil { 55 | return diag.FromErr(err) 56 | } 57 | 58 | networkAccessProfileSid := d.Get("network_access_profile_sid").(string) 59 | 60 | r, err := m.(*client.Config).Client.SupersimV1.CreateNetworkAccessProfileNetwork(networkAccessProfileSid, ¶ms) 61 | if err != nil { 62 | return diag.FromErr(err) 63 | } 64 | 65 | idParts := []string{networkAccessProfileSid} 66 | idParts = append(idParts, (*r.Sid)) 67 | d.SetId(strings.Join(idParts, "/")) 68 | 69 | err = MarshalSchema(d, r) 70 | if err != nil { 71 | return diag.FromErr(err) 72 | } 73 | 74 | return nil 75 | } 76 | 77 | func deleteNetworkAccessProfilesNetworks(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 78 | 79 | networkAccessProfileSid := d.Get("network_access_profile_sid").(string) 80 | sid := d.Get("sid").(string) 81 | 82 | err := m.(*client.Config).Client.SupersimV1.DeleteNetworkAccessProfileNetwork(networkAccessProfileSid, sid) 83 | if err != nil { 84 | return diag.FromErr(err) 85 | } 86 | 87 | d.SetId("") 88 | 89 | return nil 90 | } 91 | 92 | func readNetworkAccessProfilesNetworks(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 93 | 94 | networkAccessProfileSid := d.Get("network_access_profile_sid").(string) 95 | sid := d.Get("sid").(string) 96 | 97 | r, err := m.(*client.Config).Client.SupersimV1.FetchNetworkAccessProfileNetwork(networkAccessProfileSid, sid) 98 | if err != nil { 99 | return diag.FromErr(err) 100 | } 101 | 102 | err = MarshalSchema(d, r) 103 | if err != nil { 104 | return diag.FromErr(err) 105 | } 106 | 107 | return nil 108 | } 109 | 110 | func parseNetworkAccessProfilesNetworksImportId(importId string, d *schema.ResourceData) error { 111 | importParts := strings.Split(importId, "/") 112 | errStr := "invalid import ID (%q), expected network_access_profile_sid/sid" 113 | 114 | if len(importParts) != 2 { 115 | return fmt.Errorf(errStr, importId) 116 | } 117 | 118 | d.Set("network_access_profile_sid", importParts[0]) 119 | d.Set("sid", importParts[1]) 120 | 121 | return nil 122 | } 123 | -------------------------------------------------------------------------------- /twilio/resources/trunking/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_trunking_trunks_credential_lists_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **trunk_sid** | string | **Required** | The SID of the Trunk to associate the credential list with. 9 | **credential_list_sid** | string | **Required** | The SID of the [Credential List](https://www.twilio.com/docs/voice/sip/api/sip-credentiallist-resource) that you want to associate with the trunk. Once associated, we will authenticate access to the trunk against this list. 10 | **sid** | string | *Computed* | The unique string that we created to identify the CredentialList resource to fetch. 11 | 12 | ## twilio_trunking_trunks_ip_access_control_lists_v1 13 | 14 | ### Parameters 15 | 16 | Name | Type | Requirement | Description 17 | --- | --- | --- | --- 18 | **trunk_sid** | string | **Required** | The SID of the Trunk to associate the IP Access Control List with. 19 | **ip_access_control_list_sid** | string | **Required** | The SID of the [IP Access Control List](https://www.twilio.com/docs/voice/sip/api/sip-ipaccesscontrollist-resource) that you want to associate with the trunk. 20 | **sid** | string | *Computed* | The unique string that we created to identify the IpAccessControlList resource to fetch. 21 | 22 | ## twilio_trunking_trunks_origination_urls_v1 23 | 24 | ### Parameters 25 | 26 | Name | Type | Requirement | Description 27 | --- | --- | --- | --- 28 | **trunk_sid** | string | **Required** | The SID of the Trunk to associate the resource with. 29 | **weight** | int | **Required** | The value that determines the relative share of the load the URI should receive compared to other URIs with the same priority. Can be an integer from 1 to 65535, inclusive, and the default is 10. URLs with higher values receive more load than those with lower ones with the same priority. 30 | **priority** | int | **Required** | The relative importance of the URI. Can be an integer from 0 to 65535, inclusive, and the default is 10. The lowest number represents the most important URI. 31 | **enabled** | bool | **Required** | Whether the URL is enabled. The default is `true`. 32 | **friendly_name** | string | **Required** | A descriptive string that you create to describe the resource. It can be up to 64 characters long. 33 | **sip_url** | string | **Required** | The SIP address you want Twilio to route your Origination calls to. This must be a `sip:` schema. 34 | **sid** | string | *Computed* | The unique string that we created to identify the OriginationUrl resource to update. 35 | 36 | ## twilio_trunking_trunks_phone_numbers_v1 37 | 38 | ### Parameters 39 | 40 | Name | Type | Requirement | Description 41 | --- | --- | --- | --- 42 | **trunk_sid** | string | **Required** | The SID of the Trunk to associate the phone number with. 43 | **phone_number_sid** | string | **Required** | The SID of the [Incoming Phone Number](https://www.twilio.com/docs/phone-numbers/api/incomingphonenumber-resource) that you want to associate with the trunk. 44 | **sid** | string | *Computed* | The unique string that we created to identify the PhoneNumber resource to fetch. 45 | 46 | ## twilio_trunking_trunks_v1 47 | 48 | ### Parameters 49 | 50 | Name | Type | Requirement | Description 51 | --- | --- | --- | --- 52 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It can be up to 64 characters long. 53 | **domain_name** | string | Optional | The unique address you reserve on Twilio to which you route your SIP traffic. Domain names can contain letters, digits, and `-` and must end with `pstn.twilio.com`. See [Termination Settings](https://www.twilio.com/docs/sip-trunking#termination) for more information. 54 | **disaster_recovery_url** | string | Optional | The URL we should call using the `disaster_recovery_method` if an error occurs while sending SIP traffic towards the configured Origination URL. We retrieve TwiML from the URL and execute the instructions like any other normal TwiML call. See [Disaster Recovery](https://www.twilio.com/docs/sip-trunking#disaster-recovery) for more information. 55 | **disaster_recovery_method** | string | Optional | The HTTP method we should use to call the `disaster_recovery_url`. Can be: `GET` or `POST`. 56 | **transfer_mode** | string | Optional | 57 | **secure** | bool | Optional | Whether Secure Trunking is enabled for the trunk. If enabled, all calls going through the trunk will be secure using SRTP for media and TLS for signaling. If disabled, then RTP will be used for media. See [Secure Trunking](https://www.twilio.com/docs/sip-trunking#securetrunking) for more information. 58 | **cnam_lookup_enabled** | bool | Optional | Whether Caller ID Name (CNAM) lookup should be enabled for the trunk. If enabled, all inbound calls to the SIP Trunk from the United States and Canada automatically perform a CNAM Lookup and display Caller ID data on your phone. See [CNAM Lookups](https://www.twilio.com/docs/sip-trunking#CNAM) for more information. 59 | **transfer_caller_id** | string | Optional | 60 | **sid** | string | *Computed* | The unique string that we created to identify the OriginationUrl resource to update. 61 | 62 | -------------------------------------------------------------------------------- /twilio/resources/trusthub/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_trusthub_customer_profiles_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **friendly_name** | string | **Required** | The string that you assigned to describe the resource. 9 | **email** | string | **Required** | The email address that will receive updates when the Customer-Profile resource changes status. 10 | **policy_sid** | string | **Required** | The unique string of a policy that is associated to the Customer-Profile resource. 11 | **status_callback** | string | Optional | The URL we call to inform your application of status changes. 12 | **sid** | string | *Computed* | The unique string that we created to identify the Customer-Profile resource. 13 | **status** | string | Optional | 14 | 15 | ## twilio_trusthub_customer_profiles_channel_endpoint_assignments_v1 16 | 17 | ### Parameters 18 | 19 | Name | Type | Requirement | Description 20 | --- | --- | --- | --- 21 | **customer_profile_sid** | string | **Required** | The unique string that we created to identify the CustomerProfile resource. 22 | **channel_endpoint_type** | string | **Required** | The type of channel endpoint. eg: phone-number 23 | **channel_endpoint_sid** | string | **Required** | The SID of an channel endpoint 24 | **sid** | string | *Computed* | The unique string that we created to identify the resource. 25 | 26 | ## twilio_trusthub_customer_profiles_entity_assignments_v1 27 | 28 | ### Parameters 29 | 30 | Name | Type | Requirement | Description 31 | --- | --- | --- | --- 32 | **customer_profile_sid** | string | **Required** | The unique string that we created to identify the CustomerProfile resource. 33 | **object_sid** | string | **Required** | The SID of an object bag that holds information of the different items. 34 | **sid** | string | *Computed* | The unique string that we created to identify the Identity resource. 35 | 36 | ## twilio_trusthub_end_users_v1 37 | 38 | ### Parameters 39 | 40 | Name | Type | Requirement | Description 41 | --- | --- | --- | --- 42 | **friendly_name** | string | **Required** | The string that you assigned to describe the resource. 43 | **type** | string | **Required** | The type of end user of the Bundle resource - can be `individual` or `business`. 44 | **attributes** | string | Optional | The set of parameters that are the attributes of the End User resource which are derived End User Types. 45 | **sid** | string | *Computed* | The unique string created by Twilio to identify the End User resource. 46 | 47 | ## twilio_trusthub_supporting_documents_v1 48 | 49 | ### Parameters 50 | 51 | Name | Type | Requirement | Description 52 | --- | --- | --- | --- 53 | **friendly_name** | string | **Required** | The string that you assigned to describe the resource. 54 | **type** | string | **Required** | The type of the Supporting Document. 55 | **attributes** | string | Optional | The set of parameters that are the attributes of the Supporting Documents resource which are derived Supporting Document Types. 56 | **sid** | string | *Computed* | The unique string created by Twilio to identify the Supporting Document resource. 57 | 58 | ## twilio_trusthub_trust_products_v1 59 | 60 | ### Parameters 61 | 62 | Name | Type | Requirement | Description 63 | --- | --- | --- | --- 64 | **friendly_name** | string | **Required** | The string that you assigned to describe the resource. 65 | **email** | string | **Required** | The email address that will receive updates when the Trust Product resource changes status. 66 | **policy_sid** | string | **Required** | The unique string of a policy that is associated to the Trust Product resource. 67 | **status_callback** | string | Optional | The URL we call to inform your application of status changes. 68 | **sid** | string | *Computed* | The unique string that we created to identify the Trust Product resource. 69 | **status** | string | Optional | 70 | 71 | ## twilio_trusthub_trust_products_channel_endpoint_assignments_v1 72 | 73 | ### Parameters 74 | 75 | Name | Type | Requirement | Description 76 | --- | --- | --- | --- 77 | **trust_product_sid** | string | **Required** | The unique string that we created to identify the CustomerProfile resource. 78 | **channel_endpoint_type** | string | **Required** | The type of channel endpoint. eg: phone-number 79 | **channel_endpoint_sid** | string | **Required** | The SID of an channel endpoint 80 | **sid** | string | *Computed* | The unique string that we created to identify the resource. 81 | 82 | ## twilio_trusthub_trust_products_entity_assignments_v1 83 | 84 | ### Parameters 85 | 86 | Name | Type | Requirement | Description 87 | --- | --- | --- | --- 88 | **trust_product_sid** | string | **Required** | The unique string that we created to identify the TrustProduct resource. 89 | **object_sid** | string | **Required** | The SID of an object bag that holds information of the different items. 90 | **sid** | string | *Computed* | The unique string that we created to identify the Identity resource. 91 | 92 | -------------------------------------------------------------------------------- /twilio/resources/video/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_video_compositions_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **room_sid** | string | **Required** | The SID of the Group Room with the media tracks to be used as composition sources. 9 | **video_layout** | string | Optional | An object that describes the video layout of the composition in terms of regions. See [Specifying Video Layouts](https://www.twilio.com/docs/video/api/compositions-resource#specifying-video-layouts) for more info. Please, be aware that either video_layout or audio_sources have to be provided to get a valid creation request 10 | **audio_sources** | list(string) | Optional | An array of track names from the same group room to merge into the new composition. Can include zero or more track names. The new composition includes all audio sources specified in `audio_sources` except for those specified in `audio_sources_excluded`. The track names in this parameter can include an asterisk as a wild card character, which will match zero or more characters in a track name. For example, `student*` includes `student` as well as `studentTeam`. Please, be aware that either video_layout or audio_sources have to be provided to get a valid creation request 11 | **audio_sources_excluded** | list(string) | Optional | An array of track names to exclude. The new composition includes all audio sources specified in `audio_sources` except for those specified in `audio_sources_excluded`. The track names in this parameter can include an asterisk as a wild card character, which will match zero or more characters in a track name. For example, `student*` excludes `student` as well as `studentTeam`. This parameter can also be empty. 12 | **resolution** | string | Optional | A string that describes the columns (width) and rows (height) of the generated composed video in pixels. Defaults to `640x480`. The string's format is `{width}x{height}` where: * 16 <= `{width}` <= 1280 * 16 <= `{height}` <= 1280 * `{width}` * `{height}` <= 921,600 Typical values are: * HD = `1280x720` * PAL = `1024x576` * VGA = `640x480` * CIF = `320x240` Note that the `resolution` imposes an aspect ratio to the resulting composition. When the original video tracks are constrained by the aspect ratio, they are scaled to fit. See [Specifying Video Layouts](https://www.twilio.com/docs/video/api/compositions-resource#specifying-video-layouts) for more info. 13 | **format** | string | Optional | 14 | **status_callback** | string | Optional | The URL we should call using the `status_callback_method` to send status information to your application on every composition event. If not provided, status callback events will not be dispatched. 15 | **status_callback_method** | string | Optional | The HTTP method we should use to call `status_callback`. Can be: `POST` or `GET` and the default is `POST`. 16 | **trim** | bool | Optional | Whether to clip the intervals where there is no active media in the composition. The default is `true`. Compositions with `trim` enabled are shorter when the Room is created and no Participant joins for a while as well as if all the Participants leave the room and join later, because those gaps will be removed. See [Specifying Video Layouts](https://www.twilio.com/docs/video/api/compositions-resource#specifying-video-layouts) for more info. 17 | **sid** | string | *Computed* | The SID of the Composition resource to fetch. 18 | 19 | ## twilio_video_composition_hooks_v1 20 | 21 | ### Parameters 22 | 23 | Name | Type | Requirement | Description 24 | --- | --- | --- | --- 25 | **friendly_name** | string | **Required** | A descriptive string that you create to describe the resource. It can be up to 100 characters long and it must be unique within the account. 26 | **enabled** | bool | Optional | Whether the composition hook is active. When `true`, the composition hook will be triggered for every completed Group Room in the account. When `false`, the composition hook will never be triggered. 27 | **video_layout** | string | Optional | An object that describes the video layout of the composition hook in terms of regions. See [Specifying Video Layouts](https://www.twilio.com/docs/video/api/compositions-resource#specifying-video-layouts) for more info. 28 | **audio_sources** | list(string) | Optional | An array of track names from the same group room to merge into the compositions created by the composition hook. Can include zero or more track names. A composition triggered by the composition hook includes all audio sources specified in `audio_sources` except those specified in `audio_sources_excluded`. The track names in this parameter can include an asterisk as a wild card character, which matches zero or more characters in a track name. For example, `student*` includes tracks named `student` as well as `studentTeam`. 29 | **audio_sources_excluded** | list(string) | Optional | An array of track names to exclude. A composition triggered by the composition hook includes all audio sources specified in `audio_sources` except for those specified in `audio_sources_excluded`. The track names in this parameter can include an asterisk as a wild card character, which matches zero or more characters in a track name. For example, `student*` excludes `student` as well as `studentTeam`. This parameter can also be empty. 30 | **resolution** | string | Optional | A string that describes the columns (width) and rows (height) of the generated composed video in pixels. Defaults to `640x480`. The string's format is `{width}x{height}` where: * 16 <= `{width}` <= 1280 * 16 <= `{height}` <= 1280 * `{width}` * `{height}` <= 921,600 Typical values are: * HD = `1280x720` * PAL = `1024x576` * VGA = `640x480` * CIF = `320x240` Note that the `resolution` imposes an aspect ratio to the resulting composition. When the original video tracks are constrained by the aspect ratio, they are scaled to fit. See [Specifying Video Layouts](https://www.twilio.com/docs/video/api/compositions-resource#specifying-video-layouts) for more info. 31 | **format** | string | Optional | 32 | **status_callback** | string | Optional | The URL we should call using the `status_callback_method` to send status information to your application on every composition event. If not provided, status callback events will not be dispatched. 33 | **status_callback_method** | string | Optional | The HTTP method we should use to call `status_callback`. Can be: `POST` or `GET` and the default is `POST`. 34 | **trim** | bool | Optional | Whether to clip the intervals where there is no active media in the Compositions triggered by the composition hook. The default is `true`. Compositions with `trim` enabled are shorter when the Room is created and no Participant joins for a while as well as if all the Participants leave the room and join later, because those gaps will be removed. See [Specifying Video Layouts](https://www.twilio.com/docs/video/api/compositions-resource#specifying-video-layouts) for more info. 35 | **sid** | string | *Computed* | The SID of the CompositionHook resource to update. 36 | 37 | -------------------------------------------------------------------------------- /twilio/resources/voice/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_voice_byoc_trunks_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It is not unique and can be up to 255 characters long. 9 | **voice_url** | string | Optional | The URL we should call when the BYOC Trunk receives a call. 10 | **voice_method** | string | Optional | The HTTP method we should use to call `voice_url`. Can be: `GET` or `POST`. 11 | **voice_fallback_url** | string | Optional | The URL that we should call when an error occurs while retrieving or executing the TwiML from `voice_url`. 12 | **voice_fallback_method** | string | Optional | The HTTP method we should use to call `voice_fallback_url`. Can be: `GET` or `POST`. 13 | **status_callback_url** | string | Optional | The URL that we should call to pass status parameters (such as call ended) to your application. 14 | **status_callback_method** | string | Optional | The HTTP method we should use to call `status_callback_url`. Can be: `GET` or `POST`. 15 | **cnam_lookup_enabled** | bool | Optional | Whether Caller ID Name (CNAM) lookup is enabled for the trunk. If enabled, all inbound calls to the BYOC Trunk from the United States and Canada automatically perform a CNAM Lookup and display Caller ID data on your phone. See [CNAM Lookups](https://www.twilio.com/docs/sip-trunking#CNAM) for more information. 16 | **connection_policy_sid** | string | Optional | The SID of the Connection Policy that Twilio will use when routing traffic to your communications infrastructure. 17 | **from_domain_sid** | string | Optional | The SID of the SIP Domain that should be used in the `From` header of originating calls sent to your SIP infrastructure. If your SIP infrastructure allows users to \\\"call back\\\" an incoming call, configure this with a [SIP Domain](https://www.twilio.com/docs/voice/api/sending-sip) to ensure proper routing. If not configured, the from domain will default to \\\"sip.twilio.com\\\". 18 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the BYOC Trunk resource to update. 19 | 20 | ## twilio_voice_connection_policies_v1 21 | 22 | ### Parameters 23 | 24 | Name | Type | Requirement | Description 25 | --- | --- | --- | --- 26 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It is not unique and can be up to 255 characters long. 27 | **sid** | string | *Computed* | The unique string that we created to identify the Connection Policy resource to update. 28 | 29 | ## twilio_voice_connection_policies_targets_v1 30 | 31 | ### Parameters 32 | 33 | Name | Type | Requirement | Description 34 | --- | --- | --- | --- 35 | **connection_policy_sid** | string | **Required** | The SID of the Connection Policy that owns the Target. 36 | **target** | string | **Required** | The SIP address you want Twilio to route your calls to. This must be a `sip:` schema. `sips` is NOT supported. 37 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It is not unique and can be up to 255 characters long. 38 | **priority** | int | Optional | The relative importance of the target. Can be an integer from 0 to 65535, inclusive, and the default is 10. The lowest number represents the most important target. 39 | **weight** | int | Optional | The value that determines the relative share of the load the Target should receive compared to other Targets with the same priority. Can be an integer from 1 to 65535, inclusive, and the default is 10. Targets with higher values receive more load than those with lower ones with the same priority. 40 | **enabled** | bool | Optional | Whether the Target is enabled. The default is `true`. 41 | **sid** | string | *Computed* | The unique string that we created to identify the Target resource to update. 42 | 43 | ## twilio_voice_ip_records_v1 44 | 45 | ### Parameters 46 | 47 | Name | Type | Requirement | Description 48 | --- | --- | --- | --- 49 | **ip_address** | string | **Required** | An IP address in dotted decimal notation, IPv4 only. 50 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It is not unique and can be up to 255 characters long. 51 | **cidr_prefix_length** | int | Optional | An integer representing the length of the [CIDR](https://tools.ietf.org/html/rfc4632) prefix to use with this IP address. By default the entire IP address is used, which for IPv4 is value 32. 52 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the IP Record resource to update. 53 | 54 | ## twilio_voice_source_ip_mappings_v1 55 | 56 | ### Parameters 57 | 58 | Name | Type | Requirement | Description 59 | --- | --- | --- | --- 60 | **ip_record_sid** | string | **Required** | The Twilio-provided string that uniquely identifies the IP Record resource to map from. 61 | **sip_domain_sid** | string | **Required** | The SID of the SIP Domain that the IP Record should be mapped to. 62 | **sid** | string | *Computed* | The Twilio-provided string that uniquely identifies the IP Record resource to update. 63 | 64 | -------------------------------------------------------------------------------- /twilio/resources/wireless/v1/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## twilio_wireless_commands_v1 3 | 4 | ### Parameters 5 | 6 | Name | Type | Requirement | Description 7 | --- | --- | --- | --- 8 | **command** | string | **Required** | The message body of the Command. Can be plain text in text mode or a Base64 encoded byte string in binary mode. 9 | **sim** | string | Optional | The `sid` or `unique_name` of the [SIM](https://www.twilio.com/docs/iot/wireless/api/sim-resource) to send the Command to. 10 | **callback_method** | string | Optional | The HTTP method we use to call `callback_url`. Can be: `POST` or `GET`, and the default is `POST`. 11 | **callback_url** | string | Optional | The URL we call using the `callback_url` when the Command has finished sending, whether the command was delivered or it failed. 12 | **command_mode** | string | Optional | 13 | **include_sid** | string | Optional | Whether to include the SID of the command in the message body. Can be: `none`, `start`, or `end`, and the default behavior is `none`. When sending a Command to a SIM in text mode, we can automatically include the SID of the Command in the message body, which could be used to ensure that the device does not process the same Command more than once. A value of `start` will prepend the message with the Command SID, and `end` will append it to the end, separating the Command SID from the message body with a space. The length of the Command SID is included in the 160 character limit so the SMS body must be 128 characters or less before the Command SID is included. 14 | **delivery_receipt_requested** | bool | Optional | Whether to request delivery receipt from the recipient. For Commands that request delivery receipt, the Command state transitions to 'delivered' once the server has received a delivery receipt from the device. The default value is `true`. 15 | **sid** | string | *Computed* | The SID of the Command resource to fetch. 16 | 17 | ## twilio_wireless_rate_plans_v1 18 | 19 | ### Parameters 20 | 21 | Name | Type | Requirement | Description 22 | --- | --- | --- | --- 23 | **unique_name** | string | Optional | An application-defined string that uniquely identifies the resource. It can be used in place of the resource's `sid` in the URL to address the resource. 24 | **friendly_name** | string | Optional | A descriptive string that you create to describe the resource. It does not have to be unique. 25 | **data_enabled** | bool | Optional | Whether SIMs can use GPRS/3G/4G/LTE data connectivity. 26 | **data_limit** | int | Optional | The total data usage (download and upload combined) in Megabytes that the Network allows during one month on the home network (T-Mobile USA). The metering period begins the day of activation and ends on the same day in the following month. Can be up to 2TB and the default value is `1000`. 27 | **data_metering** | string | Optional | The model used to meter data usage. Can be: `payg` and `quota-1`, `quota-10`, and `quota-50`. Learn more about the available [data metering models](https://www.twilio.com/docs/iot/wireless/api/rateplan-resource#payg-vs-quota-data-plans). 28 | **messaging_enabled** | bool | Optional | Whether SIMs can make, send, and receive SMS using [Commands](https://www.twilio.com/docs/iot/wireless/api/command-resource). 29 | **voice_enabled** | bool | Optional | Deprecated. 30 | **national_roaming_enabled** | bool | Optional | Whether SIMs can roam on networks other than the home network (T-Mobile USA) in the United States. See [national roaming](https://www.twilio.com/docs/iot/wireless/api/rateplan-resource#national-roaming). 31 | **international_roaming** | list(string) | Optional | The list of services that SIMs capable of using GPRS/3G/4G/LTE data connectivity can use outside of the United States. Can contain: `data` and `messaging`. 32 | **national_roaming_data_limit** | int | Optional | The total data usage (download and upload combined) in Megabytes that the Network allows during one month on non-home networks in the United States. The metering period begins the day of activation and ends on the same day in the following month. Can be up to 2TB. See [national roaming](https://www.twilio.com/docs/iot/wireless/api/rateplan-resource#national-roaming) for more info. 33 | **international_roaming_data_limit** | int | Optional | The total data usage (download and upload combined) in Megabytes that the Network allows during one month when roaming outside the United States. Can be up to 2TB. 34 | **sid** | string | *Computed* | The SID of the RatePlan resource to update. 35 | 36 | -------------------------------------------------------------------------------- /twilio/resources/wireless/v1/api_default.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This code was generated by 3 | * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ 4 | * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ 5 | * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ 6 | * 7 | * Twilio - Wireless 8 | * This is the public Twilio REST API. 9 | * 10 | * NOTE: This class is auto generated by OpenAPI Generator. 11 | * https://openapi-generator.tech 12 | * Do not edit the class manually. 13 | */ 14 | 15 | package openapi 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | "strings" 21 | 22 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 23 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 24 | "github.com/twilio/terraform-provider-twilio/client" 25 | . "github.com/twilio/terraform-provider-twilio/core" 26 | . "github.com/twilio/twilio-go/rest/wireless/v1" 27 | ) 28 | 29 | func ResourceCommands() *schema.Resource { 30 | return &schema.Resource{ 31 | CreateContext: createCommands, 32 | ReadContext: readCommands, 33 | DeleteContext: deleteCommands, 34 | Schema: map[string]*schema.Schema{ 35 | "command": AsString(SchemaForceNewRequired), 36 | "sim": AsString(SchemaForceNewOptional), 37 | "callback_method": AsString(SchemaForceNewOptional), 38 | "callback_url": AsString(SchemaForceNewOptional), 39 | "command_mode": AsString(SchemaForceNewOptional), 40 | "include_sid": AsString(SchemaForceNewOptional), 41 | "delivery_receipt_requested": AsBool(SchemaForceNewOptional), 42 | "sid": AsString(SchemaComputed), 43 | }, 44 | Importer: &schema.ResourceImporter{ 45 | StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { 46 | err := parseCommandsImportId(d.Id(), d) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | return []*schema.ResourceData{d}, nil 52 | }, 53 | }, 54 | } 55 | } 56 | 57 | func createCommands(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 58 | params := CreateCommandParams{} 59 | if err := UnmarshalSchema(¶ms, d); err != nil { 60 | return diag.FromErr(err) 61 | } 62 | 63 | r, err := m.(*client.Config).Client.WirelessV1.CreateCommand(¶ms) 64 | if err != nil { 65 | return diag.FromErr(err) 66 | } 67 | 68 | idParts := []string{} 69 | idParts = append(idParts, (*r.Sid)) 70 | d.SetId(strings.Join(idParts, "/")) 71 | 72 | err = MarshalSchema(d, r) 73 | if err != nil { 74 | return diag.FromErr(err) 75 | } 76 | 77 | return nil 78 | } 79 | 80 | func deleteCommands(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 81 | 82 | sid := d.Get("sid").(string) 83 | 84 | err := m.(*client.Config).Client.WirelessV1.DeleteCommand(sid) 85 | if err != nil { 86 | return diag.FromErr(err) 87 | } 88 | 89 | d.SetId("") 90 | 91 | return nil 92 | } 93 | 94 | func readCommands(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 95 | 96 | sid := d.Get("sid").(string) 97 | 98 | r, err := m.(*client.Config).Client.WirelessV1.FetchCommand(sid) 99 | if err != nil { 100 | return diag.FromErr(err) 101 | } 102 | 103 | err = MarshalSchema(d, r) 104 | if err != nil { 105 | return diag.FromErr(err) 106 | } 107 | 108 | return nil 109 | } 110 | 111 | func parseCommandsImportId(importId string, d *schema.ResourceData) error { 112 | importParts := strings.Split(importId, "/") 113 | errStr := "invalid import ID (%q), expected sid" 114 | 115 | if len(importParts) != 1 { 116 | return fmt.Errorf(errStr, importId) 117 | } 118 | 119 | d.Set("sid", importParts[0]) 120 | 121 | return nil 122 | } 123 | func ResourceRatePlans() *schema.Resource { 124 | return &schema.Resource{ 125 | CreateContext: createRatePlans, 126 | ReadContext: readRatePlans, 127 | UpdateContext: updateRatePlans, 128 | DeleteContext: deleteRatePlans, 129 | Schema: map[string]*schema.Schema{ 130 | "unique_name": AsString(SchemaComputedOptional), 131 | "friendly_name": AsString(SchemaComputedOptional), 132 | "data_enabled": AsBool(SchemaForceNewOptional), 133 | "data_limit": AsInt(SchemaForceNewOptional), 134 | "data_metering": AsString(SchemaForceNewOptional), 135 | "messaging_enabled": AsBool(SchemaForceNewOptional), 136 | "voice_enabled": AsBool(SchemaForceNewOptional), 137 | "national_roaming_enabled": AsBool(SchemaForceNewOptional), 138 | "international_roaming": AsList(AsString(SchemaForceNewOptional), SchemaForceNewOptional), 139 | "national_roaming_data_limit": AsInt(SchemaForceNewOptional), 140 | "international_roaming_data_limit": AsInt(SchemaForceNewOptional), 141 | "sid": AsString(SchemaComputed), 142 | }, 143 | Importer: &schema.ResourceImporter{ 144 | StateContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { 145 | err := parseRatePlansImportId(d.Id(), d) 146 | if err != nil { 147 | return nil, err 148 | } 149 | 150 | return []*schema.ResourceData{d}, nil 151 | }, 152 | }, 153 | } 154 | } 155 | 156 | func createRatePlans(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 157 | params := CreateRatePlanParams{} 158 | if err := UnmarshalSchema(¶ms, d); err != nil { 159 | return diag.FromErr(err) 160 | } 161 | 162 | r, err := m.(*client.Config).Client.WirelessV1.CreateRatePlan(¶ms) 163 | if err != nil { 164 | return diag.FromErr(err) 165 | } 166 | 167 | idParts := []string{} 168 | idParts = append(idParts, (*r.Sid)) 169 | d.SetId(strings.Join(idParts, "/")) 170 | 171 | err = MarshalSchema(d, r) 172 | if err != nil { 173 | return diag.FromErr(err) 174 | } 175 | 176 | return nil 177 | } 178 | 179 | func deleteRatePlans(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 180 | 181 | sid := d.Get("sid").(string) 182 | 183 | err := m.(*client.Config).Client.WirelessV1.DeleteRatePlan(sid) 184 | if err != nil { 185 | return diag.FromErr(err) 186 | } 187 | 188 | d.SetId("") 189 | 190 | return nil 191 | } 192 | 193 | func readRatePlans(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 194 | 195 | sid := d.Get("sid").(string) 196 | 197 | r, err := m.(*client.Config).Client.WirelessV1.FetchRatePlan(sid) 198 | if err != nil { 199 | return diag.FromErr(err) 200 | } 201 | 202 | err = MarshalSchema(d, r) 203 | if err != nil { 204 | return diag.FromErr(err) 205 | } 206 | 207 | return nil 208 | } 209 | 210 | func parseRatePlansImportId(importId string, d *schema.ResourceData) error { 211 | importParts := strings.Split(importId, "/") 212 | errStr := "invalid import ID (%q), expected sid" 213 | 214 | if len(importParts) != 1 { 215 | return fmt.Errorf(errStr, importId) 216 | } 217 | 218 | d.Set("sid", importParts[0]) 219 | 220 | return nil 221 | } 222 | func updateRatePlans(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { 223 | params := UpdateRatePlanParams{} 224 | if err := UnmarshalSchema(¶ms, d); err != nil { 225 | return diag.FromErr(err) 226 | } 227 | 228 | sid := d.Get("sid").(string) 229 | 230 | r, err := m.(*client.Config).Client.WirelessV1.UpdateRatePlan(sid, ¶ms) 231 | if err != nil { 232 | return diag.FromErr(err) 233 | } 234 | 235 | err = MarshalSchema(d, r) 236 | if err != nil { 237 | return diag.FromErr(err) 238 | } 239 | 240 | return nil 241 | } 242 | -------------------------------------------------------------------------------- /twilio/resources_flex_test.go: -------------------------------------------------------------------------------- 1 | package twilio 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 11 | . "github.com/twilio/terraform-provider-twilio/client" 12 | ) 13 | 14 | func TestAccFlexSetup_basic(t *testing.T) { 15 | flexResourceName := "twilio_flex_flex_flows_v1.flows" 16 | chatResourceName := "twilio_chat_services_v2.chat_service" 17 | studioResourceName := "twilio_studio_flows_v2.studio_flow" 18 | 19 | chatServiceName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) 20 | studioFlowName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) 21 | flexName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) 22 | 23 | resource.Test(t, resource.TestCase{ 24 | IsUnitTest: false, 25 | PreCheck: func() { testAccPreCheck(t) }, 26 | ProviderFactories: testAccProviderFactories, 27 | PreventPostDestroyRefresh: false, 28 | CheckDestroy: testAccFlexInstanceDestroy, 29 | Steps: []resource.TestStep{ 30 | { 31 | Config: testAccTwilioFlexConfig(chatServiceName, studioFlowName, flexName, "sms"), 32 | Check: resource.ComposeTestCheckFunc( 33 | resource.TestCheckResourceAttr(chatResourceName, "friendly_name", chatServiceName), 34 | resource.TestCheckResourceAttr(chatResourceName, "reachability_enabled", "false"), 35 | resource.TestCheckResourceAttr(studioResourceName, "friendly_name", studioFlowName), 36 | resource.TestCheckResourceAttr(studioResourceName, "commit_message", "first draft"), 37 | resource.TestCheckResourceAttr(studioResourceName, "status", "draft"), 38 | resource.TestCheckResourceAttr(flexResourceName, "friendly_name", flexName), 39 | resource.TestCheckResourceAttr(flexResourceName, "channel_type", "sms"), 40 | resource.TestCheckResourceAttr(flexResourceName, "contact_identity", "true"), 41 | ), 42 | }, 43 | { 44 | Config: testAccTwilioFlexConfig(chatServiceName, studioFlowName, flexName, "custom"), 45 | Check: resource.ComposeTestCheckFunc( 46 | resource.TestCheckResourceAttr(chatResourceName, "friendly_name", chatServiceName), 47 | resource.TestCheckResourceAttr(studioResourceName, "friendly_name", studioFlowName), 48 | resource.TestCheckResourceAttr(flexResourceName, "friendly_name", flexName), 49 | resource.TestCheckResourceAttr(flexResourceName, "channel_type", "custom"), 50 | resource.TestCheckResourceAttr(flexResourceName, "contact_identity", "true"), 51 | ), 52 | }, 53 | { 54 | ResourceName: chatResourceName, 55 | ImportState: true, 56 | ImportStateVerify: true, 57 | }, 58 | { 59 | ResourceName: flexResourceName, 60 | ImportState: true, 61 | ImportStateVerify: true, 62 | }, 63 | { 64 | ResourceName: studioResourceName, 65 | ImportState: true, 66 | ImportStateVerify: true, 67 | }, 68 | }, 69 | IDRefreshName: "", 70 | IDRefreshIgnore: nil, 71 | }) 72 | } 73 | 74 | func testAccFlexInstanceDestroy(state *terraform.State) error { 75 | 76 | for _, rs := range state.RootModule().Resources { 77 | 78 | conn, _ := testAccProviderFactories[ProviderName]() 79 | conn.Configure(context.Background(), terraform.NewResourceConfigRaw(nil)) 80 | client := conn.Meta().(*Config) 81 | 82 | if rs.Type == "twilio_chat_services_v2" { 83 | //Check if the chat service has been destroyed 84 | _, err := client.Client.ChatV2.FetchService(rs.Primary.ID) 85 | if err == nil { 86 | return fmt.Errorf("flex chat service still exists") 87 | } 88 | } else if rs.Type == "twilio_studio_flows_v2" { 89 | //Check if the studio flow has been destroyed 90 | _, err := client.Client.StudioV2.FetchFlow(rs.Primary.ID) 91 | if err == nil { 92 | return fmt.Errorf("flex studio flow still exists") 93 | } 94 | } else if rs.Type == "twilio_flex_flex_flows_v1" { 95 | //Check if the flex instance has been destroyed 96 | _, err := client.Client.FlexV1.FetchFlexFlow(rs.Primary.ID) 97 | if err == nil { 98 | return fmt.Errorf("flex flow still exists") 99 | } 100 | } else { 101 | continue 102 | } 103 | } 104 | 105 | return nil 106 | } 107 | 108 | func testAccTwilioFlexConfig(chatServiceName string, studioFlowName string, flexName string, channelType string) string { 109 | return fmt.Sprintf(` 110 | 111 | resource "twilio_chat_services_v2" "chat_service" { 112 | friendly_name = "%s" 113 | } 114 | 115 | resource "twilio_studio_flows_v2" "studio_flow" { 116 | commit_message = "first draft" 117 | friendly_name = "%s" 118 | status = "draft" 119 | definition = jsonencode({ 120 | description = "A New Flow", 121 | states = [{ 122 | name = "Trigger" 123 | type = "trigger" 124 | transitions = [] 125 | properties = { 126 | offset = { 127 | x = 0 128 | y = 0 129 | } 130 | } 131 | }] 132 | initial_state = "Trigger" 133 | flags = { 134 | allow_concurrent_calls = true 135 | } 136 | }) 137 | } 138 | 139 | resource "twilio_flex_flex_flows_v1" "flows" { 140 | friendly_name = "%s" 141 | chat_service_sid = twilio_chat_services_v2.chat_service.id 142 | channel_type = "%s" 143 | integration_flow_sid = twilio_studio_flows_v2.studio_flow.id 144 | contact_identity = "true" 145 | } 146 | `, chatServiceName, studioFlowName, flexName, channelType) 147 | } 148 | -------------------------------------------------------------------------------- /twilio/resources_serverless_test.go: -------------------------------------------------------------------------------- 1 | package twilio 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "testing" 7 | 8 | openapi "github.com/twilio/twilio-go/rest/serverless/v1" 9 | 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 11 | 12 | . "github.com/twilio/terraform-provider-twilio/client" 13 | 14 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 15 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 16 | ) 17 | 18 | func TestAccServerlessSetup_basic(t *testing.T) { 19 | serverlessSvcResourceName := "twilio_serverless_services_v1.service" 20 | serverlessSvcFuncResourceName := "twilio_serverless_services_functions_v1.function" 21 | serverlessSvcEnvResourceName := "twilio_serverless_services_environments_v1.environment" 22 | 23 | serviceName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) 24 | 25 | var serviceBefore, serviceAfter openapi.ServerlessV1Environment 26 | 27 | resource.Test(t, resource.TestCase{ 28 | IsUnitTest: false, 29 | PreCheck: func() { testAccPreCheck(t) }, 30 | ProviderFactories: testAccProviderFactories, 31 | PreventPostDestroyRefresh: false, 32 | CheckDestroy: testAccServerlessServiceDestroy, 33 | Steps: []resource.TestStep{ 34 | { 35 | Config: testAccTwilioServerlessConfig(serviceName, "Serverless func", "environment-dummy"), 36 | Check: resource.ComposeTestCheckFunc( 37 | testAccServerlessServiceEnvironmentExists(serverlessSvcEnvResourceName, &serviceBefore), 38 | resource.TestCheckResourceAttr(serverlessSvcResourceName, "friendly_name", "Terraform service"), 39 | resource.TestCheckResourceAttr(serverlessSvcResourceName, "unique_name", serviceName), 40 | resource.TestCheckResourceAttr(serverlessSvcFuncResourceName, "friendly_name", "Serverless func"), 41 | resource.TestCheckResourceAttr(serverlessSvcEnvResourceName, "unique_name", "environment-dummy"), 42 | ), 43 | }, 44 | { 45 | Config: testAccTwilioServerlessConfig(serviceName, "Serverless func 2", "environment-dummy-updated"), 46 | Check: resource.ComposeTestCheckFunc( 47 | testAccServerlessServiceEnvironmentExists(serverlessSvcEnvResourceName, &serviceAfter), 48 | resource.TestCheckResourceAttr(serverlessSvcResourceName, "friendly_name", "Terraform service"), 49 | resource.TestCheckResourceAttr(serverlessSvcResourceName, "unique_name", serviceName), 50 | resource.TestCheckResourceAttr(serverlessSvcFuncResourceName, "friendly_name", "Serverless func 2"), 51 | resource.TestCheckResourceAttr(serverlessSvcEnvResourceName, "unique_name", "environment-dummy-updated"), 52 | testAccEnvResourceWasRecreated(&serviceBefore, &serviceAfter), 53 | ), 54 | }, 55 | { 56 | ResourceName: serverlessSvcResourceName, 57 | ImportState: true, 58 | ImportStateVerify: true, 59 | }, 60 | { 61 | ResourceName: serverlessSvcFuncResourceName, 62 | ImportState: true, 63 | ImportStateVerify: true, 64 | }, 65 | { 66 | ResourceName: serverlessSvcEnvResourceName, 67 | ImportState: true, 68 | ImportStateVerify: true, 69 | }, 70 | }, 71 | IDRefreshName: "", 72 | IDRefreshIgnore: nil, 73 | }) 74 | } 75 | 76 | func testAccEnvResourceWasRecreated(before, after *openapi.ServerlessV1Environment) resource.TestCheckFunc { 77 | return func(s *terraform.State) error { 78 | if *before.UniqueName == *after.UniqueName { 79 | return fmt.Errorf("serverless Service Environment was not recreated, "+ 80 | "before name: %s, after name: %s", *before.UniqueName, *after.UniqueName) 81 | } 82 | 83 | conn, _ := testAccProviderFactories[ProviderName]() 84 | conn.Configure(context.Background(), terraform.NewResourceConfigRaw(nil)) 85 | 86 | client := conn.Meta().(*Config) 87 | _, err := client.Client.ServerlessV1.FetchEnvironment(*before.ServiceSid, *before.Sid) 88 | if err == nil { 89 | return fmt.Errorf("serverless service environment with sid %s exists but should not; err: %s", *before.Sid, err) 90 | } 91 | 92 | _, err = client.Client.ServerlessV1.FetchEnvironment(*after.ServiceSid, *after.Sid) 93 | if err != nil { 94 | return fmt.Errorf("serverless service environment was not recreated becauase service %s does not exist; err: %s", *after.Sid, err) 95 | } 96 | 97 | return nil 98 | } 99 | } 100 | 101 | func testAccServerlessServiceEnvironmentExists(resourceName string, env *openapi.ServerlessV1Environment) resource.TestCheckFunc { 102 | return func(s *terraform.State) error { 103 | rs, ok := s.RootModule().Resources[resourceName] 104 | if !ok { 105 | return fmt.Errorf("not found: %s", resourceName) 106 | } 107 | conn, _ := testAccProviderFactories[ProviderName]() 108 | conn.Configure(context.Background(), terraform.NewResourceConfigRaw(nil)) 109 | 110 | client := conn.Meta().(*Config) 111 | output, err := client.Client.ServerlessV1.FetchEnvironment(rs.Primary.Attributes["service_sid"], rs.Primary.Attributes["sid"]) 112 | if err != nil { 113 | return fmt.Errorf("serverless service environment does not exist; service_sid: %s, primary id: %s", 114 | rs.Primary.Attributes["service_sid"], rs.Primary.ID) 115 | } 116 | 117 | *env = *output 118 | return nil 119 | } 120 | } 121 | 122 | func testAccServerlessServiceDestroy(state *terraform.State) error { 123 | for _, rs := range state.RootModule().Resources { 124 | if rs.Type != "twilio_serverless_services_v1" { 125 | continue 126 | } 127 | 128 | conn, _ := testAccProviderFactories[ProviderName]() 129 | conn.Configure(context.Background(), terraform.NewResourceConfigRaw(nil)) 130 | 131 | client := conn.Meta().(*Config) 132 | _, err := client.Client.ServerlessV1.FetchService(rs.Primary.ID) 133 | if err == nil { 134 | return fmt.Errorf("serverless service still exists") 135 | } 136 | } 137 | 138 | return nil 139 | } 140 | 141 | func testAccTwilioServerlessConfig(serviceName string, funcName string, environmentName string) string { 142 | return fmt.Sprintf(` 143 | resource "twilio_serverless_services_v1" "service" { 144 | friendly_name = "Terraform service" 145 | unique_name = "%s" 146 | } 147 | 148 | resource "twilio_serverless_services_functions_v1" "function" { 149 | service_sid = twilio_serverless_services_v1.service.id 150 | friendly_name = "%s" 151 | } 152 | 153 | resource "twilio_serverless_services_environments_v1" "environment" { 154 | service_sid = twilio_serverless_services_v1.service.sid 155 | unique_name = "%s" 156 | domain_suffix = "com" 157 | } 158 | `, serviceName, funcName, environmentName) 159 | } 160 | --------------------------------------------------------------------------------