├── .files ├── .gitignore └── swlogo.png ├── .gitignore ├── Chat ├── README.md ├── Using chat to send messages and make voice calls Relay v4 │ ├── .env.example │ ├── .gitignore │ ├── README.md │ ├── frontend │ │ ├── app.css │ │ ├── app.js │ │ ├── bootstrap.css │ │ ├── bootstrap.js │ │ └── index.html │ ├── index.js │ ├── package-lock.json │ └── package.json └── Using chat to send messages and make voice calls │ ├── .env.example │ ├── .gitignore │ ├── README.md │ ├── frontend │ ├── app.css │ ├── app.js │ ├── bootstrap.css │ ├── bootstrap.js │ └── index.html │ ├── index.js │ ├── package-lock.json │ └── package.json ├── Fax ├── Forwarding Incoming Faxes to Email with Python │ ├── app.py │ ├── example.env │ └── readme.MD ├── README.md └── Retry Failed Faxes with Express-NodeJS │ ├── Readme.md │ ├── app.js │ ├── example.env │ ├── package-lock.json │ └── package.json ├── Integrations ├── README.md ├── SignalWire API on Azure Function - NodeJS │ ├── .funcignore │ ├── .gitignore │ ├── README.md │ ├── SendSMS │ │ ├── function.json │ │ ├── index.js │ │ └── sample.dat │ ├── SendVoice │ │ ├── function.json │ │ ├── index.js │ │ └── sample.dat │ ├── env.example │ ├── host.json │ ├── package-lock.json │ └── package.json └── Textit-integration │ ├── README.md │ └── static │ ├── account.png │ ├── add_channel.png │ ├── api.png │ ├── enter_info.png │ └── testing_text.jpg ├── LICENSE ├── Messaging ├── Forward Messages - NodeJS │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── env.sample │ ├── index.js │ ├── package-lock.json │ └── package.json ├── Forward Messages to Email - NodeJS Relay v4 │ ├── .env.sample │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── index.js │ ├── package-lock.json │ └── package.json ├── Forward Messages to Email - NodeJS │ ├── .env.sample │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── index.js │ ├── package-lock.json │ └── package.json ├── Private-URL-Shortener-Python │ ├── .env │ ├── main.py │ ├── readme.MD │ ├── shortUrls.csv │ ├── static │ │ ├── style.css │ │ └── swlogo.jpg │ └── templates │ │ └── urlShortener.html ├── README.md ├── Send-SMS-Through-Google-Sheets │ ├── README.md │ └── SMS Through Google Sheets.js ├── Sending SMS from the Browser - NodeJS Relay v4 │ ├── .gitignore │ ├── README.md │ ├── env.sample │ ├── html │ │ ├── index.css │ │ └── index.html │ ├── index.js │ ├── package-lock.json │ └── package.json ├── Sending SMS from the Browser - NodeJS │ ├── .gitignore │ ├── README.md │ ├── env.sample │ ├── html │ │ ├── index.css │ │ └── index.html │ ├── index.js │ ├── package.json │ └── yarn.lock ├── Text Subscription with Python │ ├── Dockerfile │ ├── app.py │ ├── campaigns.json │ ├── donotcontact.json │ ├── example.env │ └── readme.MD ├── Two Factor Authentication via SMS - NodeJS Relay v4 │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── example.env │ ├── html │ │ ├── index.css │ │ └── index.html │ ├── index.js │ ├── package-lock.json │ └── package.json ├── Two Factor Authentication via SMS - NodeJS │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── example.env │ ├── html │ │ ├── index.css │ │ └── index.html │ ├── index.js │ ├── package-lock.json │ └── package.json └── Two Factor Authentication via SMS - Python │ ├── LICENSE │ ├── README.md │ └── python │ ├── Dockerfile │ ├── app.py │ └── example.env ├── PhoneNumbers └── readme.MD ├── README.md ├── Video ├── AppKit-Framework-Examples │ ├── Angular │ │ ├── .browserslistrc │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── .vscode │ │ │ ├── extensions.json │ │ │ ├── launch.json │ │ │ └── tasks.json │ │ ├── README.md │ │ ├── angular.json │ │ ├── karma.conf.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ │ ├── app │ │ │ │ ├── app.component.css │ │ │ │ ├── app.component.html │ │ │ │ ├── app.component.spec.ts │ │ │ │ ├── app.component.ts │ │ │ │ └── app.module.ts │ │ │ ├── assets │ │ │ │ └── .gitkeep │ │ │ ├── environments │ │ │ │ ├── environment.prod.ts │ │ │ │ └── environment.ts │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── main.ts │ │ │ ├── polyfills.ts │ │ │ ├── styles.css │ │ │ └── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.json │ │ └── tsconfig.spec.json │ ├── React │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── logo192.png │ │ │ ├── logo512.png │ │ │ ├── manifest.json │ │ │ └── robots.txt │ │ └── src │ │ │ ├── App.css │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ ├── index.css │ │ │ ├── index.js │ │ │ ├── logo.svg │ │ │ ├── reportWebVitals.js │ │ │ └── setupTests.js │ ├── Vite │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── main.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ │ └── vite.svg │ │ ├── src │ │ │ ├── style.css │ │ │ ├── typescript.svg │ │ │ └── vite-env.d.ts │ │ └── style.css │ └── Vue 3 │ │ ├── .gitignore │ │ ├── .vscode │ │ └── extensions.json │ │ ├── README.md │ │ ├── env.d.ts │ │ ├── index.html │ │ ├── package.json │ │ ├── public │ │ └── favicon.ico │ │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ ├── base.css │ │ │ ├── logo.svg │ │ │ └── main.css │ │ └── main.ts │ │ ├── tsconfig.config.json │ │ ├── tsconfig.json │ │ └── vite.config.ts ├── Embed Video Rooms - Videoconferencing Widget │ ├── README.md │ ├── index.html │ └── raw_guide.md ├── Interactive-Live-Streaming │ ├── .gitignore │ ├── README.md │ ├── jsconfig.json │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── manifest.json │ │ └── robots.txt │ ├── server │ │ ├── index.js │ │ ├── jsconfig.json │ │ ├── package-lock.json │ │ └── package.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── InCall.js │ │ ├── InCall.module.css │ │ ├── Prejoin.js │ │ ├── Prejoin.module.css │ │ ├── components │ │ ├── Audience.js │ │ ├── Audience.module.css │ │ ├── AudienceCount.js │ │ ├── CameraButton.js │ │ ├── LeaveButton.js │ │ ├── Members.js │ │ ├── Members.module.css │ │ ├── MicrophoneButton.js │ │ └── SplitButton.js │ │ ├── features │ │ └── promotion.js │ │ ├── index.css │ │ ├── index.js │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── Layout-Positions │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── index.js │ │ └── styles.css ├── README.md ├── RTMP-Streaming │ ├── .gitignore │ ├── README.md │ ├── index.css │ ├── index.html │ ├── index.js │ ├── package-lock.json │ ├── package.json │ ├── swlogo.png │ └── yt-streaming.webp ├── React-Native-Basic │ ├── App.js │ ├── README.md │ ├── app.json │ ├── babel.config.js │ ├── eas.json │ ├── index.js │ ├── metro.config.js │ ├── package.json │ └── yarn.lock ├── Room Preview Demo │ ├── .gitignore │ ├── README.md │ ├── embed.js │ ├── env.example │ ├── index.html │ ├── index.js │ ├── package-lock.json │ ├── package.json │ ├── static │ │ ├── embed.js │ │ └── index.html │ └── yarn.lock └── Simple Video Demo │ ├── Dockerfile │ ├── README.md │ ├── env.example │ ├── package.json │ └── src │ ├── frontend │ ├── index.css │ ├── index.html │ ├── index.js │ └── swlogo.png │ └── index.js └── Voice ├── .DS_Store ├── AI Agent with NodeJS ├── Dockerfile ├── README.md ├── env.example ├── index.js ├── package-lock.json └── package.json ├── Answering Machine Detection with NodeJS ├── Dockerfile ├── README.md ├── env.example ├── index.js ├── package-lock.json └── package.json ├── Answering Machine Detection with Ruby ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── app.rb ├── example.env └── readme.MD ├── Appointment Reminder using NodeJS and Relay V3 ├── .gitignore ├── Dockerfile ├── consumer.js ├── env.example ├── index.js ├── package-lock.json ├── package.json ├── readme.MD └── views │ └── index.ejs ├── Build a Dynamic IVR with JSON Menus - Python ├── app.py ├── menus.json └── readme.MD ├── Call Center with Dynamic JSON Menus and Python ├── README.md └── python │ ├── Dockerfile │ ├── app.py │ └── config.json.example ├── Dial By Voice Python ├── Dockerfile ├── Image1.png ├── LICENSE ├── README.md └── app.py ├── Implement Coaching and Recording with NodeJS ├── Dockerfile ├── README.md ├── coach-screen-snap.png ├── example.env ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo.svg │ └── manifest.json ├── server.js └── src │ ├── App.js │ ├── App.test.js │ ├── components │ ├── CallControls.js │ ├── CallQueue.js │ ├── CallRecordings.js │ ├── CallerDetails.js │ ├── Dashboard.css │ ├── Dashboard.js │ ├── FetchData.js │ ├── Layout.js │ ├── NavMenu.css │ ├── NavMenu.js │ ├── Participants.js │ ├── SupervisorControls.js │ ├── custom.css │ ├── delete-6x.png │ ├── media-pause-2x.png │ ├── media-pause-3x.png │ ├── media-pause-4x.png │ ├── media-pause-6x.png │ ├── media-play-2x.png │ ├── media-play-3x.png │ ├── media-play-4x.png │ ├── media-play-6x.png │ ├── media-record-2x.png │ ├── media-record-3x.png │ ├── media-record-4x.png │ ├── media-record-6x.png │ ├── media-stop-2x.png │ ├── media-stop-3x.png │ ├── media-stop-4x.png │ ├── media-stop-6x.png │ ├── spinner.png │ └── spinner2.png │ ├── css │ ├── GithubIssues.css │ └── index.css │ ├── custom.css │ ├── index.js │ ├── logo.svg │ ├── registerServiceWorker.js │ └── utils │ └── appHelpers.js ├── Implement two-factor with Python ├── Dockerfile ├── LICENSE ├── README.md ├── app.py └── example.env ├── Lenny Spam Filter Relay v4 ├── .env.example ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── run_docker.sh └── src │ ├── captcha.js │ ├── index.js │ ├── lenny.js │ └── transfer.js ├── Make Appointment Reminder Calls with Ruby ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── app.rb ├── config.json ├── example.env ├── readme.MD └── views │ ├── index.erb │ └── layout.erb ├── Multi-Factor Authentication in Ruby ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── README.md ├── app.rb ├── env.example └── views │ ├── index.erb │ └── layout.erb ├── Phone Survey With Python ├── CovidSurvey.py ├── Image1.png ├── README.md ├── config.json.example └── sheets.py ├── README.md ├── Recording Audio Tracks with Websockets ├── app.py └── readme.md ├── Request Callback in a Queue with Python ├── Dockerfile ├── app.py ├── example.env └── readme.MD ├── SIP Voicemail with NodeJS ├── Dockerfile ├── README.md ├── env.example ├── index.js ├── ngrok-webhook-config.png ├── package-lock.json └── package.json ├── SIP Voicemail with Python ├── .env.example ├── Dockerfile ├── Pipfile ├── Pipfile.lock ├── README.md ├── index.py └── ngrok-webhook-config.png ├── Screen Calls & Record Voicemail in PHP ├── README.md ├── composer.json ├── composer.lock └── public │ └── index.php ├── Screen Calls Based on Block List with Python ├── app.py ├── readme.MD └── requirements.txt ├── Sentiment Analysis with Python ├── Dockerfile ├── app.py ├── example.env └── readme.MD ├── Voicemails to Email IVR with NodeJS ├── Dockerfile ├── README.md ├── env.example ├── index.js ├── package-lock.json └── package.json ├── Weather Phone IVR - NodeJS Relay v4 ├── .env.sample ├── Dockerfile ├── README.md ├── index.js ├── package-lock.json └── package.json └── Weather Phone IVR - NodeJS ├── .env.sample ├── Dockerfile ├── README.md ├── index.js ├── package.json └── yarn.lock /.files/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.files/swlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/.files/swlogo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | 27 | 28 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 29 | 30 | # dependencies 31 | /node_modules 32 | /.pnp 33 | .pnp.js 34 | 35 | # testing 36 | /coverage 37 | 38 | # production 39 | /build 40 | 41 | # misc 42 | .DS_Store 43 | .env 44 | .env.local 45 | .env.development.local 46 | .env.test.local 47 | .env.production.local 48 | 49 | npm-debug.log* 50 | yarn-debug.log* 51 | yarn-error.log* 52 | 53 | 54 | # See http://help.github.com/ignore-files/ for more about ignoring files. 55 | 56 | # Compiled output 57 | /dist 58 | /tmp 59 | /out-tsc 60 | /bazel-out 61 | 62 | # Node 63 | /node_modules 64 | npm-debug.log 65 | yarn-error.log 66 | 67 | # IDEs and editors 68 | .idea/ 69 | .project 70 | .classpath 71 | .c9/ 72 | *.launch 73 | .settings/ 74 | *.sublime-workspace 75 | 76 | # Visual Studio Code 77 | .vscode/* 78 | !.vscode/settings.json 79 | !.vscode/tasks.json 80 | !.vscode/launch.json 81 | !.vscode/extensions.json 82 | .history/* 83 | 84 | # Miscellaneous 85 | /.angular/cache 86 | .sass-cache/ 87 | /connect.lock 88 | /coverage 89 | /libpeerconnection.log 90 | testem.log 91 | /typings 92 | 93 | # System files 94 | .DS_Store 95 | Thumbs.db 96 | -------------------------------------------------------------------------------- /Chat/README.md: -------------------------------------------------------------------------------- 1 | [Using chat to send messages and voice call](./Using%20chat%20to%20send%20messages%20and%20make%20voice%20calls) 2 | This web chat application describes how to create an IVR using SignalWire Chat to send SMS and make Voice calls 3 | 4 | -------------------------------------------------------------------------------- /Chat/Using chat to send messages and make voice calls Relay v4/.env.example: -------------------------------------------------------------------------------- 1 | SPACE_URL= 2 | PROJECT_ID= 3 | API_TOKEN= -------------------------------------------------------------------------------- /Chat/Using chat to send messages and make voice calls Relay v4/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | -------------------------------------------------------------------------------- /Chat/Using chat to send messages and make voice calls Relay v4/frontend/app.css: -------------------------------------------------------------------------------- 1 | .chatPage { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | } 6 | 7 | .chatPage #messageEditor .dropdown { 8 | text-align: right; 9 | margin-top: 5px; 10 | } 11 | 12 | .chatPage #messageEditor #messageToSend { 13 | margin-top: 20px; 14 | } 15 | 16 | .chatPage #messageEditor { 17 | max-width: 500px; 18 | display: flex; 19 | flex-direction: column; 20 | width: 100%; 21 | } 22 | 23 | .chatPage #typing { 24 | height: 1.1em; 25 | margin-top: 1em; 26 | } 27 | 28 | #messagesContainer { 29 | flex: 1; 30 | flex-direction: column; 31 | } 32 | 33 | #channelsContainer { 34 | display: flex; 35 | justify-content: center; 36 | gap: 5px 20px; 37 | } 38 | 39 | #channelsContainer .channel { 40 | width: 600px; 41 | background-color: #e5e5e5; 42 | padding: 10px 15px 20px 15px; 43 | } 44 | 45 | #channelsContainer .channel .messages-list { 46 | height: 500px; 47 | overflow: scroll; 48 | } 49 | 50 | #channelsContainer .message { 51 | background: rgb(20, 127, 255); 52 | border-radius: 20px; 53 | padding: 10px 15px; 54 | color: white; 55 | margin-top: 10px; 56 | } 57 | 58 | #channelsContainer .channel-name { 59 | text-align: center; 60 | margin-bottom: 1em; 61 | } 62 | 63 | .message .message-meta { 64 | font-style: italic; 65 | font-size: 0.9em; 66 | opacity: 0.8; 67 | } 68 | -------------------------------------------------------------------------------- /Chat/Using chat to send messages and make voice calls Relay v4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chat-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "nodemon index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@signalwire/realtime-api": "^4.0.0", 15 | "axios": "^0.27.2", 16 | "body-parser": "^1.20.0", 17 | "cors": "^2.8.5", 18 | "dotenv": "^16.0.1", 19 | "express": "^4.18.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Chat/Using chat to send messages and make voice calls/.env.example: -------------------------------------------------------------------------------- 1 | SPACE_URL= 2 | PROJECT_ID= 3 | API_TOKEN= -------------------------------------------------------------------------------- /Chat/Using chat to send messages and make voice calls/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | -------------------------------------------------------------------------------- /Chat/Using chat to send messages and make voice calls/frontend/app.css: -------------------------------------------------------------------------------- 1 | .chatPage { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | } 6 | 7 | .chatPage #messageEditor .dropdown { 8 | text-align: right; 9 | margin-top: 5px; 10 | } 11 | 12 | .chatPage #messageEditor #messageToSend { 13 | margin-top: 20px; 14 | } 15 | 16 | .chatPage #messageEditor { 17 | max-width: 500px; 18 | display: flex; 19 | flex-direction: column; 20 | width: 100%; 21 | } 22 | 23 | .chatPage #typing { 24 | height: 1.1em; 25 | margin-top: 1em; 26 | } 27 | 28 | #messagesContainer { 29 | flex: 1; 30 | flex-direction: column; 31 | } 32 | 33 | #channelsContainer { 34 | display: flex; 35 | justify-content: center; 36 | gap: 5px 20px; 37 | } 38 | 39 | #channelsContainer .channel { 40 | width: 600px; 41 | background-color: #e5e5e5; 42 | padding: 10px 15px 20px 15px; 43 | } 44 | 45 | #channelsContainer .channel .messages-list { 46 | height: 500px; 47 | overflow: scroll; 48 | } 49 | 50 | #channelsContainer .message { 51 | background: rgb(20, 127, 255); 52 | border-radius: 20px; 53 | padding: 10px 15px; 54 | color: white; 55 | margin-top: 10px; 56 | } 57 | 58 | #channelsContainer .channel-name { 59 | text-align: center; 60 | margin-bottom: 1em; 61 | } 62 | 63 | .message .message-meta { 64 | font-style: italic; 65 | font-size: 0.9em; 66 | opacity: 0.8; 67 | } 68 | -------------------------------------------------------------------------------- /Chat/Using chat to send messages and make voice calls/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chat-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.18.1", 14 | "@signalwire/realtime-api": "^3.1.1", 15 | "dotenv": "^16.0.1", 16 | "axios": "^0.27.2", 17 | "body-parser": "^1.20.0", 18 | "cors": "^2.8.5" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Fax/Forwarding Incoming Faxes to Email with Python/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | import pprint 4 | 5 | from flask import Flask, request 6 | 7 | app = Flask(__name__) 8 | 9 | 10 | # Listen on route '/fax-webhook' for incoming GET/POST requests when a fax comes in 11 | @app.route('/fax-webhook', methods=['POST']) 12 | def fax_webhook(): 13 | # Forward incoming form data to email 14 | send_email(pprint.pformat(request.form, indent=4)) 15 | return "200" 16 | 17 | 18 | # Send email using MailGun API 19 | def send_email(body): 20 | return requests.post( 21 | "https://api.mailgun.net/v3/" + os.environ['MAILGUN_DOMAIN'] + "/messages", 22 | auth=("api", os.environ['MAILGUN_API_TOKEN']), 23 | data={"from": os.environ['EMAIL_FROM'], 24 | "to": [os.environ['EMAIL_TO']], 25 | "subject": os.environ['EMAIL_SUBJECT'], 26 | "text": body}) 27 | 28 | 29 | # Listen on '/' for default requests 30 | @app.route('/') 31 | def hello(): 32 | return "Hello World!" 33 | 34 | 35 | if __name__ == '__main__': 36 | app.run() -------------------------------------------------------------------------------- /Fax/Forwarding Incoming Faxes to Email with Python/example.env: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_SPACE= 2 | SIGNALWIRE_PROJECT= 3 | SIGNALWIRE_TOKEN= 4 | MAILGUN_DOMAIN= 5 | MAILGUN_API_TOKEN= 6 | EMAIL_FROM=info@yourdomain.com 7 | EMAIL_TO=youremail@yourdomain.com 8 | EMAIL_SUBJECT=INCOMING FAX -------------------------------------------------------------------------------- /Fax/README.md: -------------------------------------------------------------------------------- 1 | # Fax Guides 2 | 3 | [Forwarding Incoming Faxes to Email with Python](./Forwarding%20Incoming%20Faxes%20to%20Email%20with%20Python) 4 | This short and simple guide will show how you can use the SignalWire Python SDK and the MailGun API in order to forward your incoming SignalWire faxes to email. 5 | 6 | [Retry Failed Faxes with Express-NodeJS](./Retry%20Failed%20Faxes%20with%20Express-NodeJS) 7 | This is a simple guide using the SignalWire NodeJS SDK and Express to create an application that can send faxes, detected failed faxes with status callbacks, and perform one retry. 8 | -------------------------------------------------------------------------------- /Fax/Retry Failed Faxes with Express-NodeJS/example.env: -------------------------------------------------------------------------------- 1 | # This is the full name of your SignalWire Space. e.g.: example.signalwire.com 2 | SIGNALWIRE_SPACE_URL= 3 | 4 | # Your Project ID - you can find it on the `API` page in your Dashboard. 5 | SIGNALWIRE_PROJECT_ID= 6 | 7 | # Your API token - you can generate one on the `API` page in your Dashboard 8 | SIGNALWIRE_API_TOKEN= 9 | 10 | # The phone number you'll be using for this Snippet. Must include the `+1` ex. `+11231231234` 11 | SIGNALWIRE_FROMNUMBER=+1<10dlc number> 12 | SIGNALWIRE_TONUMBER=+1<10dlc number> 13 | 14 | # If you have an Ngrok account you can include your auth token here. 15 | NGROKTOKEN= 16 | 17 | #If hosting this app, enter the host domain here and remove the ngrok tunnel 18 | DOMAIN= -------------------------------------------------------------------------------- /Fax/Retry Failed Faxes with Express-NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@signalwire/compatibility-api": "^3.0.3", 4 | "express": "^4.17.2", 5 | "ngrok": "^4.2.2" 6 | }, 7 | "devDependencies": { 8 | "dotenv": "^10.0.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Integrations/README.md: -------------------------------------------------------------------------------- 1 | # Integrations Guides 2 | 3 | [SignalWire API on Azure Function - NodeJS](./SignalWire%20API%20on%20Azure%20Function%20-%20NodeJS) 4 | This project makes use of SignalWire Compatibility API and NodeJs SDK to make voice call and send sms on Azure function using the HttpTrigger function. 5 | 6 | [TextIt Integration](./Textit-integration/) 7 | This project walks through connecting a SignalWire phone number to the chatbot platform TextIt. 8 | -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/.funcignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | *.ts 3 | .git* 4 | .vscode 5 | local.settings.json 6 | test 7 | tsconfig.json -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/README.md: -------------------------------------------------------------------------------- 1 | # SignalWire API on Azure Function- Node.Js 2 | 3 | This project makes use of SignalWire Compatibility API and NodeJs SDK to make voice call and send sms on Azure function using the HttpTrigger function. 4 | 5 | 📖 [Read the full guide](https://developer.signalwire.com/apis/docs/microsoft-azure-functions) 6 | 7 | # How to Run Application 8 | 9 | Follow the below steps to get started with this project. 10 | 11 | - Clone this project 12 | - Basic understanding of cloud concept 13 | - Follow the [Guide](https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-node) to set up your environment 14 | - Create `.env` file from the `.env.example` file 15 | - Get your Project ID, API token and Space URL. If you do not know where to find these values, check out our guide [here](https://developer.signalwire.com/apis/docs/navigating-your-space#api)! 16 | 17 | # Sign Up Here 18 | 19 | If you would like to test this example out, you can create a SignalWire account and space [here](https://m.signalwire.com/signups/new?s=1). 20 | 21 | Please feel free to reach out to us on our [Community Slack](https://signalwire.community/) or create a Support ticket if you need guidance! 22 | 23 | -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/SendSMS/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "anonymous", 5 | "type": "httpTrigger", 6 | "direction": "in", 7 | "name": "req", 8 | "methods": [ 9 | "get", 10 | "post" 11 | ] 12 | }, 13 | { 14 | "type": "http", 15 | "direction": "out", 16 | "name": "res" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/SendSMS/index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config() 2 | const axios = require('axios') 3 | 4 | // PROJECT_ID and API_TOKEN are environment variable added in the .env file 5 | // Azure Functions uses the Application settings. You can access that from your 6 | 7 | const projectID = process.env.PROJECT_ID 8 | const token = process.env.API_TOKEN 9 | const spaceURL = process.env.SPACE_URL 10 | 11 | 12 | // Initialize the auth object for authentication when making 13 | // a call to signalwire api 14 | const auth = { 15 | username: projectID, 16 | password: token 17 | } 18 | 19 | 20 | // API url name to make our POST call too 21 | const apiUrl = `https://${spaceURL}/api/laml/2010-04-01/Accounts/${projectID}/Messages` 22 | 23 | module.exports = async function (context, req) { 24 | context.log('JavaScript HTTP trigger function processed a request.'); 25 | 26 | // Get the receiver, sender and message params from the body 27 | // It makes use of the destructuring in NodeJs 28 | const {receiver, sender, message} = req.body 29 | 30 | // An empty object to save the response from axios 31 | let responseMessage = null 32 | 33 | // Axios call to the signalwire api 34 | await axios.post(apiUrl, { 35 | To: receiver, 36 | From: sender, 37 | Body: message 38 | }, {auth}).then(response=> { 39 | 40 | // appending response from the axios call to the {responseMessage} object 41 | responseMessage = response.data 42 | 43 | }, error => { 44 | console.log(error.message) 45 | }) 46 | 47 | // return the response of the axios call in a json format 48 | context.res = { 49 | body: responseMessage 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/SendSMS/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure" 3 | } -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/SendVoice/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "anonymous", 5 | "type": "httpTrigger", 6 | "direction": "in", 7 | "name": "req", 8 | "methods": [ 9 | "get", 10 | "post" 11 | ] 12 | }, 13 | { 14 | "type": "http", 15 | "direction": "out", 16 | "name": "res" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/SendVoice/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | const {RestClient} = require('@signalwire/compatibility-api') 3 | 4 | const username = process.env.PROJECT_ID 5 | const token = process.env.API_TOKEN 6 | const spaceURL = process.env.SPACE_URL 7 | 8 | const client = RestClient(username, token, {signalwireSpaceUrl: spaceURL}) 9 | 10 | module.exports = async function (context, req) { 11 | 12 | context.log('JavaScript HTTP trigger function processed a request.'); 13 | 14 | const {receiver, sender, callUrl} = req.body 15 | 16 | let responseBody = {} 17 | 18 | await client.calls.create({to: receiver, from: sender, url: callUrl}).then(response => { 19 | responseBody = response 20 | }, error => { 21 | responseBody = error.message 22 | }) 23 | 24 | context.res = { 25 | // status: 200, /* Defaults to 200 */ 26 | body: responseBody 27 | }; 28 | } -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/SendVoice/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure" 3 | } -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/env.example: -------------------------------------------------------------------------------- 1 | PROJECT_ID= 2 | API_TOKEN= 3 | SPACE_URL= -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | } 9 | } 10 | }, 11 | "extensionBundle": { 12 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 13 | "version": "[2.*, 3.0.0)" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Integrations/SignalWire API on Azure Function - NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "signalwire-api-messaging", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "func start", 7 | "test": "echo \"No tests yet...\"" 8 | }, 9 | "dependencies": { 10 | "@signalwire/compatibility-api": "^3.0.2", 11 | "axios": "^0.26.1", 12 | "dotenv": "^16.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Integrations/Textit-integration/static/account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Integrations/Textit-integration/static/account.png -------------------------------------------------------------------------------- /Integrations/Textit-integration/static/add_channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Integrations/Textit-integration/static/add_channel.png -------------------------------------------------------------------------------- /Integrations/Textit-integration/static/api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Integrations/Textit-integration/static/api.png -------------------------------------------------------------------------------- /Integrations/Textit-integration/static/enter_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Integrations/Textit-integration/static/enter_info.png -------------------------------------------------------------------------------- /Integrations/Textit-integration/static/testing_text.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Integrations/Textit-integration/static/testing_text.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 SignalWire 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do 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 | -------------------------------------------------------------------------------- /Messaging/Forward Messages - NodeJS/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /frontend/build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* -------------------------------------------------------------------------------- /Messaging/Forward Messages - NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | WORKDIR /app 4 | 5 | ENV NODE_ENV=production 6 | 7 | COPY package*.json ./ 8 | RUN npm install 9 | 10 | COPY index.js . 11 | 12 | EXPOSE 3000 13 | 14 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /Messaging/Forward Messages - NodeJS/README.md: -------------------------------------------------------------------------------- 1 | # Forward Messages to Another Phone Number with Node.js 2 | 3 | This super simple guide will show how you can handle incoming messages and forward them to another phone number. We will use the [SignalWire Javascript SDK](https://developer.signalwire.com/client-sdk/reference/js-exports) to handle the incoming message and [RELAY Realtime API](https://developer.signalwire.com/sdks/reference/realtime-sdk/) to forward the message. 4 | 5 | # Setup Your Environment File 6 | 7 | Copy from env.sample and fill in your values. 8 | 9 | You will need a SignalWire phone number as well as your API Credentials (API Token and Project ID) from within the API tab of your SignalWire Space. 10 | 11 | Save the new file as `.env`. 12 | 13 | # How to Run This Code 14 | 15 | You can run this code natively by cloning and using the `npm start` command in your terminal. 16 | 17 | You may also choose to run it on Docker by building the image with `docker build -t forwardsms .` followed by `docker run -it --rm -p 3000:3000 --name forwardsms --env-file .env forwardsms` 18 | 19 | # Code Walkthrough 20 | 21 | Read the full walkthrough on the [Forwarding Messages](https://developer.signalwire.com/apis/docs/how-to-forward-messages) guide. 22 | -------------------------------------------------------------------------------- /Messaging/Forward Messages - NodeJS/env.sample: -------------------------------------------------------------------------------- 1 | # Project ID copied from the API Credentials in your SignalWire Space 2 | PROJECT_ID= 3 | # API token copied from the API Credentials in your SignalWire Space 4 | API_TOKEN= 5 | # Your SignalWire number receiving messages in E.164 format (+1XXXYYYZZZZ) 6 | ORIGINAL_NUMBER= 7 | # Number you would like to forward to in E.164 format (+1XXXYYYZZZZ) 8 | TO_NUMBER= -------------------------------------------------------------------------------- /Messaging/Forward Messages - NodeJS/index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const { Messaging } = require("@signalwire/realtime-api"); 3 | 4 | const client = new Messaging.Client({ 5 | project: process.env.PROJECT_ID, 6 | token: process.env.API_TOKEN, 7 | contexts: ["office"], 8 | }); 9 | 10 | const express = require("express"); 11 | const app = express(); 12 | const port = 3000; 13 | const bodyparser = require("body-parser"); 14 | 15 | app.use(bodyparser.urlencoded({ extended: true })); 16 | 17 | client.on("message.received", async (message) => { 18 | console.log(message); 19 | const date = new Date().toLocaleDateString(); 20 | const text = "'" + message.body + "'"; 21 | const sender = message.from; 22 | let media; 23 | if (message.media) { 24 | media = message.media; 25 | text = "media only"; 26 | } 27 | 28 | const data = { 29 | from: process.env.ORIGINAL_NUMBER, 30 | to: process.env.TO_NUMBER, 31 | context: "office", 32 | body: `At ${date} you received a message from ${sender} to ${process.env.ORIGINAL_NUMBER}. The message body was: ${text}.`, 33 | media, 34 | }; 35 | console.log(data); 36 | 37 | try { 38 | const sendResult = await client.send(data); 39 | console.log("Forwarding message.", sendResult); 40 | } catch (error) { 41 | console.error("Message failed to send", error); 42 | } 43 | }); 44 | 45 | app.listen(port, () => { 46 | console.log(`Server listening on port ${port}`); 47 | }); 48 | -------------------------------------------------------------------------------- /Messaging/Forward Messages - NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forward-messages---nodejs", 3 | "version": "1.0.0", 4 | "description": "This super simple guide will show how you can handle incoming messages and forward them to another phone number. We will use the [SignalWire Javascript SDK](https://developer.signalwire.com/client-sdk/reference/js-exports) to handle the incoming message and [RELAY Realtime API]() to forward the message.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@signalwire/realtime-api": "^3.3.1", 14 | "body-parser": "^1.20.0", 15 | "dotenv": "^16.0.1", 16 | "express": "^4.18.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS Relay v4/.env.sample: -------------------------------------------------------------------------------- 1 | PROJECT_ID= 2 | API_TOKEN= 3 | MAILGUN_DOMAIN= 4 | MAILGUN_API_TOKEN= 5 | EMAIL_FROM="info@.com" 6 | EMAIL_TO="@.com" -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS Relay v4/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /frontend/build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS Relay v4/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | WORKDIR /app 4 | 5 | ENV NODE_ENV=production 6 | 7 | COPY package*.json ./ 8 | RUN npm install 9 | 10 | COPY index.js . 11 | 12 | EXPOSE 3000 13 | 14 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS Relay v4/README.md: -------------------------------------------------------------------------------- 1 | # Forward Messages to Email with Node.js 2 | 3 | This super simple guide will show how you can handle incoming messages and forward them to an email address. We will use the [SignalWire Javascript SDK](https://developer.signalwire.com/sdks) to handle the incoming message and [MailGun API](https://www.mailgun.com/) to send an email. 4 | 5 | # Setup Your Environment File 6 | 7 | Copy from .env.sample and fill in your values. 8 | 9 | You will need a SignalWire phone number as well as your API Credentials (API Token, Space URL, and Project ID) from within the API tab of your SignalWire Space. 10 | 11 | You will also need your Credentials from the MailGun API. 12 | 13 | Save new file called .env 14 | 15 | # How to Run This Code 16 | 17 | You can run this code natively by cloning and using the `npm start` command in your terminal. 18 | 19 | You may also choose to run it on Docker by building the image with `docker build -t smstoemail .` followed by `docker run -it --rm -p 3000:3000 --name smstoemail --env-file .env smstoemail` 20 | 21 | # Code Walkthrough 22 | 23 | Read the full walkthrough on the [Forwarding Texts to Email - Node.js](https://developer.signalwire.com/apis/docs/forwarding-texts-to-email-nodejs?relay_version=relayv4) guide. 24 | -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS Relay v4/index.js: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { SignalWire } from "@signalwire/realtime-api"; 3 | 4 | import formData from "form-data"; 5 | import mailgun from "mailgun.js"; 6 | 7 | const swClient = await SignalWire({ 8 | project: process.env.PROJECT_ID, 9 | token: process.env.API_TOKEN, 10 | topics: ["office"], 11 | }); 12 | 13 | const Mailgun = new mailgun(formData); 14 | const mgClient = Mailgun.client({ 15 | username: "api", 16 | key: process.env.MAILGUN_API_TOKEN, 17 | }); 18 | 19 | let messageClient = swClient.messaging; 20 | 21 | await messageClient.listen({ 22 | topics: ["office"], 23 | onMessageReceived: async (message) => { 24 | let date = new Date().toISOString(); 25 | let body = message.body; 26 | let from = message.from; 27 | let to = message.to; 28 | let media = message.media; 29 | let data = { 30 | from: process.env.EMAIL_FROM, 31 | to: process.env.EMAIL_TO, 32 | subject: "Incoming Message to " + to, 33 | text: `At ${date} you received a message from ${from} to ${to}. The message body was: '${body}'. The included media was: ${media}`, 34 | }; 35 | 36 | mgClient.messages 37 | .create(process.env.MAILGUN_DOMAIN, data) 38 | .then((res) => { 39 | console.log(data); 40 | console.log(res); 41 | }) 42 | .catch((err) => { 43 | console.error(err); 44 | }); 45 | }, 46 | }); 47 | -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS Relay v4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smstoemail", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node index.js", 9 | "dev": "nodemon index.js" 10 | }, 11 | "dependencies": { 12 | "@signalwire/realtime-api": "^4.0.0", 13 | "dotenv": "^16.0.0", 14 | "form-data": "^4.0.0", 15 | "mailgun.js": "^7.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS/.env.sample: -------------------------------------------------------------------------------- 1 | PROJECT_ID= 2 | API_TOKEN= 3 | MAILGUN_DOMAIN= 4 | MAILGUN_API_TOKEN= 5 | EMAIL_FROM="info@.com" 6 | EMAIL_TO="@.com" -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /frontend/build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | WORKDIR /app 4 | 5 | ENV NODE_ENV=production 6 | 7 | COPY package*.json ./ 8 | RUN npm install 9 | 10 | COPY index.js . 11 | 12 | EXPOSE 3000 13 | 14 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS/README.md: -------------------------------------------------------------------------------- 1 | # Forward Messages to Email with Node.js 2 | 3 | This super simple guide will show how you can handle incoming messages and forward them to an email address. We will use the [SignalWire Javascript SDK](https://developer.signalwire.com/sdks) to handle the incoming message and [MailGun API](https://www.mailgun.com/) to send an email. 4 | 5 | # Setup Your Environment File 6 | 7 | Copy from .env.sample and fill in your values. 8 | 9 | You will need a SignalWire phone number as well as your API Credentials (API Token, Space URL, and Project ID) from within the API tab of your SignalWire Space. 10 | 11 | You will also need your Credentials from the MailGun API. 12 | 13 | Save new file called .env 14 | 15 | # How to Run This Code 16 | 17 | You can run this code natively by cloning and using the `npm start` command in your terminal. 18 | 19 | You may also choose to run it on Docker by building the image with `docker build -t smstoemail .` followed by `docker run -it --rm -p 3000:3000 --name smstoemail --env-file .env smstoemail` 20 | 21 | # Code Walkthrough 22 | 23 | Read the full walkthrough on the [Forwarding Texts to Email - Node.js](https://developer.signalwire.com/apis/docs/forwarding-texts-to-email-nodejs?relay_version=relayv3) guide. 24 | -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS/index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | let { Messaging } = require("@signalwire/realtime-api"); 3 | let formData = require("form-data"); 4 | let mailgun = require("mailgun.js"); 5 | 6 | const swClient = new Messaging.Client({ 7 | project: process.env.PROJECT_ID, 8 | token: process.env.API_TOKEN, 9 | contexts: ["office"], 10 | }); 11 | 12 | const Mailgun = new mailgun(formData); 13 | const mgClient = Mailgun.client({ 14 | username: "api", 15 | key: process.env.MAILGUN_API_TOKEN, 16 | }); 17 | 18 | swClient.on("message.received", (message) => { 19 | let date = new Date().toISOString(); 20 | let body = message.body; 21 | let from = message.from; 22 | let to = message.to; 23 | let media = message.media; 24 | let data = { 25 | from: process.env.EMAIL_FROM, 26 | to: process.env.EMAIL_TO, 27 | subject: "Incoming Message to " + to, 28 | text: `At ${date} you received a message from ${from} to ${to}. The message body was: '${body}'. The included media was: ${media}`, 29 | }; 30 | 31 | mgClient.messages 32 | .create(process.env.MAILGUN_DOMAIN, data) 33 | .then((res) => { 34 | console.log(data); 35 | console.log(res); 36 | }) 37 | .catch((err) => { 38 | console.error(err); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /Messaging/Forward Messages to Email - NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smstoemail", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "node index.js", 8 | "dev": "nodemon index.js" 9 | }, 10 | "dependencies": { 11 | "@signalwire/realtime-api": "^3.0.0", 12 | "dotenv": "^16.0.0", 13 | "form-data": "^4.0.0", 14 | "mailgun.js": "^7.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Messaging/Private-URL-Shortener-Python/.env: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_HOST_NAME=https://{YourHostName}/ -------------------------------------------------------------------------------- /Messaging/Private-URL-Shortener-Python/shortUrls.csv: -------------------------------------------------------------------------------- 1 | Full URL,Short URL,Created Date,Last Clicked,Times Clicked 2 | 3 | -------------------------------------------------------------------------------- /Messaging/Private-URL-Shortener-Python/static/swlogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Messaging/Private-URL-Shortener-Python/static/swlogo.jpg -------------------------------------------------------------------------------- /Messaging/Send-SMS-Through-Google-Sheets/README.md: -------------------------------------------------------------------------------- 1 | # Send SMS Through Google Sheets 2 | 3 | ## Overview 4 | Do you store your customer’s information in an excel or Google Sheets spreadsheet? Wouldn’t it be handy to be able to send SMS to your customers directly from Google Sheets? With this guide we’ll show you how to integrate SignalWire API with Google Sheets API to track and contact customers regarding payments that are due. We’ll be using Google’s version of Javascript which is called Apps Script. You can modify this code however you need to fit your particular use case. 5 | 6 |
7 | 8 | ## What do you need to run this code? 9 | 10 | View the full walkthrough on our developer site [here](https://developer.signalwire.com/apis/docs/how-to-send-sms-from-google-sheets)! 11 | 12 | This guide uses Google Sheets so you'll need to have an active Google account. 13 | 14 | You will need a SignalWire phone number as well as your API Credentials (API Token, Space URL, and Project ID) which can all be found in an easily copyable format within the API tab of your SignalWire portal. 15 | 16 |
17 | 18 | ## How to Run Application 19 | 20 | ### Build and Run within Google Sheets 21 | 22 | 1. Copy the code from the Javascript file and paste it into the Apps Script Editor in Google Sheets. 23 | 24 | 2. Input your SignalWire credentials in the custom 'Credentials' menu. 25 | 26 | 3. Run the script from the custom 'Send SMS' menu. 27 | 28 |
29 | 30 | ## Sign Up Here 31 | 32 | If you would like to test this example out, you can create a SignalWire account and space [here](https://m.signalwire.com/signups/new?s=1). 33 | 34 | Please feel free to reach out to us on our [Community Slack](https://signalwire.community/) or create a Support ticket if you need guidance! 35 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS Relay v4/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS Relay v4/README.md: -------------------------------------------------------------------------------- 1 | # Send SMS from the browser with SignalWire APIs - Node JS 2 | 3 | A demo application that demonstrates how to send an SMS message using the SignalWire Messaging API. 4 | 5 | 📖 [Read the full guide](https://developer.signalwire.com/apis/docs/send-sms-from-the-browser-using-node-js?relay_version=relayv4) 6 | 7 | ## Setup 8 | 9 | 1. Use `yarn install` to install the dependencies. 10 | 2. Buy a new phone number from your SignalWire Dashboard. ([Guide](https://developer.signalwire.com/apis/docs/buying-a-phone-number)) 11 | 3. Note the Project ID and API key from your SignalWire Dashboard. ([Guide](https://developer.signalwire.com/apis/docs/getting-started-with-the-signalwire-video-api-1#obtaining-your-api-key-and-project-id)) 12 | 4. Rename the `env.sample` file as `.env` and fill in the Phone Number, Project ID and API key. 13 | 5. Run `yarn start` to start the demo application. 14 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS Relay v4/env.sample: -------------------------------------------------------------------------------- 1 | PROJECT_ID= 2 | API_TOKEN= 3 | PHONE_NUMBER= -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS Relay v4/html/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | .body { 6 | width: 100vw; 7 | height: 100vh; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | } 12 | form { 13 | width: 300px; 14 | height: 300px; 15 | } 16 | 17 | label { 18 | width: 100%; 19 | } 20 | input { 21 | width: 100%; 22 | } 23 | textarea { 24 | width: 100%; 25 | max-width: 100%; 26 | min-width: 100%; 27 | max-height: 300px; 28 | } 29 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS Relay v4/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SMS with SignalWire RealTime API 5 | 6 | 7 | 8 |
9 |
10 |

Send an SMS with SignalWire

11 | 12 | 17 |
18 |
19 | Message: 20 | 21 | 22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS Relay v4/index.js: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { SignalWire } from "@signalwire/realtime-api"; 3 | 4 | const client = await SignalWire({ 5 | project: process.env.PROJECT_ID, 6 | token: process.env.API_TOKEN, 7 | }); 8 | 9 | let messageClient = client.messaging; 10 | 11 | const sendingPhoneNumber = process.env.PHONE_NUMBER; 12 | 13 | const express = require("express"); 14 | const app = express(); 15 | const port = 3000; 16 | const bodyparser = require("body-parser"); 17 | const isE164PhoneNumber = require("is-e164-phone-number"); 18 | 19 | app.use(bodyparser.urlencoded({ extended: true })); 20 | app.use("/", express.static("html")); 21 | 22 | app.post("/sendSMS", async (req, res) => { 23 | let { phoneno, body } = req.body; 24 | if (typeof body !== "string" || body === "") return res.send("Invalid body"); 25 | if (!isE164PhoneNumber(phoneno)) return res.send("Invalid Phone Number"); 26 | 27 | console.log("Sending message to phone number", phoneno); 28 | try { 29 | const status = await messageClient.send({ 30 | topic: "office", 31 | from: sendingPhoneNumber, // The number you bought from SignalWire 32 | to: phoneno, 33 | body, 34 | }); 35 | 36 | console.log(status); 37 | return res.send("Your SMS was sent"); 38 | } catch (e) { 39 | console.error(e); 40 | return res.send("Error sending SMS"); 41 | } 42 | }); 43 | 44 | app.listen(port, () => { 45 | console.log(`Example app listening on port ${port}`); 46 | }); 47 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS Relay v4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smsdemo", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node index.js", 9 | "dev": "nodemon index.js" 10 | }, 11 | "dependencies": { 12 | "@signalwire/realtime-api": "^4.0.0", 13 | "body-parser": "^1.20.0", 14 | "dotenv": "^16.0.0", 15 | "express": "^4.17.3", 16 | "is-e164-phone-number": "^1.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS/README.md: -------------------------------------------------------------------------------- 1 | # Send SMS from the browser with SignalWire APIs - Node JS 2 | 3 | A demo application that demonstrates how to send an SMS message using the SignalWire Messaging API. 4 | 5 | 📖 [Read the full guide](https://developer.signalwire.com/apis/docs/send-sms-from-the-browser-using-node-js?relay_version=relayv3) 6 | 7 | ## Setup 8 | 9 | 1. Use `yarn install` to install the dependencies. 10 | 2. Buy a new phone number from your SignalWire Dashboard. ([Guide](https://developer.signalwire.com/apis/docs/buying-a-phone-number)) 11 | 3. Note the Project ID and API key from your SignalWire Dashboard. ([Guide](https://developer.signalwire.com/apis/docs/getting-started-with-the-signalwire-video-api-1#obtaining-your-api-key-and-project-id)) 12 | 4. Rename the `env.sample` file as `.env` and fill in the Phone Number, Project ID and API key. 13 | 5. Run `yarn start` to start the demo application. 14 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS/env.sample: -------------------------------------------------------------------------------- 1 | PROJECT_ID= 2 | API_TOKEN= 3 | PHONE_NUMBER= -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS/html/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | .body { 6 | width: 100vw; 7 | height: 100vh; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | } 12 | form { 13 | width: 300px; 14 | height: 300px; 15 | } 16 | 17 | label { 18 | width: 100%; 19 | } 20 | input { 21 | width: 100%; 22 | } 23 | textarea { 24 | width: 100%; 25 | max-width: 100%; 26 | min-width: 100%; 27 | max-height: 300px; 28 | } 29 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SMS with SignalWire RealTime API 5 | 6 | 7 | 8 |
9 |
10 |

Send an SMS with SignalWire

11 | 12 | 17 |
18 |
19 | Message: 20 | 21 | 22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS/index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | let sw = require("@signalwire/realtime-api"); 3 | let Messaging = sw.Messaging; 4 | 5 | const sendingPhoneNumber = process.env.PHONE_NUMBER; 6 | 7 | const client = new Messaging.Client({ 8 | project: process.env.PROJECT_ID, 9 | token: process.env.API_TOKEN, 10 | }); 11 | 12 | const express = require("express"); 13 | const app = express(); 14 | const port = 3000; 15 | const bodyparser = require("body-parser"); 16 | const isE164PhoneNumber = require("is-e164-phone-number"); 17 | 18 | app.use(bodyparser.urlencoded({ extended: true })); 19 | app.use("/", express.static("html")); 20 | 21 | app.post("/sendSMS", async (req, res) => { 22 | let { phoneno, body } = req.body; 23 | if (typeof body !== "string" || body === "") return res.send("Invalid body"); 24 | if (!isE164PhoneNumber(phoneno)) return res.send("Invalid Phone Number"); 25 | 26 | console.log("Sending message to phone number", phoneno); 27 | try { 28 | const status = await client.send({ 29 | context: "office", 30 | from: sendingPhoneNumber, // The number you bought from SignalWire 31 | to: phoneno, 32 | body, 33 | }); 34 | 35 | console.log(status); 36 | return res.send("Your SMS was sent"); 37 | } catch (e) { 38 | console.error(e); 39 | return res.send("Error sending SMS"); 40 | } 41 | }); 42 | 43 | app.listen(port, () => { 44 | console.log(`Example app listening on port ${port}`); 45 | }); 46 | -------------------------------------------------------------------------------- /Messaging/Sending SMS from the Browser - NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smsdemo", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "node index.js", 8 | "dev": "nodemon index.js" 9 | }, 10 | "dependencies": { 11 | "@signalwire/realtime-api": "^3.0.0", 12 | "body-parser": "^1.20.0", 13 | "dotenv": "^16.0.0", 14 | "express": "^4.17.3", 15 | "is-e164-phone-number": "^1.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Messaging/Text Subscription with Python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | ADD app.py / 4 | ADD campaigns.json / 5 | 6 | RUN pip install flask 7 | RUN pip install signalwire 8 | 9 | EXPOSE 5000 10 | 11 | CMD [ "python", "./app.py" ] -------------------------------------------------------------------------------- /Messaging/Text Subscription with Python/campaigns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Id": "1", 4 | "Name": "signalwire-demo-1", 5 | "Phrases": [ 6 | "signalwire" 7 | ], 8 | "Subscribers": [ 9 | ] 10 | }, 11 | { 12 | "Id": "2", 13 | "Name": "signalwire-demo-2", 14 | "Phrases": [ 15 | "original" 16 | ], 17 | "Subscribers": [ 18 | ] 19 | } 20 | ] -------------------------------------------------------------------------------- /Messaging/Text Subscription with Python/donotcontact.json: -------------------------------------------------------------------------------- 1 | { 2 | "DoNotContact": [] 3 | } -------------------------------------------------------------------------------- /Messaging/Text Subscription with Python/example.env: -------------------------------------------------------------------------------- 1 | # This is the full name of your SignalWire Space. e.g.: example.signalwire.com 2 | SIGNALWIRE_SPACE= 3 | # Your Project ID - you can find it on the `API` page in your Dashboard. 4 | SIGNALWIRE_PROJECT= 5 | # Your API token - you can generate one on the `API` page in your Dashboard 6 | SIGNALWIRE_TOKEN= 7 | # The phone number you'll be using for this Snippets. Must include the `+1` , e.g.: +15551234567 8 | SIGNALWIRE_NUMBER= 9 | # MailGun domain associated with your MailGun account 10 | MAILGUN_DOMAIN= 11 | # MailGun token associated with your MailGun Account 12 | MAILGUN_API_TOKEN= 13 | # Send Email From Address 14 | EMAIL_FROM=info@yourdomain.com 15 | # Send email to address for administrator notifications 16 | EMAIL_TO=youremail@yourdomain.com 17 | # Email subject for admin notifications 18 | EMAIL_SUBJECT=SMS TO EMAIL 19 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS Relay v4/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /frontend/build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS Relay v4/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | WORKDIR /app 4 | 5 | COPY package*.json ./ 6 | RUN npm install 7 | 8 | COPY . . 9 | 10 | EXPOSE 5000 11 | 12 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS Relay v4/example.env: -------------------------------------------------------------------------------- 1 | # Your Project ID - you can find it on the `API` page in your Dashboard. 2 | PROJECT_ID= 3 | # Your API token - you can generate one on the `API` page in your Dashboard 4 | API_TOKEN= 5 | # The phone number you'll be using for this Snippet. Must include the `+1` , E.164 format 6 | SIGNALWIRE_NUMBER= 7 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS Relay v4/html/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | .body { 6 | width: 100vw; 7 | height: 50vh; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | } 12 | form { 13 | width: 300px; 14 | height: 300px; 15 | } 16 | label { 17 | width: 100%; 18 | } 19 | input { 20 | width: 100%; 21 | } 22 | button { 23 | margin: 3px; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS Relay v4/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Two Factor Auth via SMS with SignalWire RealTime API 6 | 7 | 8 | 9 | 10 |
11 |
12 |

Request a One-time Authentication Code

13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |

Validate with Your Authentication Code

21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS Relay v4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "two-factor-authentication-via-sms---node", 3 | "version": "1.0.0", 4 | "description": "Two Factor Authentication (2FA) can provide your users effective protection against many security threats that target user passwords and accounts. This application will generate a one-time password that is sent to the recipient's phone number via SMS. Application developers can enable two-factor authentication for their users with ease and without making any changes to the already existing application logic or database structure!", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "start": "node index.js", 10 | "dev": "nodemon index.js" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "@signalwire/realtime-api": "^4.0.0", 16 | "dotenv": "^16.0.1", 17 | "express": "^4.18.1", 18 | "phone": "^3.1.22" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules/ 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /frontend/build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | WORKDIR /app 4 | 5 | COPY package*.json ./ 6 | RUN npm install 7 | 8 | COPY . . 9 | 10 | EXPOSE 5000 11 | 12 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS/example.env: -------------------------------------------------------------------------------- 1 | # Your Project ID - you can find it on the `API` page in your Dashboard. 2 | PROJECT_ID= 3 | # Your API token - you can generate one on the `API` page in your Dashboard 4 | API_TOKEN= 5 | # The phone number you'll be using for this Snippet. Must include the `+1` , E.164 format 6 | SIGNALWIRE_NUMBER= 7 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS/html/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | .body { 6 | width: 100vw; 7 | height: 50vh; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | } 12 | form { 13 | width: 300px; 14 | height: 300px; 15 | } 16 | label { 17 | width: 100%; 18 | } 19 | input { 20 | width: 100%; 21 | } 22 | button { 23 | margin: 3px; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Two Factor Auth via SMS with SignalWire RealTime API 6 | 7 | 8 | 9 | 10 |
11 |
12 |

Request a One-time Authentication Code

13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |

Validate with Your Authentication Code

21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "two-factor-authentication-via-sms---node", 3 | "version": "1.0.0", 4 | "description": "Two Factor Authentication (2FA) can provide your users effective protection against many security threats that target user passwords and accounts. This application will generate a one-time password that is sent to the recipient's phone number via SMS. Application developers can enable two-factor authentication for their users with ease and without making any changes to the already existing application logic or database structure!", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js", 9 | "dev": "nodemon index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@signalwire/realtime-api": "^3.0.2", 15 | "dotenv": "^16.0.1", 16 | "express": "^4.18.1", 17 | "phone": "^3.1.22" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - Python/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 SIGNALWIRE, INC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - Python/python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | ADD app.py / 4 | 5 | RUN pip install flask 6 | RUN pip install signalwire 7 | 8 | EXPOSE 5000 9 | 10 | CMD [ "python", "./app.py" ] 11 | -------------------------------------------------------------------------------- /Messaging/Two Factor Authentication via SMS - Python/python/example.env: -------------------------------------------------------------------------------- 1 | ## This is the full name of your SignalWire Space. e.g.: example.signalwire.com 2 | SIGNALWIRE_SPACE= 3 | # Your Project ID - you can find it on the `API` page in your Dashboard. 4 | SIGNALWIRE_PROJECT= 5 | # Your API token - you can generate one on the `API` page in your Dashboard 6 | SIGNALWIRE_TOKEN= 7 | # The phone number you'll be using for this Snippets. Must include the `+1` , e$ 8 | SIGNALWIRE_NUMBER= 9 | -------------------------------------------------------------------------------- /PhoneNumbers/readme.MD: -------------------------------------------------------------------------------- 1 | # Phone Number Guides -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SignalWire Guides 2 | 3 | Explore our guides and code examples. 4 | 5 | ### Explore by category 6 | 7 |    [🖥   Video](./Video) 8 | 9 |    [📞   Voice](./Voice) 10 | 11 |    [📞   Phone Numbers](./PhoneNumbers) 12 | 13 |    [💬   Chat](./Chat) 14 | 15 |    [💬   Messaging](./Messaging) 16 | 17 |    [📠   Fax](./Fax) 18 | 19 |    [🔌   Integrations](./Integrations) -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/README.md: -------------------------------------------------------------------------------- 1 | # Using the AppKit with Angular 2 | 3 | This is the integration example of AppKit with Angular. The project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.1.3. 4 | 5 | Using the Angular CLI, you can run `ng serve` for a dev server which you can access at `http://localhost:4200/`. The application will automatically reload if you change any of the source files. Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 6 | 7 | For a full guide to this implementation, see the blog [Video Conference AppKit: Vue 3 Integration](https://signalwire.com/blogs/developers/video-conference-appkit-with-angular). 8 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/angular-project'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-project", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^14.1.0", 14 | "@angular/common": "^14.1.0", 15 | "@angular/compiler": "^14.1.0", 16 | "@angular/core": "^14.1.0", 17 | "@angular/forms": "^14.1.0", 18 | "@angular/platform-browser": "^14.1.0", 19 | "@angular/platform-browser-dynamic": "^14.1.0", 20 | "@angular/router": "^14.1.0", 21 | "@signalwire/app-kit": "^0.0.1-dev.202208231654.564d9a2.4", 22 | "@stencil/store": "^2.0.0", 23 | "@types/jest": "^28.1.8", 24 | "rxjs": "~7.5.0", 25 | "tslib": "^2.3.0", 26 | "zone.js": "~0.11.4" 27 | }, 28 | "devDependencies": { 29 | "@angular-devkit/build-angular": "^14.1.3", 30 | "@angular/cli": "~14.1.3", 31 | "@angular/compiler-cli": "^14.1.0", 32 | "@stencil/core": "^2.17.4", 33 | "@types/jasmine": "~4.0.0", 34 | "jasmine-core": "~4.2.0", 35 | "karma": "~6.4.0", 36 | "karma-chrome-launcher": "~3.1.0", 37 | "karma-coverage": "~2.2.0", 38 | "karma-jasmine": "~5.1.0", 39 | "karma-jasmine-html-reporter": "~2.0.0", 40 | "typescript": "~4.7.2" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/AppKit-Framework-Examples/Angular/src/app/app.component.css -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 30 | 31 | 35 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async () => { 6 | await TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | }); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'angular-project'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.componentInstance; 22 | expect(app.title).toEqual('angular-project'); 23 | }); 24 | 25 | it('should render title', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.nativeElement as HTMLElement; 29 | expect(compiled.querySelector('.content span')?.textContent).toContain('angular-project app is running!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import '@signalwire/app-kit'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.css'], 8 | }) 9 | export class AppComponent implements OnInit { 10 | @ViewChild('videoComponent', { static: true }) videoComponent: ElementRef; 11 | title = 'angular-project'; 12 | ngOnInit(): void { 13 | this.videoComponent.nativeElement.setupRoomSession = (rs) => { 14 | console.log('Setting up Room Session'); 15 | 16 | rs.on('room.joined', (e) => { 17 | console.log('Joined room:', e.room_session.name); 18 | rs.videoMute(); 19 | }); 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppComponent } from './app.component'; 5 | 6 | @NgModule({ 7 | declarations: [AppComponent], 8 | imports: [BrowserModule], 9 | providers: [], 10 | bootstrap: [AppComponent], 11 | schemas: [CUSTOM_ELEMENTS_SCHEMA], 12 | }) 13 | export class AppModule {} 14 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/AppKit-Framework-Examples/Angular/src/assets/.gitkeep -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/AppKit-Framework-Examples/Angular/src/favicon.ico -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularProject 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | (id: string): T; 13 | keys(): string[]; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), 21 | ); 22 | 23 | // Then we find all the tests. 24 | const context = require.context('./', true, /\.spec\.ts$/); 25 | // And load the modules. 26 | context.keys().forEach(context); 27 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": false, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "es2020", 20 | "module": "es2020", 21 | "lib": [ 22 | "es2020", 23 | "dom" 24 | ], 25 | "allowSyntheticDefaultImports": true 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Angular/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/README.md: -------------------------------------------------------------------------------- 1 | # Using the AppKit with React 2 | 3 | This is the integration example of AppKit with React. We used `npx create-react-app` and then updated only `App.js` to embed a video conference. For a full guide to this implementation, see the blog [Video Conference AppKit: React Integration](https://signalwire.com/blogs/developers/using-the-video-conference-app-kit-with-react). 4 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cra", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@signalwire/app-kit": "^0.0.1-next.6", 7 | "@testing-library/jest-dom": "^5.16.5", 8 | "@testing-library/react": "^13.3.0", 9 | "@testing-library/user-event": "^13.5.0", 10 | "axios": "^0.27.2", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "react-scripts": "5.0.1", 14 | "web-vitals": "^2.1.4" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/AppKit-Framework-Examples/React/public/favicon.ico -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/AppKit-Framework-Examples/React/public/logo192.png -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/AppKit-Framework-Examples/React/public/logo512.png -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useLayoutEffect, useRef } from "react"; 2 | import "./App.css"; 3 | import "@signalwire/app-kit"; 4 | 5 | function App() { 6 | const videoComponent = useRef(); 7 | 8 | useLayoutEffect(() => { 9 | if (videoComponent.current) { 10 | videoComponent.current.setupRoomSession = (rs) => { 11 | console.log("Setting up Room Session"); 12 | 13 | rs.on("room.joined", (e) => 14 | console.log("Joined room:", e.room_session.name) 15 | ); 16 | }; 17 | } 18 | }, []); 19 | 20 | return ( 21 |
22 | 28 |
29 | ); 30 | } 31 | 32 | export default App; 33 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render(); 9 | 10 | // If you want to start measuring performance in your app, pass a function 11 | // to log results (for example: reportWebVitals(console.log)) 12 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 13 | reportWebVitals(); 14 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/React/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vite/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vite/README.md: -------------------------------------------------------------------------------- 1 | # Using the AppKit with Vite.js 2 | 3 | This is the integration example of AppKit with Vite. We used `npm create vite@latest` and selected `Vanilla` and `JavaScript` when prompted. The scaffolding started us with the external file `main.js` where we could insert our `sw-video-conference` component with `innerHTML`. 4 | 5 | ```js 6 | import "./style.css"; 7 | import "@signalwire/app-kit"; 8 | 9 | document.querySelector("#app")!.innerHTML = ` 10 | 16 | `; 17 | ``` 18 | 19 | Just these few lines of code are enough to run a fully functional video conference room. To go one step forward and use the `setupRoomSession` callback function available on the `sw-video-conference` component, we used `document.createElement` to create the element, access the callback function, and get the Room Session object before adding it to the HTML. 20 | 21 | For a full guide to this implementation, see the blog [Video Conference AppKit: Vite Integration](https://signalwire.com/blogs/developers/video-conference-appkit-with-vite). 22 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vite/main.js: -------------------------------------------------------------------------------- 1 | import "@signalwire/app-kit"; 2 | document.body.onload = addElement; 3 | 4 | function addElement() { 5 | const roomSession = document.createElement("sw-video-conference"); 6 | roomSession.setAttribute("token", "vpt_25e...8dd"); 7 | roomSession.setAttribute("user-name", "Joe"); 8 | roomSession.setAttribute("device-picker", "false"); 9 | roomSession.setupRoomSession = (rs) => { 10 | console.log("Setting up Room Session", rs); 11 | 12 | rs.on("room.joined", (e) => 13 | console.log("Joined room:", e.room.display_name) 14 | ); 15 | }; 16 | document.getElementById("app").append(roomSession); 17 | } 18 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "vite": "^3.2.3" 13 | }, 14 | "dependencies": { 15 | "@signalwire/app-kit": "^0.0.1-next.6" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vite/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vite/src/typescript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vite/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | 27 | 28 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 29 | 30 | # dependencies 31 | /node_modules 32 | /.pnp 33 | .pnp.js 34 | 35 | # testing 36 | /coverage 37 | 38 | # production 39 | /build 40 | 41 | # misc 42 | .DS_Store 43 | .env.local 44 | .env.development.local 45 | .env.test.local 46 | .env.production.local 47 | 48 | npm-debug.log* 49 | yarn-debug.log* 50 | yarn-error.log* 51 | 52 | 53 | # See http://help.github.com/ignore-files/ for more about ignoring files. 54 | 55 | # Compiled output 56 | /dist 57 | /tmp 58 | /out-tsc 59 | /bazel-out 60 | 61 | # Node 62 | /node_modules 63 | npm-debug.log 64 | yarn-error.log 65 | 66 | # IDEs and editors 67 | .idea/ 68 | .project 69 | .classpath 70 | .c9/ 71 | *.launch 72 | .settings/ 73 | *.sublime-workspace 74 | 75 | # Visual Studio Code 76 | .vscode/* 77 | !.vscode/settings.json 78 | !.vscode/tasks.json 79 | !.vscode/launch.json 80 | !.vscode/extensions.json 81 | .history/* 82 | 83 | # Miscellaneous 84 | /.angular/cache 85 | .sass-cache/ 86 | /connect.lock 87 | /coverage 88 | /libpeerconnection.log 89 | testem.log 90 | /typings 91 | 92 | # System files 93 | .DS_Store 94 | Thumbs.db 95 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/README.md: -------------------------------------------------------------------------------- 1 | # Using the AppKit with Vue 3 2 | 3 | This is the integration example of AppKit with Vue 3. It is built with Vite to be TypeScript-ready. We used the create-vue scaffolding tool with `npm init vue@latest` and then updated only `App.vue` to embed a video conference. For a full guide to this implementation, see the blog [Video Conference AppKit: Vue 3 Integration](https://signalwire.com/blogs/developers/video-conference-appkit-with-vue-3). 4 | 5 | For more on using Vue with TypeScript, see the [Vue documentation](https://vuejs.org/guide/typescript/overview.html). 6 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-project", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "dev": "vite", 6 | "build": "run-p type-check build-only", 7 | "preview": "vite preview --port 4173", 8 | "build-only": "vite build", 9 | "type-check": "vue-tsc --noEmit" 10 | }, 11 | "dependencies": { 12 | "@signalwire/app-kit": "^0.0.1-dev.202208231654.564d9a2.4", 13 | "vue": "^3.2.37" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^16.11.47", 17 | "@vitejs/plugin-vue": "^3.0.1", 18 | "@vitejs/plugin-vue-jsx": "^2.0.0", 19 | "@vue/tsconfig": "^0.1.3", 20 | "npm-run-all": "^4.1.5", 21 | "typescript": "~4.7.4", 22 | "vite": "^3.0.4", 23 | "vue-tsc": "^0.39.5" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/AppKit-Framework-Examples/Vue 3/public/favicon.ico -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import "./base.css"; 2 | 3 | #app { 4 | max-width: 1280px; 5 | margin: 0 auto; 6 | padding: 2rem; 7 | 8 | font-weight: normal; 9 | } 10 | 11 | a, 12 | .green { 13 | text-decoration: none; 14 | color: hsla(160, 100%, 37%, 1); 15 | transition: 0.4s; 16 | } 17 | 18 | @media (hover: hover) { 19 | a:hover { 20 | background-color: hsla(160, 100%, 37%, 0.2); 21 | } 22 | } 23 | 24 | @media (min-width: 1024px) { 25 | body { 26 | display: flex; 27 | place-items: center; 28 | } 29 | 30 | #app { 31 | display: grid; 32 | grid-template-columns: 1fr 2fr; 33 | padding: 0 2rem; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | import './assets/main.css' 5 | 6 | createApp(App).mount('#app') 7 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/tsconfig.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.node.json", 3 | "include": ["vite.config.*", "vitest.config.*", "cypress.config.*"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "types": ["node"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.web.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./src/*"] 8 | } 9 | }, 10 | 11 | "references": [ 12 | { 13 | "path": "./tsconfig.config.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Video/AppKit-Framework-Examples/Vue 3/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | import vueJsx from '@vitejs/plugin-vue-jsx' 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [vue(), vueJsx()], 10 | resolve: { 11 | alias: { 12 | '@': fileURLToPath(new URL('./src', import.meta.url)) 13 | } 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /Video/Embed Video Rooms - Videoconferencing Widget/README.md: -------------------------------------------------------------------------------- 1 | # Embed Video Rooms: Videoconferencing Widget 2 | 3 | 📖 [Read the full guide](https://developer.signalwire.com/guides/video/creating-a-video-room) 4 | 5 | The SignalWire Video APIs give you full flexibility to build your own personalized video conferencing experience. But if you just need a basic video-conference widget, you can get started by copy-pasting a **Video Room Widget** from your SignalWire space. Video Rooms can be embedded in your CMS like **WordPress**, **Drupal**, or any other kind of **static HTML page**, simply by **copy-pasting** a snippet of HTML code. 6 | 7 | # Running the code 8 | 9 | Simply open [index.html](index.html) in your browser. We have configured a room with a demo account. **Make sure to replace the code snippet with your own!** 10 | -------------------------------------------------------------------------------- /Video/Embed Video Rooms - Videoconferencing Widget/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Static Template 8 | 9 | 10 |

This is a static HTML page.

11 |

Here is an embedded room:

12 | 13 |
14 | 15 | 33 | 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/README.md: -------------------------------------------------------------------------------- 1 | # Interactive Live Streaming Demo 2 | 3 | 📖 [Read the full guide](https://developer.signalwire.com/guides/video/interactive-live-streaming) 4 | 5 | ## Get started 6 | 7 | Create a file at `server/.env`, with the following information: 8 | 9 | ``` 10 | # server/.env 11 | 12 | PROJECT_ID= 13 | API_TOKEN= 14 | SPACE_URL=.signalwire.com 15 | ``` 16 | 17 | Make sure that your API token has the Video and PubSub scopes enabled. 18 | 19 | Then install the dependencies with `npm install` and run the server and the client with `npm run start`. 20 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "checkJs": true, 4 | "jsx": "react-jsx" 5 | }, 6 | "exclude": ["node_modules", "**/node_modules/*"] 7 | } -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "livewire-broadcasting", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/react": "^11.10.4", 7 | "@emotion/styled": "^11.10.4", 8 | "@mui/icons-material": "^5.10.6", 9 | "@mui/material": "^5.10.7", 10 | "@signalwire-community/react": "^1.4.2", 11 | "@signalwire/js": "^3.17.0", 12 | "@testing-library/jest-dom": "^5.16.5", 13 | "@testing-library/react": "^13.4.0", 14 | "@testing-library/user-event": "^13.5.0", 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0", 17 | "react-router-dom": "^6.4.1", 18 | "react-scripts": "5.0.1", 19 | "web-vitals": "^2.1.4" 20 | }, 21 | "resolutions": { 22 | "@signalwire/js": "^3.17.0" 23 | }, 24 | "scripts": { 25 | "postinstall": "cd server && npm install", 26 | "start": "concurrently \"react-scripts start\" \"npm run start:server\"", 27 | "start:server": "cd server && npm run start", 28 | "build": "react-scripts build", 29 | "test": "react-scripts test", 30 | "eject": "react-scripts eject" 31 | }, 32 | "eslintConfig": { 33 | "extends": [ 34 | "react-app", 35 | "react-app/jest" 36 | ] 37 | }, 38 | "browserslist": { 39 | "production": [ 40 | ">0.2%", 41 | "not dead", 42 | "not op_mini all" 43 | ], 44 | "development": [ 45 | "last 1 chrome version", 46 | "last 1 firefox version", 47 | "last 1 safari version" 48 | ] 49 | }, 50 | "devDependencies": { 51 | "concurrently": "^7.4.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/Interactive-Live-Streaming/public/favicon.ico -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/server/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "checkJs": true, 4 | }, 5 | "exclude": ["node_modules", "**/node_modules/*"] 6 | } -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "axios": "^0.27.2", 14 | "body-parser": "^1.20.0", 15 | "cors": "^2.8.5", 16 | "dotenv": "^16.0.2", 17 | "express": "^4.18.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/App.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: rgb(37,37,37); 3 | color: rgb(204,204,204); 4 | } 5 | 6 | .App { 7 | text-align: center; 8 | } 9 | 10 | .App-logo { 11 | height: 40vmin; 12 | pointer-events: none; 13 | } 14 | 15 | @media (prefers-reduced-motion: no-preference) { 16 | .App-logo { 17 | animation: App-logo-spin infinite 20s linear; 18 | } 19 | } 20 | 21 | .App-header { 22 | background-color: #282c34; 23 | min-height: 100vh; 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | justify-content: center; 28 | font-size: calc(10px + 2vmin); 29 | color: white; 30 | } 31 | 32 | .App-link { 33 | color: #61dafb; 34 | } 35 | 36 | @keyframes App-logo-spin { 37 | from { 38 | transform: rotate(0deg); 39 | } 40 | to { 41 | transform: rotate(360deg); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./App.css"; 3 | import { createBrowserRouter, RouterProvider } from "react-router-dom"; 4 | import { ThemeProvider, createTheme } from "@mui/material/styles"; 5 | import Prejoin from "./Prejoin"; 6 | import InCall from "./InCall"; 7 | 8 | const darkTheme = createTheme({ 9 | palette: { 10 | mode: "dark", 11 | }, 12 | }); 13 | 14 | export default function App() { 15 | const router = createBrowserRouter([ 16 | { 17 | path: "/", 18 | element: , 19 | }, 20 | { 21 | path: "in-call", 22 | element: , 23 | }, 24 | ]); 25 | 26 | return ( 27 | 28 | 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/InCall.module.css: -------------------------------------------------------------------------------- 1 | .grid { 2 | display: grid; 3 | grid-template-columns: 70vw 1fr; 4 | grid-template-rows: 1fr 100px; 5 | height: 100vh; 6 | } 7 | 8 | .video { 9 | background-color: black; 10 | aspect-ratio: 16 / 9; 11 | max-height: 100%; 12 | max-width: 100%; 13 | } 14 | 15 | .sidebar { 16 | padding: 10px; 17 | } 18 | 19 | .bottombar { 20 | padding: 5px 20px; 21 | grid-column-start: 1; 22 | grid-column-end: -1; 23 | grid-row-start: 2; 24 | height: 100%; 25 | } 26 | 27 | .bottombar > div { 28 | display: flex; 29 | gap: 10px; 30 | } -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/Prejoin.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { TextField, Button } from "@mui/material"; 3 | import { useNavigate } from "react-router-dom"; 4 | import style from "./Prejoin.module.css"; 5 | 6 | export default function Prejoin() { 7 | const navigate = useNavigate(); 8 | const [username, setUsername] = useState(""); 9 | 10 | async function onJoinClicked(mod) { 11 | if (!username) return; 12 | 13 | const endpoint = mod ? "/get_member_token" : "/get_audience_token"; 14 | const token = await fetch(`http://127.0.0.1:15000${endpoint}`, { 15 | method: "POST", 16 | headers: { 17 | "Content-Type": "application/json", 18 | }, 19 | body: JSON.stringify({ 20 | user_name: username, 21 | room_name: "my_live_stream", 22 | }), 23 | }); 24 | 25 | navigate("/in-call", { 26 | state: { 27 | token: (await token.json()).token, 28 | userName: username, 29 | }, 30 | }); 31 | } 32 | 33 | return ( 34 |
35 |
My Live Stream
36 |
37 | setUsername(e.target.value)} 42 | /> 43 |
44 | 47 | 50 |
51 |
52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/Prejoin.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | max-width: 600px; 3 | margin: 60px auto; 4 | } 5 | 6 | .title { 7 | font-size: 2rem; 8 | text-align: center; 9 | } 10 | 11 | .joinForm { 12 | display: flex; 13 | flex-direction: column; 14 | max-width: 500px; 15 | margin: 60px auto; 16 | } 17 | 18 | .joinButtons { 19 | margin: 30px auto; 20 | } 21 | 22 | .joinButtons > button { 23 | margin: 0 10px; 24 | } -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/components/Audience.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | margin-bottom: 2em; 3 | } 4 | 5 | .container > div { 6 | display: flex; 7 | align-items: center; 8 | padding: 0 10px; 9 | } 10 | 11 | .container > div:hover { 12 | background-color: rgb(51,51,51); 13 | } 14 | 15 | .container > div > span { 16 | flex: 1; 17 | } -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/components/AudienceCount.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | 3 | export default function AudienceCount({ roomSession }) { 4 | const [count, setCount] = useState(0); 5 | 6 | useEffect(() => { 7 | if (!roomSession) return; 8 | 9 | const onAudienceCount = (e) => { 10 | setCount(e.total); 11 | }; 12 | roomSession.on("room.audience_count", onAudienceCount); 13 | 14 | return () => { 15 | roomSession.off("room.audience_count", onAudienceCount); 16 | }; 17 | }, [roomSession]); 18 | 19 | return ( 20 |
21 | Audience count: {count} 22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/components/CameraButton.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import SplitButton from "./SplitButton"; 3 | import VideocamOffIcon from "@mui/icons-material/VideocamOff"; 4 | import VideocamIcon from "@mui/icons-material/Videocam"; 5 | import { useMembers, useWebRTC } from "@signalwire-community/react"; 6 | 7 | export default function CameraButton({ roomSession }) { 8 | const { cameras } = useWebRTC({ 9 | camera: true, 10 | microphone: false, 11 | speaker: false, 12 | }); 13 | 14 | const { members } = useMembers(roomSession); 15 | 16 | const self = members.find((m) => m.id === roomSession?.memberId); 17 | 18 | return ( 19 | } 22 | unmutedIcon={} 23 | devices={cameras} 24 | onSetMuted={(muted) => 25 | muted ? roomSession.videoMute() : roomSession.videoUnmute() 26 | } 27 | onDevicePicked={(deviceId) => roomSession.updateCamera({ deviceId })} 28 | /> 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/components/LeaveButton.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Button from "@mui/material/Button"; 3 | 4 | export default function LeaveButton({ roomSession }) { 5 | return ( 6 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/components/Members.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import IconButton from "@mui/material/IconButton"; 3 | import LogoutIcon from "@mui/icons-material/Logout"; 4 | import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; 5 | import { useMembers } from "@signalwire-community/react"; 6 | import { Tooltip } from "@mui/material"; 7 | import style from "./Members.module.css"; 8 | 9 | export default function Members({ roomSession }) { 10 | const { members } = useMembers(roomSession); 11 | 12 | return ( 13 |
14 | {members?.map((member) => ( 15 |
16 | {member.name} 17 | 18 | 19 |
20 | ))} 21 |
22 | ); 23 | } 24 | 25 | function SmallLeaveButton({ roomSession, member }) { 26 | return ( 27 | 28 | roomSession?.removeMember({ memberId: member.id })} 32 | > 33 | 34 | 35 | 36 | ); 37 | } 38 | 39 | function SmallDemoteButton({ roomSession, member }) { 40 | return ( 41 | 42 | roomSession?.demote({ memberId: member.id })} 46 | > 47 | 48 | 49 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/components/Members.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | margin-bottom: 2em; 3 | } 4 | 5 | .container > div { 6 | display: flex; 7 | align-items: center; 8 | padding: 0 10px; 9 | } 10 | 11 | .container > div:hover { 12 | background-color: rgb(51,51,51); 13 | } 14 | 15 | .container > div > span { 16 | flex: 1; 17 | } -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/components/MicrophoneButton.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import SplitButton from "./SplitButton"; 3 | import MicOffIcon from "@mui/icons-material/MicOff"; 4 | import MicIcon from "@mui/icons-material/Mic"; 5 | import { useMembers, useWebRTC } from "@signalwire-community/react"; 6 | 7 | export default function MicrophoneButton({ roomSession }) { 8 | const { microphones } = useWebRTC({ 9 | camera: false, 10 | microphone: true, 11 | speaker: false, 12 | }); 13 | 14 | const { members } = useMembers(roomSession); 15 | 16 | const self = members.find((m) => m.id === roomSession?.memberId); 17 | 18 | return ( 19 | } 22 | unmutedIcon={} 23 | devices={microphones} 24 | onSetMuted={(muted) => 25 | muted ? roomSession.audioMute() : roomSession.audioUnmute() 26 | } 27 | onDevicePicked={(deviceId) => roomSession.updateMicrophone({ deviceId })} 28 | /> 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /Video/Interactive-Live-Streaming/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /Video/Layout-Positions/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | dist -------------------------------------------------------------------------------- /Video/Layout-Positions/README.md: -------------------------------------------------------------------------------- 1 | # Layout Positions 2 | 3 | This guide shows how to control positions and layouts in a video room. 4 | 5 | 📖 [Read the full guide](https://developer.signalwire.com/apis/docs/layout-positions) 6 | 7 | ### How to run this demo 8 | 9 | 1. `npm install` 10 | 2. `npm run start` 11 | 12 | -------------------------------------------------------------------------------- /Video/Layout-Positions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "positions-for-layouts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": { 11 | "parcel-bundler": "^1.12.5" 12 | }, 13 | "devDependencies": { 14 | "@babel/core": "7.2.0", 15 | "typescript": "4.4.4" 16 | }, 17 | "resolutions": { 18 | "@babel/preset-env": "7.13.8" 19 | }, 20 | "browserslist": [ 21 | "since 2021-01" 22 | ], 23 | "keywords": [] 24 | } 25 | -------------------------------------------------------------------------------- /Video/Layout-Positions/src/styles.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: sans-serif; 3 | font-size: 16px; 4 | } 5 | 6 | #video-conference { 7 | max-height: 400px; 8 | aspect-ratio: 16 / 9; 9 | } 10 | 11 | #layout-cfg, #position-cfg { 12 | background-color: whitesmoke; 13 | padding: 10px; 14 | margin-top: 20px; 15 | } -------------------------------------------------------------------------------- /Video/README.md: -------------------------------------------------------------------------------- 1 | # Video Guides 2 | 3 | [Embed Video Rooms - Videoconferencing Widget](./Embed%20Video%20Rooms%20-%20Videoconferencing%20Widget) 4 | Embed a videoconferencing widget in your website without any software development experience. 5 | 6 | [Create a Simple Video Demo](./Simple%20Video%20Demo) 7 | Develop a simple full-stack video demo with this step-by-step walk-through. 8 | 9 | [Room Previews using Programmable Video Communication](./Room%20Preview%20Demo) 10 | A very simple demonstration of getting and refreshing Room Previews. 11 | 12 | [Layout Positions](./Layout-Positions) 13 | This guide shows how to control positions and layouts in a video room. 14 | 15 | [RTMP Streaming](./RTMP-Streaming) 16 | A simple example of RTMP streaming from a PVC to the RTMP URL of your choice. 17 | 18 | [React Native Basic Component](./React-Native-Basic) 19 | Use components from SignalWire Community to create a simple video calling app with React Native. 20 | 21 | [AppKit Framework Examples](./AppKit-Framework-Examples/) 22 | Examples of AppKit, the library behind Programmable Video Conferences, integrated with popular front-end frameworks. 23 | -------------------------------------------------------------------------------- /Video/RTMP-Streaming/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | 27 | 28 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 29 | 30 | # dependencies 31 | /node_modules 32 | /.pnp 33 | .pnp.js 34 | 35 | # testing 36 | /coverage 37 | 38 | # production 39 | /build 40 | 41 | # misc 42 | .DS_Store 43 | .env 44 | .env.local 45 | .env.development.local 46 | .env.test.local 47 | .env.production.local 48 | 49 | npm-debug.log* 50 | yarn-debug.log* 51 | yarn-error.log* 52 | 53 | 54 | # See http://help.github.com/ignore-files/ for more about ignoring files. 55 | 56 | # Compiled output 57 | /dist 58 | /tmp 59 | /out-tsc 60 | /bazel-out 61 | 62 | # Node 63 | /node_modules 64 | npm-debug.log 65 | yarn-error.log 66 | 67 | # IDEs and editors 68 | .idea/ 69 | .project 70 | .classpath 71 | .c9/ 72 | *.launch 73 | .settings/ 74 | *.sublime-workspace 75 | 76 | # Visual Studio Code 77 | .vscode/* 78 | !.vscode/settings.json 79 | !.vscode/tasks.json 80 | !.vscode/launch.json 81 | !.vscode/extensions.json 82 | .history/* 83 | 84 | # Miscellaneous 85 | /.angular/cache 86 | .sass-cache/ 87 | /connect.lock 88 | /coverage 89 | /libpeerconnection.log 90 | testem.log 91 | /typings 92 | 93 | # System files 94 | .DS_Store 95 | Thumbs.db 96 | -------------------------------------------------------------------------------- /Video/RTMP-Streaming/index.css: -------------------------------------------------------------------------------- 1 | #logo { 2 | max-width: 200px; 3 | } 4 | 5 | #pvc { 6 | margin: 0 auto; 7 | width: 800px; 8 | height: 500px; 9 | display: flex; 10 | flex-direction: column-reverse; 11 | justify-content: flex-end; 12 | } 13 | 14 | #id { 15 | margin: 0 auto; 16 | } 17 | 18 | #note { 19 | color: #8e9292; 20 | } 21 | 22 | h1, 23 | #button-bar { 24 | margin: 5px auto; 25 | font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, 26 | sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; 27 | } 28 | 29 | #button-bar { 30 | display: none; 31 | } 32 | 33 | #streaming { 34 | display: none; 35 | } 36 | 37 | #stream-url { 38 | width: 400px; 39 | } 40 | 41 | #start, 42 | #stop { 43 | color: white; 44 | font-weight: 500; 45 | border: none; 46 | border-radius: 5px; 47 | padding: 8px; 48 | cursor: pointer; 49 | } 50 | 51 | #start { 52 | background-color: #044ef4; 53 | } 54 | #stop { 55 | display: none; 56 | background-color: rgb(211, 96, 96); 57 | } 58 | -------------------------------------------------------------------------------- /Video/RTMP-Streaming/index.js: -------------------------------------------------------------------------------- 1 | let roomSession; 2 | let stream; 3 | 4 | const stopStream = () => { 5 | if (stream) { 6 | stream.stop(); 7 | } 8 | }; 9 | 10 | const setRoomSession = (session) => { 11 | roomSession = session; 12 | 13 | document.getElementById("button-bar").style.display = "block"; 14 | 15 | roomSession.on("room.left", () => { 16 | document.getElementById("button-bar").style.display = "none"; 17 | 18 | stopStream(); 19 | }); 20 | }; 21 | 22 | document.addEventListener("DOMContentLoaded", () => { 23 | document.getElementById("rtmp-form").onsubmit = async (e) => { 24 | e.preventDefault(); 25 | 26 | const url = document.getElementById("stream-url").value; 27 | try { 28 | stream = await roomSession.startStream({ url }); 29 | document.getElementById("streaming").style.display = "block"; 30 | document.getElementById("start").style.display = "none"; 31 | document.getElementById("stop").style.display = "inline"; 32 | } catch (error) { 33 | console.log(error); 34 | alert( 35 | "There was an error starting the stream. Please check your URL and try again." 36 | ); 37 | } 38 | }; 39 | 40 | document.getElementById("stop").onclick = (e) => { 41 | e.preventDefault(); 42 | try { 43 | stopStream(); 44 | document.getElementById("streaming").style.display = "none"; 45 | document.getElementById("start").style.display = "inline"; 46 | document.getElementById("stop").style.display = "none"; 47 | } catch (e) { 48 | console.log(e); 49 | } 50 | }; 51 | }); 52 | -------------------------------------------------------------------------------- /Video/RTMP-Streaming/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rtmp-streaming", 3 | "version": "1.0.0", 4 | "description": "RTMP streaming demo", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "http-server" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "http-server": "^14.1.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Video/RTMP-Streaming/swlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/RTMP-Streaming/swlogo.png -------------------------------------------------------------------------------- /Video/RTMP-Streaming/yt-streaming.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/RTMP-Streaming/yt-streaming.webp -------------------------------------------------------------------------------- /Video/React-Native-Basic/README.md: -------------------------------------------------------------------------------- 1 | # Basic React Native Video Example using Community Components 2 | 3 | This example uses the components from [@signalwire-community/react](https://github.com/signalwire-community/react/) package to demonstrate a few simple features of the SignalWire Video SDK. 4 | 5 | 📖 [Read the full guide](https://developer.signalwire.com/guides/video-api/guides/using-video-api-react-native/) 6 | 7 | ## Usage 8 | 9 | To run the app, you need to have the Android development environment set up. You can find instructions on how to set up the environment [here](https://reactnative.dev/docs/environment-setup). Folow the "React Native CLI Quickstart" instructions. 10 | 11 | In the root of the project directory, run `yarn install` to install the dependencies, then `yarn android` to install and run the app. 12 | 13 | You will need to add a token to the TOKEN constant in `./App.js`. Follow the [guide](https://developer.signalwire.com/guides/video-api/guides/using-video-api-react-native/) for more details. 14 | -------------------------------------------------------------------------------- /Video/React-Native-Basic/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "plugins": ["@config-plugins/react-native-webrtc"], 4 | "android": { 5 | "permissions": [ 6 | "android.permission.ACCESS_NETWORK_STATE", 7 | "android.permission.BLUETOOTH", 8 | "android.permission.CAMERA", 9 | "android.permission.INTERNET", 10 | "android.permission.MODIFY_AUDIO_SETTINGS", 11 | "android.permission.RECORD_AUDIO", 12 | "android.permission.SYSTEM_ALERT_WINDOW", 13 | "android.permission.WAKE_LOCK" 14 | ], 15 | "package": "com.signalwire.basic_tutorial" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Video/React-Native-Basic/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /Video/React-Native-Basic/eas.json: -------------------------------------------------------------------------------- 1 | { 2 | "cli": { 3 | "version": ">= 0.42.4" 4 | }, 5 | "build": { 6 | "development": { 7 | "developmentClient": true, 8 | "distribution": "internal" 9 | }, 10 | "preview": { 11 | "distribution": "internal" 12 | }, 13 | "production": {} 14 | }, 15 | "submit": { 16 | "production": {} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Video/React-Native-Basic/index.js: -------------------------------------------------------------------------------- 1 | import 'expo-dev-client'; 2 | 3 | import { registerRootComponent } from "expo"; 4 | 5 | import App from "./App"; 6 | 7 | // registerRootComponent calls AppRegistry.registerComponent('main', () => App); 8 | // It also ensures that whether you load the app in the Expo client or in a native build, 9 | // the environment is set up appropriately 10 | registerRootComponent(App); 11 | -------------------------------------------------------------------------------- /Video/React-Native-Basic/metro.config.js: -------------------------------------------------------------------------------- 1 | // Learn more https://docs.expo.dev/guides/customizing-metro 2 | const { getDefaultConfig } = require('expo/metro-config'); 3 | 4 | module.exports = getDefaultConfig(__dirname); 5 | -------------------------------------------------------------------------------- /Video/React-Native-Basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "expo start --dev-client", 4 | "android": "expo run:android", 5 | "ios": "expo run:ios", 6 | "web": "expo start --web" 7 | }, 8 | "dependencies": { 9 | "@signalwire-community/react-native": "^0.1.0", 10 | "@signalwire/js": "^3.13.1", 11 | "expo": "^45.0.0", 12 | "expo-dev-client": "~0.9.5", 13 | "expo-splash-screen": "~0.15.1", 14 | "expo-status-bar": "~1.3.0", 15 | "react": "17.0.2", 16 | "react-dom": "17.0.2", 17 | "react-native": "0.68.2", 18 | "react-native-get-random-values": "^1.8.0", 19 | "react-native-web": "0.17.7", 20 | "react-native-webrtc": "^1.94.1" 21 | }, 22 | "devDependencies": { 23 | "@babel/core": "^7.12.9", 24 | "@config-plugins/react-native-webrtc": "^2.0.1" 25 | }, 26 | "name": "basic_tutorial", 27 | "version": "1.0.0", 28 | "private": true 29 | } 30 | -------------------------------------------------------------------------------- /Video/Room Preview Demo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Video/Room Preview Demo/README.md: -------------------------------------------------------------------------------- 1 | # Demo for [Room Previews using Programmable Video Rooms](https://developer.signalwire.com/apis/docs/get-thumbnails-for-your-video-calls) 2 | 3 | This minimal demo uses Programmable Video Rooms and SignalWire Video REST APIs to fetch and preview room previews. 4 | 5 | To run this demo locally, make necessary adjustments ot the env.example file and rename it to `.env`. You can get the `PROJECT_ID` and `API_TOKEN` from your SignalWire Dashboard. 6 | 7 | Once you have made the adjustments, install the dependencies using `yarn install` and then start it via `yarn dev`. 8 | 9 | This sample code is explained in detail in the guide 📖 [Get Thumbnails for your Video Calls](https://developer.signalwire.com/apis/docs/get-thumbnails-for-your-video-calls) 10 | at SignalWire Developer Portal. 11 | -------------------------------------------------------------------------------- /Video/Room Preview Demo/embed.js: -------------------------------------------------------------------------------- 1 | !function(e,r){e.swvr=e.swvr||function(r={}){ 2 | Object.assign(e.swvr.p=e.swvr.p||{},r)} 3 | ;let t=r.currentScript,n=r.createElement("script") 4 | ;n.type="module",n.src="https://cdn.swire.io/video/rooms/index.js", 5 | n.onload=function(){let n=r.createElement("ready-room") 6 | ;n.params=e.swvr.p,t.parentNode.appendChild(n)},t.parentNode.insertBefore(n,t) 7 | ;let i=r.createElement("link") 8 | ;i.type="text/css",i.rel="stylesheet",i.href="https://cdn.swire.io/video/rooms/signalwire.css", 9 | t.parentNode.insertBefore(i,t), 10 | e.SignalWire=e.SignalWire||{},e.SignalWire.Prebuilt={VideoRoom:e.swvr} 11 | }(window,document); 12 | 13 | SignalWire.Prebuilt.VideoRoom({ 14 | token: 'vpt_43a7bb37f75dbbd411821d472b9b8b90', 15 | // userName: 'your-name' 16 | }); 17 | -------------------------------------------------------------------------------- /Video/Room Preview Demo/env.example: -------------------------------------------------------------------------------- 1 | PROJECT_ID=yourProjectId 2 | API_TOKEN=PT... 3 | SPACE_URL={yourSpaceName}.signalwire.com 4 | PORT=3000 -------------------------------------------------------------------------------- /Video/Room Preview Demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Preview 5 | 6 | 10 | 11 | 12 | 13 | 14 |
Generating preview
15 | 16 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Video/Room Preview Demo/index.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const express = require("express"); 3 | const app = express(); 4 | const port = process.env.PORT ?? 3000; 5 | const axios = require("axios"); 6 | 7 | const { PROJECT_ID, API_TOKEN, SPACE_URL } = process.env; 8 | const auth = { username: PROJECT_ID, password: API_TOKEN }; 9 | 10 | app.get("/thumbURL", async (req, res) => { 11 | console.log( 12 | SPACE_URL + "/api/video/room_sessions?page_size=100&status=in-progress" 13 | ); 14 | try { 15 | let roomsessions = await axios.get( 16 | "https://" + 17 | SPACE_URL + 18 | "/api/video/room_sessions?page_size=100&status=in-progress", 19 | { auth } 20 | ); 21 | console.log(roomsessions.data.data); 22 | let thumbroom = roomsessions.data.data.find( 23 | (x) => x.room_id === "3c1e815c-3b3f-4bc5-a200-107ab367a924" 24 | ); 25 | res.json(thumbroom); 26 | } catch (err) { 27 | console.log(err); 28 | res.status(500); 29 | } 30 | }); 31 | 32 | app.use("/", express.static("static")); 33 | 34 | app.listen(port, () => { 35 | console.log(`Example app listening on port ${port}`); 36 | }); 37 | -------------------------------------------------------------------------------- /Video/Room Preview Demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "room_preview_demo", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "start": "node index.js", 6 | "dev": "nodemon index.js" 7 | }, 8 | "main": "index.js", 9 | "dependencies": { 10 | "axios": "^0.26.1", 11 | "dotenv": "^16.0.0", 12 | "express": "^4.17.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Video/Room Preview Demo/static/embed.js: -------------------------------------------------------------------------------- 1 | !(function (e, r) { 2 | e.swvr = 3 | e.swvr || 4 | function (r = {}) { 5 | Object.assign((e.swvr.p = e.swvr.p || {}), r); 6 | }; 7 | let t = r.currentScript, 8 | n = r.createElement("script"); 9 | (n.type = "module"), 10 | (n.src = "https://cdn.signalwire.com/video/rooms/index.js"), 11 | (n.onload = function () { 12 | let n = r.createElement("ready-room"); 13 | (n.params = e.swvr.p), t.parentNode.appendChild(n); 14 | }), 15 | t.parentNode.insertBefore(n, t); 16 | let i = r.createElement("link"); 17 | (i.type = "text/css"), 18 | (i.rel = "stylesheet"), 19 | (i.href = "https://cdn.signalwire.com/video/rooms/signalwire.css"), 20 | t.parentNode.insertBefore(i, t), 21 | (e.SignalWire = e.SignalWire || {}), 22 | (e.SignalWire.Prebuilt = { VideoRoom: e.swvr }); 23 | })(window, document); 24 | 25 | SignalWire.Prebuilt.VideoRoom({ 26 | token: "vpt_cc56fea7323b3016b9b2db95e104fb38", 27 | // userName: 'your-name' 28 | }); 29 | -------------------------------------------------------------------------------- /Video/Room Preview Demo/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Preview 5 | 6 | 21 | 22 | 23 | 24 | 25 |
Generating preview
26 | 27 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Video/Simple Video Demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | WORKDIR /app 4 | 5 | # Install app dependencies 6 | COPY package*.json ./ 7 | RUN npm install 8 | 9 | # Bundle app source 10 | COPY src/index.js ./src/index.js 11 | COPY src/frontend ./src/frontend 12 | 13 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Video/Simple Video Demo/env.example: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_PROJECT_ID=YOUR_PROJECT_ID 2 | SIGNALWIRE_API_TOKEN=YOUR_AUTH_TOKEN 3 | SIGNALWIRE_SPACE_URL=YOUR_SPACE.signalwire.com 4 | 5 | KEY_FILE_PATH=/root/certs/privkey.pem 6 | CERT_FILE_PATH=/root/certs/fullchain.pem -------------------------------------------------------------------------------- /Video/Simple Video Demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-video-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "start": "nodemon src/index.js" 8 | }, 9 | "dependencies": { 10 | "axios": "0.26.0", 11 | "body-parser": "1.19.0", 12 | "cors": "2.8.5", 13 | "dotenv": "^16.0.1", 14 | "express": "4.17.1", 15 | "https": "^1.0.0", 16 | "log-timestamp": "^0.3.0" 17 | }, 18 | "devDependencies": { 19 | "nodemon": "1.18.4" 20 | }, 21 | "keywords": [] 22 | } -------------------------------------------------------------------------------- /Video/Simple Video Demo/src/frontend/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Montserrat; 3 | } 4 | 5 | input { 6 | width: 200px; 7 | } 8 | 9 | /* Hide all divs at start 10 | We'll use javascript to selectively display divs. */ 11 | body>div.dynamic { 12 | display: none; 13 | } 14 | 15 | #root { 16 | /* width: 400px; */ 17 | width: 90%; 18 | } 19 | 20 | #logo { 21 | width: 130px; 22 | margin-left: 10px; 23 | } 24 | 25 | #events { 26 | /* width: 100px; */ 27 | height: 300px; 28 | border-left: dotted 2px gray; 29 | padding-left: 10px; 30 | } 31 | 32 | .body { 33 | display: grid; 34 | grid-template-columns: 70% 30%; 35 | margin-top: 20px; 36 | } 37 | 38 | .content { 39 | min-height: 300px; 40 | } 41 | 42 | .header { 43 | display: grid; 44 | grid-template-columns: 100px 1fr; 45 | gap: 0 50px; 46 | padding-top: 15px; 47 | } 48 | 49 | .content { 50 | display: flex; 51 | justify-content: center; 52 | align-items: center; 53 | } 54 | 55 | .header>div { 56 | display: flex; 57 | /* justify-content: center; */ 58 | align-items: center; 59 | margin-left: 20px; 60 | } 61 | 62 | #instant_invite { 63 | font-size: 12px; 64 | font-family: monospace; 65 | } -------------------------------------------------------------------------------- /Video/Simple Video Demo/src/frontend/swlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Video/Simple Video Demo/src/frontend/swlogo.png -------------------------------------------------------------------------------- /Voice/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/.DS_Store -------------------------------------------------------------------------------- /Voice/AI Agent with NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | WORKDIR /app 4 | 5 | # Install app dependencies 6 | COPY package*.json ./ 7 | RUN npm install 8 | 9 | # Bundle app source 10 | COPY index.js . 11 | 12 | EXPOSE 3000 13 | 14 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Voice/AI Agent with NodeJS/env.example: -------------------------------------------------------------------------------- 1 | # Project ID copied from the API Credentials in your SignalWire Space 2 | # Example: 7b98XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 3 | PROJECT_ID= 4 | 5 | # API token copied from the API Credentials in your SignalWire Space 6 | # Example: PTda745XXXXXXXXXXXXXXXXXXXXXXXXXXXXX 7 | API_TOKEN= 8 | 9 | # Your SignalWire Space URL copied from the API Credentials in your SignalWire Space 10 | # Example: spacename.signalwire.com 11 | SPACE_URL= 12 | 13 | # The URL of your deployed application, including the protocol extension 14 | # Example: https://example.ngrok.app 15 | HOST_APP= 16 | 17 | # 10-digit phone number for a sales department in the following format: 18 | # Example: 222-555-0110 19 | SALES_NUMBER= 20 | 21 | # 10-digit phone number for a support department in the following format: 22 | # Example: 222-555-0110 23 | SUPPORT_NUMBER= -------------------------------------------------------------------------------- /Voice/AI Agent with NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "virtual-agent---nodejs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "start": "node index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@signalwire/compatibility-api": "^3.1.0", 15 | "dotenv": "^16.0.3", 16 | "express": "^4.18.2", 17 | "node-fetch": "^3.3.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Voice/Answering Machine Detection with NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | WORKDIR /app 4 | 5 | # Install app dependencies 6 | COPY package*.json ./ 7 | RUN npm install 8 | 9 | # Bundle app source 10 | COPY index.js . 11 | 12 | EXPOSE 3000 13 | 14 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Voice/Answering Machine Detection with NodeJS/env.example: -------------------------------------------------------------------------------- 1 | # Project ID copied from the API Credentials in your SignalWire Space. 2 | # Example: 7b98XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 3 | PROJECT_ID= 4 | 5 | # API token copied from the API Credentials in your SignalWire Space. 6 | # Example: PTda745XXXXXXXXXXXXXXXXXXXXXXXXXXXXX 7 | API_TOKEN= 8 | 9 | # Your SignalWire Space URL copied from the API Credentials in your SignalWire Space. 10 | # Example: spacename.signalwire.com 11 | SPACE_URL= 12 | 13 | # The URL you would like to receive the AMD result. 14 | # Example: https://example.ngrok.app 15 | SERVER_URL= 16 | 17 | # A phone number from your SignalWire account for caller ID in E.164 format. 18 | # Example: +1XXXXXXXXXXX 19 | SW_NUMBER= 20 | 21 | # The test phone number to dial in E.164 format. 22 | # Example: +1XXXXXXXXXXX 23 | CUSTOMER_NUMBER= 24 | 25 | # A live agent's phone number in E.164 format. 26 | # Example: +1XXXXXXXXXXX 27 | AGENT_NUMBER= -------------------------------------------------------------------------------- /Voice/Answering Machine Detection with NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "answering-machine-detection-with-nodejs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@signalwire/compatibility-api": "^3.0.4", 15 | "dotenv": "^16.0.3", 16 | "express": "^4.18.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Voice/Answering Machine Detection with Ruby/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.7 2 | 3 | RUN bundle config --global frozen 1 4 | 5 | WORKDIR /app 6 | 7 | COPY Gemfile Gemfile.lock ./ 8 | RUN bundle install 9 | 10 | COPY app.rb . 11 | 12 | EXPOSE 8080 13 | 14 | CMD ["bundle", "exec", "ruby", "app.rb"] -------------------------------------------------------------------------------- /Voice/Answering Machine Detection with Ruby/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | gem "signalwire" 5 | gem "sinatra" 6 | gem "thin" -------------------------------------------------------------------------------- /Voice/Answering Machine Detection with Ruby/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | concurrent-ruby (1.1.8) 5 | daemons (1.3.1) 6 | eventmachine (1.2.7) 7 | faraday (1.3.0) 8 | faraday-net_http (~> 1.0) 9 | multipart-post (>= 1.2, < 3) 10 | ruby2_keywords 11 | faraday-net_http (1.0.1) 12 | faye-websocket (0.11.0) 13 | eventmachine (>= 0.12.0) 14 | websocket-driver (>= 0.5.1) 15 | has-guarded-handlers (1.6.3) 16 | jwt (2.2.2) 17 | logger (1.4.3) 18 | mini_portile2 (2.5.0) 19 | multipart-post (2.1.1) 20 | mustermann (1.1.1) 21 | ruby2_keywords (~> 0.0.1) 22 | nokogiri (1.11.2) 23 | mini_portile2 (~> 2.5.0) 24 | racc (~> 1.4) 25 | racc (1.5.2) 26 | rack (2.2.3) 27 | rack-protection (2.1.0) 28 | rack 29 | ruby2_keywords (0.0.4) 30 | signalwire (2.3.4) 31 | concurrent-ruby (~> 1.1) 32 | faye-websocket (~> 0.10) 33 | has-guarded-handlers (~> 1.6.3) 34 | logger (~> 1.3) 35 | twilio-ruby (~> 5.0) 36 | sinatra (2.1.0) 37 | mustermann (~> 1.0) 38 | rack (~> 2.2) 39 | rack-protection (= 2.1.0) 40 | tilt (~> 2.0) 41 | thin (1.8.0) 42 | daemons (~> 1.0, >= 1.0.9) 43 | eventmachine (~> 1.0, >= 1.0.4) 44 | rack (>= 1, < 3) 45 | tilt (2.0.10) 46 | twilio-ruby (5.48.0) 47 | faraday (>= 0.9, < 2.0) 48 | jwt (>= 1.5, <= 2.5) 49 | nokogiri (>= 1.6, < 2.0) 50 | websocket-driver (0.7.3) 51 | websocket-extensions (>= 0.1.0) 52 | websocket-extensions (0.1.5) 53 | 54 | PLATFORMS 55 | ruby 56 | 57 | DEPENDENCIES 58 | signalwire 59 | sinatra 60 | thin 61 | 62 | BUNDLED WITH 63 | 2.1.4 -------------------------------------------------------------------------------- /Voice/Answering Machine Detection with Ruby/app.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'sinatra' 3 | require 'signalwire' 4 | 5 | set :port, 8080 6 | set :bind, '0.0.0.0' 7 | 8 | get '/' do 9 | "It's working!" 10 | end 11 | 12 | post '/start' do 13 | response = Signalwire::Sdk::VoiceResponse.new 14 | 15 | case params[:AnsweredBy] 16 | when 'machine_end_other', 'machine_end_silence', 'machine_end_beep' 17 | puts "It's a machine!" 18 | # put in a little pause to allow the recording to start on the other end 19 | response.pause(length: 1) 20 | # replace messsage with whatever voicemail you want to leave 21 | response.say(message: "Hello! This is the County Medical Center. We are calling you to confirm your doctor appointment. Please call us back as soon as possible.") 22 | response.hangup 23 | when 'human' 24 | puts "We got ourselves a live human here!" 25 | response.dial do |dial| 26 | # defaulting to calling a time voice announcement number as an example 27 | dial.number(ENV.fetch('AGENT_NUMBER', '+12027621401')) 28 | end 29 | end 30 | 31 | # debug the LAML 32 | puts response.to_s 33 | response.to_s 34 | end 35 | -------------------------------------------------------------------------------- /Voice/Answering Machine Detection with Ruby/example.env: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_PROJECT_KEY=YOURKEY 2 | SIGNALWIRE_TOKEN=YOURTOKEN 3 | SIGNALWIRE_SPACE=YOURSPACENAME.signalwire.com 4 | FROM_NUMBER=+1555xxxxxxx 5 | AGENT_NUMBER=+1202xxxxxxx 6 | APP_DOMAIN=https://YOURTUNNEL.ngrok.io -------------------------------------------------------------------------------- /Voice/Appointment Reminder using NodeJS and Relay V3/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | -------------------------------------------------------------------------------- /Voice/Appointment Reminder using NodeJS and Relay V3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | RUN mkdir -p /usr/src/app 4 | 5 | WORKDIR /usr/src/app 6 | 7 | COPY . . 8 | 9 | RUN npm install 10 | 11 | RUN npm run build 12 | 13 | EXPOSE 8080 14 | 15 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /Voice/Appointment Reminder using NodeJS and Relay V3/env.example: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_PROJECT_ID=your-project 2 | SIGNALWIRE_TOKEN=your-token 3 | 4 | CALLER_ID=a-number-from-your-sw-account 5 | AGENT_NUMBER=any-phone-number 6 | DEFAULT_DESTINATION==any-phone-number 7 | REPORTING_URL=http://localhost:8080 -------------------------------------------------------------------------------- /Voice/Appointment Reminder using NodeJS and Relay V3/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const express = require('express'); 3 | let { Task } = require('@signalwire/realtime-api') 4 | 5 | const PORT = process.env.PORT || 8080 6 | const app = express(); 7 | const http = require('http').createServer(app); 8 | 9 | app.use(express.json()); 10 | app.set('view engine', 'ejs'); 11 | 12 | let {createSession, createChannel} = require("better-sse"); 13 | const channel = createChannel(); 14 | 15 | app.get("/", async (req, res, next) => { 16 | res.render('index', { destination: process.env.DEFAULT_DESTINATION }) 17 | }) 18 | 19 | app.post("/notify", async (req, res, next) => { 20 | channel.broadcast(req.body.message); 21 | res.json({ status: 'ok' }); 22 | }) 23 | 24 | app.post("/send", async (req, res, next) => { 25 | console.log(req.body); 26 | await Task.send({ 27 | project: process.env.SIGNALWIRE_PROJECT_ID, 28 | token: process.env.SIGNALWIRE_TOKEN, 29 | context: 'office', 30 | message: { 31 | number: req.body.number, 32 | message: req.body.message, 33 | } 34 | }) 35 | 36 | res.json({ status: 'ok' }); 37 | }); 38 | 39 | app.get("/sse", async (req, res) => { 40 | const session = await createSession(req, res); 41 | channel.register(session); 42 | }); 43 | 44 | http.listen(PORT, '0.0.0.0', () => { 45 | console.log(`Listening to ${PORT}`); 46 | }); -------------------------------------------------------------------------------- /Voice/Appointment Reminder using NodeJS and Relay V3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "signalwire-v3-dialer", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js & node consumer.js", 8 | "consumer": "node consumer.js", 9 | "server": "node index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@signalwire/realtime-api": "^3.0.1", 15 | "axios": "^0.27.2", 16 | "better-sse": "^0.8.0", 17 | "dotenv": "^16.0.1", 18 | "ejs": "^3.1.8", 19 | "express": "^4.18.1" 20 | }, 21 | "keywords": [] 22 | } 23 | -------------------------------------------------------------------------------- /Voice/Build a Dynamic IVR with JSON Menus - Python/menus.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": { 3 | "1": { 4 | "verbiage": "If you'd like to connect to our Sales team, press 1", 5 | "action": "/get_menu?menu=sales" 6 | }, 7 | "2": { 8 | "verbiage": "If you'd like to connect to our Support Engineering Team, press 2", 9 | "action": "/get_menu?menu=tech" 10 | } 11 | }, 12 | "sales": { 13 | "1": { 14 | "verbiage": "If you are already a customer and would like to connect to your Account Executive, press 1", 15 | "action": "/get_menu?menu=salesteam" 16 | }, 17 | "2": { 18 | "verbiage": "For assistance with a purchase or all other sales inquiries, press 2", 19 | "action": "/dial_sales?name=general&group=sales_support" 20 | } 21 | }, 22 | "tech": { 23 | "1": { 24 | "verbiage": "If you are having a problem with SignalWire Work, press 1", 25 | "action": "/dial_support?group=work_support" 26 | }, 27 | "2": { 28 | "verbiage": "If you are having a problem with SignalWire Cloud, press 2", 29 | "action": "/dial_support?group=cloud_support" 30 | }, 31 | "3": { 32 | "verbiage": "If you are having a problem with SignalWire Stack, press 3", 33 | "action": "/dial_support?group=stack_support" 34 | } 35 | }, 36 | "salesteam": { 37 | "1": { 38 | "verbiage": "If you would like to speak to Bob, press 1", 39 | "action": "/dial_sales?name=bob&group=sale_partners" 40 | }, 41 | "2": { 42 | "verbiage": "If you would like to speak to Alice, press 2", 43 | "action": "/dial_sales?name=alice&group=sale_partners" 44 | }, 45 | "3": { 46 | "verbiage": "If you would like to speak to Charlie, press 3", 47 | "action": "/dial_sales?name=charlie&group=sale_partners" 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Voice/Call Center with Dynamic JSON Menus and Python/python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | ADD app.py / 4 | ADD config.json / 5 | 6 | RUN pip install flask 7 | RUN pip install signalwire 8 | 9 | EXPOSE 5000 10 | 11 | CMD [ "python", "./app.py" ] 12 | -------------------------------------------------------------------------------- /Voice/Dial By Voice Python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | ADD app.py / 4 | 5 | RUN pip install flask 6 | RUN pip install signalwire 7 | 8 | EXPOSE 5000 9 | 10 | CMD [ "python", "./app.py" ] 11 | -------------------------------------------------------------------------------- /Voice/Dial By Voice Python/Image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Dial By Voice Python/Image1.png -------------------------------------------------------------------------------- /Voice/Dial By Voice Python/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 SignalWire 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do 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 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | RUN mkdir -p /usr/src/app 4 | 5 | WORKDIR /usr/src/app 6 | 7 | COPY . . 8 | 9 | RUN npm install 10 | 11 | RUN npm run build 12 | 13 | EXPOSE 5000 14 | 15 | CMD ["node", "server.js"] 16 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/coach-screen-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/coach-screen-snap.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/example.env: -------------------------------------------------------------------------------- 1 | ## This is the full name of your SignalWire Space. e.g.: example.signalwire.com 2 | SIGNALWIRE_SPACE= 3 | # Your Project ID - you can find it on the `API` page in your Dashboard. 4 | SIGNALWIRE_PROJECT= 5 | # Your API token - you can generate one on the `API` page in your Dashboard 6 | SIGNALWIRE_TOKEN= 7 | # The name of your example conference 8 | CONFERENCE_NAME= 9 | # The inbound phone number you'll be using for this Snippets. Must include the `+1` , e$ 10 | INBOUND_NUMBER= 11 | # The agent phone number you'll be using for this Snippets. Must include the `+1` , e$ 12 | AGENT_NUMBER= 13 | # The supervisor phone number you'll be using for this Snippets. Must include the `+1` , e$ 14 | SUPERVISOR_NUMBER= 15 | # Hostname, the ip address or Fully Qualified Domain Name of your host and port, for routing action urls 16 | HOSTNAME= 17 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/public/favicon.ico -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/public/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 23 | Coach 24 | 25 | 26 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Elk31", 3 | "name": "Elk31", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { Route } from 'react-router'; 4 | import { Layout } from './components/Layout'; 5 | import { Dashboard } from './components/Dashboard'; 6 | 7 | import './custom.css' 8 | 9 | export default class App extends Component { 10 | static displayName = App.name; 11 | 12 | render() { 13 | return ( 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { MemoryRouter } from 'react-router-dom'; 4 | import App from './App'; 5 | 6 | it('renders without crashing', async () => { 7 | const div = document.createElement('div'); 8 | ReactDOM.render( 9 | 10 | 11 | , div); 12 | await new Promise(resolve => setTimeout(resolve, 1000)); 13 | }); 14 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/Dashboard.css: -------------------------------------------------------------------------------- 1 | @keyframes spin { 2 | from { 3 | transform: rotate(0deg); 4 | } 5 | 6 | to { 7 | transform: rotate(360deg); 8 | } 9 | } 10 | .center { 11 | width: 200px; 12 | height: 200px; 13 | position: absolute; 14 | left: 50%; 15 | top: 75%; 16 | margin-left: -200px; 17 | margin-top: -200px; 18 | } 19 | 20 | .my-modal { 21 | width: calc(100vw - 100px); 22 | max-width: 90%; 23 | } 24 | 25 | .modal-card { 26 | width: 90%; 27 | } 28 | 29 | .modal-content { 30 | width: 90%; 31 | } -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/FetchData.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export class FetchData extends Component { 4 | static displayName = FetchData.name; 5 | 6 | constructor(props) { 7 | super(props); 8 | this.state = { forecasts: [], loading: true }; 9 | } 10 | 11 | componentDidMount() { 12 | this.populateWeatherData(); 13 | } 14 | 15 | static renderForecastsTable(forecasts) { 16 | return ( 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {forecasts.map(forecast => 28 | 29 | 30 | 31 | 32 | 33 | 34 | )} 35 | 36 |
DateTemp. (C)Temp. (F)Summary
{forecast.date}{forecast.temperatureC}{forecast.temperatureF}{forecast.summary}
37 | ); 38 | } 39 | 40 | render() { 41 | let contents = this.state.loading 42 | ?

Loading...

43 | : FetchData.renderForecastsTable(this.state.forecasts); 44 | 45 | return ( 46 |
47 |

Weather forecast

48 |

This component demonstrates fetching data from the server.

49 | {contents} 50 |
51 | ); 52 | } 53 | 54 | async populateWeatherData() { 55 | const response = await fetch('weatherforecast'); 56 | const data = await response.json(); 57 | this.setState({ forecasts: data, loading: false }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Container } from 'reactstrap'; 3 | import { NavMenu } from './NavMenu'; 4 | 5 | export class Layout extends Component { 6 | static displayName = Layout.name; 7 | 8 | render () { 9 | return ( 10 |
11 | 12 | 13 | {this.props.children} 14 | 15 |
16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/NavMenu.css: -------------------------------------------------------------------------------- 1 | a.navbar-brand { 2 | white-space: normal; 3 | text-align: center; 4 | word-break: break-all; 5 | } 6 | 7 | html { 8 | font-size: 14px; 9 | } 10 | @media (min-width: 768px) { 11 | html { 12 | font-size: 16px; 13 | } 14 | } 15 | 16 | .box-shadow { 17 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 18 | } 19 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/custom.css: -------------------------------------------------------------------------------- 1 | /* Provide sufficient contrast against white background */ 2 | a { 3 | color: #0366d6; 4 | } 5 | 6 | code { 7 | color: #E01A76; 8 | } 9 | 10 | .btn-primary { 11 | color: #fff; 12 | background-color: #1b6ec2; 13 | border-color: #1861ac; 14 | } 15 | 16 | .my-modal { 17 | width: 75%; /* Occupy the 90% of the screen width */ 18 | max-width: 75%; 19 | } 20 | 21 | .modal-card .modal-content { 22 | width: calc(100vw - 100px); 23 | } 24 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/delete-6x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/delete-6x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-pause-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-pause-2x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-pause-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-pause-3x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-pause-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-pause-4x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-pause-6x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-pause-6x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-play-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-play-2x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-play-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-play-3x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-play-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-play-4x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-play-6x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-play-6x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-record-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-record-2x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-record-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-record-3x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-record-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-record-4x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-record-6x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-record-6x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-stop-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-stop-2x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-stop-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-stop-3x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-stop-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-stop-4x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/media-stop-6x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/media-stop-6x.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/spinner.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/components/spinner2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Implement Coaching and Recording with NodeJS/src/components/spinner2.png -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/custom.css: -------------------------------------------------------------------------------- 1 | /* Provide sufficient contrast against white background */ 2 | a { 3 | color: #0366d6; 4 | } 5 | 6 | code { 7 | color: #E01A76; 8 | } 9 | 10 | .btn-primary { 11 | color: #fff; 12 | background-color: #1b6ec2; 13 | border-color: #1861ac; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/index.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/css/bootstrap.css'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import { BrowserRouter } from 'react-router-dom'; 5 | import App from './App'; 6 | import registerServiceWorker from './registerServiceWorker'; 7 | 8 | const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href'); 9 | const rootElement = document.getElementById('root'); 10 | 11 | ReactDOM.render( 12 | 13 | 14 | , 15 | rootElement); 16 | 17 | registerServiceWorker(); 18 | 19 | -------------------------------------------------------------------------------- /Voice/Implement Coaching and Recording with NodeJS/src/utils/appHelpers.js: -------------------------------------------------------------------------------- 1 | // create a Showdown instance to parse issue/pr body content 2 | const showdown = require('showdown') 3 | 4 | // Showdown parameters to jive well with Github flavored markdown 5 | export const converter = new showdown.Converter({ 6 | tables: true, 7 | strikethrough: true, 8 | ghCompatibleHeaderId: true, 9 | literalMidWordUnderscores: true, 10 | ghCodeBlocks: true, 11 | tasklists: true, 12 | ghMentions: true, 13 | ghMentionsLink: 'https://github.com/{u}' 14 | }) 15 | 16 | // helper function to properly encode query string for fetch 17 | export const encodeQueryString = (params) => { 18 | const keys = Object.keys(params) 19 | return keys.length ? 20 | "?" + keys 21 | .map(key => encodeURIComponent(key) + 22 | "=" + encodeURIComponent(params[key])) 23 | .join("&") : 24 | "" 25 | } 26 | 27 | // helper function to parse Link headers in to an object for use with pagniation 28 | export const parseLinkHeader = (header) => { 29 | if (header.length === 0) { 30 | throw new Error("input must not be of zero length"); 31 | } 32 | 33 | // Split parts by comma and parse each part into a named link 34 | return header.split(/(?!\B"[^"]*),(?![^"]*"\B)/).reduce((links, part) => { 35 | const section = part.split(/(?!\B"[^"]*);(?![^"]*"\B)/); 36 | if (section.length < 2) { 37 | throw new Error("section could not be split on ';'"); 38 | } 39 | const url = section[0].replace(/<(.*)>/, '$1').trim(); 40 | const name = section[1].replace(/rel="(.*)"/, '$1').trim(); 41 | 42 | links[name] = url; 43 | 44 | return links; 45 | }, {}); 46 | } -------------------------------------------------------------------------------- /Voice/Implement two-factor with Python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | ADD app.py / 4 | 5 | RUN pip install flask 6 | RUN pip install signalwire 7 | 8 | EXPOSE 5000 9 | 10 | CMD [ "python", "./app.py" ] 11 | -------------------------------------------------------------------------------- /Voice/Implement two-factor with Python/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 SIGNALWIRE, INC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Voice/Implement two-factor with Python/example.env: -------------------------------------------------------------------------------- 1 | ## This is the full name of your SignalWire Space. e.g.: example.signalwire.com 2 | SIGNALWIRE_SPACE= 3 | # Your Project ID - you can find it on the `API` page in your Dashboard. 4 | SIGNALWIRE_PROJECT= 5 | # Your API token - you can generate one on the `API` page in your Dashboard 6 | SIGNALWIRE_TOKEN= 7 | # The phone number you'll be using for this Snippets. Must include the `+1` , e$ 8 | SIGNALWIRE_NUMBER= 9 | # Hostname 10 | HOSTNAME= 11 | -------------------------------------------------------------------------------- /Voice/Lenny Spam Filter Relay v4/.env.example: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_PROJECT_ID=... 2 | SIGNALWIRE_API_TOKEN=PT... 3 | SIGNALWIRE_CONTEXT=captcha 4 | MY_NUMBER=+... -------------------------------------------------------------------------------- /Voice/Lenny Spam Filter Relay v4/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .node-persist 3 | .node-persist/* 4 | .env -------------------------------------------------------------------------------- /Voice/Lenny Spam Filter Relay v4/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | WORKDIR /app 4 | 5 | # Install app dependencies 6 | COPY package*.json ./ 7 | RUN npm install 8 | 9 | # Bundle app source 10 | COPY src . 11 | 12 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Voice/Lenny Spam Filter Relay v4/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 SignalWire 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do 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 | -------------------------------------------------------------------------------- /Voice/Lenny Spam Filter Relay v4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "livewire-audio-captcha", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "start": "nodemon ./src/index.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@signalwire/realtime-api": "^4.0.0", 15 | "dotenv": "^10.0.0", 16 | "node-persist": "^3.1.0", 17 | "nodemon": "^2.0.15" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Voice/Lenny Spam Filter Relay v4/run_docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker build -t nodelenny . 4 | docker run -it --rm -v `pwd`/.node-persist:/app/.node-persist --name nodelenny --env-file .env nodelenny -------------------------------------------------------------------------------- /Voice/Lenny Spam Filter Relay v4/src/lenny.js: -------------------------------------------------------------------------------- 1 | import { Voice } from "@signalwire/realtime-api"; 2 | const lennyConfig = { 3 | soundBase: 4 | "https://s3.us-east-2.amazonaws.com/files.signalwire.com/173aba80-58fc-415d-b6ed-df6e357e766f/d1a906e8-f5e5-4939-8c07-31105b56ec41/Files/Lenny", 5 | background: "backgroundnoise.mp3", 6 | responses: [ 7 | "Lenny1.mp3", 8 | "Lenny2.mp3", 9 | "Lenny3.mp3", 10 | "Lenny4.mp3", 11 | "Lenny5.mp3", 12 | "Lenny6.mp3", 13 | "Lenny7.mp3", 14 | "Lenny8.mp3", 15 | "Lenny9.mp3", 16 | "Lenny10.mp3", 17 | "Lenny11.mp3", 18 | "Lenny12.mp3", 19 | "Lenny13.mp3", 20 | "Lenny14.mp3", 21 | "Lenny15.mp3", 22 | "Lenny16.mp3", 23 | ], 24 | }; 25 | 26 | /** 27 | * Given a call object, connect the caller to Lenny and his ducks. 28 | * 29 | * @param {*} call 30 | * @returns asynchronously returns `void` when the call ends. 31 | */ 32 | export async function lenny(call) { 33 | let i = 0; 34 | 35 | while (call.active) { 36 | await promptLenny(call, i); 37 | i += 1; 38 | 39 | if (i >= lennyConfig.responses.length) { 40 | i = 4; 41 | } 42 | } 43 | } 44 | 45 | async function promptLenny(call, responseId) { 46 | console.log("Prompting with: ", lennyConfig.responses[responseId]); 47 | 48 | await call 49 | .playAudio({ 50 | url: lennyConfig.soundBase + "/" + lennyConfig.responses[responseId], 51 | volume: +20, 52 | }) 53 | .onEnded(); 54 | 55 | return await call.prompt({ 56 | speech: { endSilenceTimeout: 1.0 }, 57 | playlist: new Voice.Playlist().add( 58 | Voice.Playlist.Audio({ 59 | url: lennyConfig.soundBase + "/" + lennyConfig.background, 60 | }) 61 | ), 62 | }); 63 | } 64 | -------------------------------------------------------------------------------- /Voice/Make Appointment Reminder Calls with Ruby/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.7 2 | 3 | WORKDIR /app 4 | COPY . /app 5 | RUN bundle install 6 | 7 | CMD ["bundle", "exec", "ruby", "app.rb", "-o", "0.0.0.0"] -------------------------------------------------------------------------------- /Voice/Make Appointment Reminder Calls with Ruby/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "signalwire" 4 | gem "sinatra" 5 | gem "sinatra-contrib" 6 | gem "dotenv" -------------------------------------------------------------------------------- /Voice/Make Appointment Reminder Calls with Ruby/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | concurrent-ruby (1.1.8) 5 | dotenv (2.7.6) 6 | eventmachine (1.2.7) 7 | faraday (1.4.1) 8 | faraday-excon (~> 1.1) 9 | faraday-net_http (~> 1.0) 10 | faraday-net_http_persistent (~> 1.1) 11 | multipart-post (>= 1.2, < 3) 12 | ruby2_keywords (>= 0.0.4) 13 | faraday-excon (1.1.0) 14 | faraday-net_http (1.0.1) 15 | faraday-net_http_persistent (1.1.0) 16 | faye-websocket (0.11.0) 17 | eventmachine (>= 0.12.0) 18 | websocket-driver (>= 0.5.1) 19 | has-guarded-handlers (1.6.3) 20 | jwt (2.2.3) 21 | logger (1.4.3) 22 | multipart-post (2.1.1) 23 | nokogiri (1.11.3-x86_64-darwin) 24 | racc (~> 1.4) 25 | racc (1.5.2) 26 | ruby2_keywords (0.0.4) 27 | signalwire (2.3.4) 28 | concurrent-ruby (~> 1.1) 29 | faye-websocket (~> 0.10) 30 | has-guarded-handlers (~> 1.6.3) 31 | logger (~> 1.3) 32 | twilio-ruby (~> 5.0) 33 | twilio-ruby (5.52.0) 34 | faraday (>= 0.9, < 2.0) 35 | jwt (>= 1.5, <= 2.5) 36 | nokogiri (>= 1.6, < 2.0) 37 | websocket-driver (0.7.3) 38 | websocket-extensions (>= 0.1.0) 39 | websocket-extensions (0.1.5) 40 | 41 | PLATFORMS 42 | x86_64-darwin-20 43 | 44 | DEPENDENCIES 45 | dotenv 46 | signalwire 47 | 48 | BUNDLED WITH 49 | 2.2.15 -------------------------------------------------------------------------------- /Voice/Make Appointment Reminder Calls with Ruby/config.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "reminders": [{ 4 | "name": "Mr. Smith", 5 | "to": "+15554567890", 6 | "date": "05/10/2021", 7 | "time": "10:00AM" 8 | }], 9 | 10 | "available" : [{ 11 | "date": "05/10/2021", 12 | "time": "11:15AM" 13 | }, 14 | { 15 | "date": "06/10/2021", 16 | "time": "2:30PM" 17 | }] 18 | } -------------------------------------------------------------------------------- /Voice/Make Appointment Reminder Calls with Ruby/example.env: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_PROJECT_KEY= 2 | SIGNALWIRE_TOKEN= 3 | SIGNALWIRE_SPACE= 4 | FROM_NUMBER= 5 | TO_NUMBER= 6 | APP_DOMAIN= -------------------------------------------------------------------------------- /Voice/Make Appointment Reminder Calls with Ruby/views/index.erb: -------------------------------------------------------------------------------- 1 | <%- @reminders.each do |rm| %> 2 | <%= rm['to'] %> 3 |
4 |
5 |
<%= rm['name'] %>
6 |
7 |
8 |
Number:
9 |
<%= rm['to'] %>
10 |
Date:
11 |
<%= rm['date'] %>
12 |
Time:
13 |
<%= rm['time'] %>
14 |
15 |
16 | Confirm 17 |
18 |
19 | <% end %> -------------------------------------------------------------------------------- /Voice/Make Appointment Reminder Calls with Ruby/views/layout.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | SignalWire Reminders 4 | 5 | 6 | 7 | 12 |
13 | <%= yield %> 14 |
15 | 16 | -------------------------------------------------------------------------------- /Voice/Multi-Factor Authentication in Ruby/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.7 2 | 3 | WORKDIR /app 4 | COPY . /app 5 | RUN bundle install 6 | 7 | CMD ["bundle", "exec", "ruby", "app.rb", "-o", "0.0.0.0"] -------------------------------------------------------------------------------- /Voice/Multi-Factor Authentication in Ruby/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "sinatra" 4 | gem "sinatra-contrib" 5 | gem "thin" 6 | gem "signalwire" 7 | gem "dotenv" -------------------------------------------------------------------------------- /Voice/Multi-Factor Authentication in Ruby/app.rb: -------------------------------------------------------------------------------- 1 | require 'dotenv/load' 2 | require 'signalwire/sdk' 3 | require 'sinatra' 4 | require 'net/http' 5 | require 'uri' 6 | require 'json' 7 | require "sinatra/reloader" if development? 8 | 9 | def make_request(action, payload) 10 | uri = URI.parse("https://#{ENV['SIGNALWIRE_SPACE']}/api/relay/rest/mfa#{action}") 11 | 12 | request = Net::HTTP::Post.new(uri) 13 | request.basic_auth(ENV['SIGNALWIRE_PROJECT_KEY'], ENV['SIGNALWIRE_TOKEN']) 14 | request.set_form_data(payload) 15 | 16 | response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https", verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| 17 | http.request(request) 18 | end 19 | 20 | if response.code.to_i < 400 21 | return JSON.parse(response.body) 22 | else 23 | return { "success" => false } 24 | end 25 | end 26 | 27 | get '/' do 28 | erb :index 29 | end 30 | 31 | post '/' do 32 | if params[:phone] 33 | # request the token 34 | payload = { 35 | "to" => params[:phone] 36 | } 37 | result = make_request("/#{params[:mode]}", payload) 38 | @verify = result["id"] 39 | elsif params[:verify] 40 | payload = { 41 | "token" => params[:code] 42 | } 43 | result = make_request("/#{params[:verify]}/verify", payload) 44 | 45 | @success = result["success"] 46 | @verify = params[:verify] 47 | end 48 | 49 | erb :index 50 | end -------------------------------------------------------------------------------- /Voice/Multi-Factor Authentication in Ruby/env.example: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_PROJECT_KEY=yourproject 2 | SIGNALWIRE_TOKEN=yourtoken 3 | SIGNALWIRE_SPACE=YOURSPACE.signalwire.com -------------------------------------------------------------------------------- /Voice/Multi-Factor Authentication in Ruby/views/layout.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | SignalWire MFA Demo 4 | 5 | 6 | 7 | 12 |
13 | <%= yield %> 14 |
15 | 16 | -------------------------------------------------------------------------------- /Voice/Phone Survey With Python/Image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/Phone Survey With Python/Image1.png -------------------------------------------------------------------------------- /Voice/Phone Survey With Python/config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "type": "service_account", 3 | "project_id": "YOUR-PROJECT-ID", 4 | "private_key_id": "YOUR-PRIVATE-KEY-ID", 5 | "private_key": "YOUR-PRIVATE-KEY" 6 | client_email": "YOUR-GOOGLE-SERVICE-ACCOUNT-EMAIL", 7 | "client_id": "YOUR-CLIENT-ID", 8 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 9 | "token_uri": "https://oauth2.googleapis.com/token", 10 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", 11 | "client_x509_cert_url": "YOUR-CERT-URI" 12 | } 13 | -------------------------------------------------------------------------------- /Voice/Phone Survey With Python/sheets.py: -------------------------------------------------------------------------------- 1 | from oauth2client.service_account import ServiceAccountCredentials 2 | import gspread 3 | import os 4 | 5 | scope = ["https://spreadsheets.google.com/feeds","https://www.googleapis.com/auth/drive"] 6 | creds = ServiceAccountCredentials.from_json_keyfile_name(os.getcwd() + "/creds.json", scope) 7 | client = gspread.authorize(creds) 8 | sheet = client.open("Covid_Survey").sheet1 9 | 10 | -------------------------------------------------------------------------------- /Voice/Recording Audio Tracks with Websockets/app.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import json 3 | import websockets 4 | import asyncio 5 | import pywav 6 | 7 | 8 | async def hello(websocket): 9 | inboundAudio=[] 10 | outboundAudio=[] 11 | saveInbound=True 12 | saveOutbound=True 13 | try: 14 | async for message in websocket: 15 | msg=json.loads(message) 16 | if msg['event'] == 'start': 17 | callId = msg['start']['callSid'] 18 | if msg['event'] == 'media': 19 | media = msg['media'] 20 | if media['track'] == 'inbound': 21 | inboundAudio.append(base64.b64decode(media['payload'])) 22 | if media['track'] == 'outbound': 23 | outboundAudio.append(base64.b64decode(media['payload'])) 24 | 25 | if msg['event']=='stop': 26 | print('recieved stop, writing audio') 27 | 28 | if saveInbound == True: 29 | inbound_bytes = b"".join(inboundAudio) 30 | wave_write = pywav.WavWrite("Inbound-" + callId + ".wav", 1, 8000, 8, 7) 31 | wave_write.write(inbound_bytes) 32 | wave_write.close() 33 | 34 | if saveOutbound == True: 35 | outbound_bytes = b"".join(outboundAudio) 36 | wave_write = pywav.WavWrite("Outbound-" + callId + ".wav", 1, 8000, 8, 7) 37 | wave_write.write(outbound_bytes) 38 | wave_write.close() 39 | 40 | except websockets.ConnectionClosed: 41 | print('connection ended') 42 | 43 | async def main(): 44 | async with websockets.serve(hello,'localhost',5000): 45 | await asyncio.Future() 46 | 47 | asyncio.run(main()) -------------------------------------------------------------------------------- /Voice/Request Callback in a Queue with Python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | ADD app.py / 4 | 5 | RUN pip install flask 6 | RUN pip install signalwire 7 | 8 | EXPOSE 5000 9 | 10 | CMD [ "python", "./app.py" ] -------------------------------------------------------------------------------- /Voice/Request Callback in a Queue with Python/example.env: -------------------------------------------------------------------------------- 1 | SIGNALWIRE_SPACE= 2 | SIGNALWIRE_PROJECT= 3 | SIGNALWIRE_TOKEN= 4 | SIGNALWIRE_NUMBER= 5 | HOSTNAME= 6 | -------------------------------------------------------------------------------- /Voice/SIP Voicemail with NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | WORKDIR /app 4 | 5 | # Install app dependencies 6 | COPY package*.json ./ 7 | RUN npm install 8 | 9 | # Bundle app source 10 | COPY index.js . 11 | 12 | EXPOSE 3000 13 | 14 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Voice/SIP Voicemail with NodeJS/env.example: -------------------------------------------------------------------------------- 1 | # Project ID copied from the API Credentials in your SignalWire Space 2 | PROJECT_ID= 3 | # API token copied from the API Credentials in your SignalWire Space 4 | API_TOKEN= 5 | # Your SignalWire Space URL copied from the API Credentials in your SignalWire Space 6 | SIGNALWIRE_URL= 7 | -------------------------------------------------------------------------------- /Voice/SIP Voicemail with NodeJS/ngrok-webhook-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/SIP Voicemail with NodeJS/ngrok-webhook-config.png -------------------------------------------------------------------------------- /Voice/SIP Voicemail with NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sip-voicemail-with-nodejs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "type": "module", 6 | "main": "index.js", 7 | "scripts": { 8 | "start": "node index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@signalwire/compatibility-api": "^3.0.3", 15 | "dotenv": "^16.0.3", 16 | "express": "^4.18.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Voice/SIP Voicemail with Python/.env.example: -------------------------------------------------------------------------------- 1 | # Project ID copied from the API Credentials in your SignalWire Space 2 | PROJECT_ID= 3 | # API token copied from the API Credentials in your SignalWire Space 4 | API_TOKEN= 5 | # Your SignalWire Space URL copied from the API Credentials in your SignalWire Space 6 | # in the format: `.signalwire.com` 7 | SIGNALWIRE_URL= -------------------------------------------------------------------------------- /Voice/SIP Voicemail with Python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10 2 | 3 | WORKDIR /app 4 | COPY Pipfile Pipfile.lock ./ 5 | RUN pip install pipenv && pipenv install 6 | COPY . . 7 | 8 | EXPOSE 3000 9 | CMD ["pipenv", "run","python", "index.py"] -------------------------------------------------------------------------------- /Voice/SIP Voicemail with Python/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | signalwire = "*" 8 | flask = "*" 9 | 10 | [dev-packages] 11 | 12 | [requires] 13 | python_version = "3.10" 14 | 15 | [scripts] 16 | dev = "pipenv run python3 index.py" 17 | -------------------------------------------------------------------------------- /Voice/SIP Voicemail with Python/index.py: -------------------------------------------------------------------------------- 1 | from flask import Flask,Response,request 2 | from signalwire.voice_response import VoiceResponse 3 | app = Flask(__name__) 4 | 5 | @app.route("/", methods=["POST"]) 6 | def index(): 7 | response = VoiceResponse() 8 | response.say("Welcome to SignalWire. Please wait while we connect you to an agent.") 9 | dial = response.dial(timeout=15, action="/voicemail") 10 | dial.sip("sip:alice@example.com") 11 | return Response(str(response), mimetype="text/xml") 12 | 13 | @app.route("/voicemail", methods=["POST"]) 14 | def voicemail(): 15 | response = VoiceResponse() 16 | if request.form["DialCallStatus"] != "completed": 17 | response.say("The agent is currently unavailable, please leave a message.") 18 | response.record(action="/hangup") 19 | return Response(str(response), mimetype="text/xml") 20 | 21 | @app.route("/hangup", methods=["POST"]) 22 | def hangup(): 23 | if "RecordingUrl" in request.form: 24 | print("Recording Url:", request.form["RecordingUrl"]) 25 | response = VoiceResponse() 26 | response.hangup() 27 | return Response(str(response), mimetype="text/xml") 28 | 29 | app.run(debug=True) 30 | -------------------------------------------------------------------------------- /Voice/SIP Voicemail with Python/ngrok-webhook-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signalwire/examples/cc1fbb1ef522abc7fe8984b8b2bb984257c5c298/Voice/SIP Voicemail with Python/ngrok-webhook-config.png -------------------------------------------------------------------------------- /Voice/Screen Calls & Record Voicemail in PHP/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "slim/slim": "4.*", 4 | "nyholm/psr7": "^1.3", 5 | "nyholm/psr7-server": "^1.0", 6 | "signalwire/signalwire": "^2.3" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Voice/Screen Calls Based on Block List with Python/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request 2 | from signalwire.voice_response import VoiceResponse 3 | import os 4 | 5 | app = Flask(__name__) 6 | 7 | 8 | def get_blocklist(): 9 | # there is a default here you can change if you don't want to use the environment variable 10 | return os.getenv('BLOCKLIST', '+1555778899').split(',') 11 | 12 | 13 | @app.route('/check', methods=['POST']) 14 | def check_number(): 15 | response = VoiceResponse() 16 | from_number = request.form.get('From') 17 | 18 | if from_number not in get_blocklist(): 19 | response.redirect(os.environ.get('REDIRECT_PATH', 20 | 'https://example.signalwire.com/laml-bins/55ab7685-e9c3-4449-b1f0-07ff083d041e')) 21 | 22 | else: 23 | response.hangup() 24 | 25 | return response.to_xml() 26 | 27 | 28 | if __name__ == "__main__": 29 | app.run() -------------------------------------------------------------------------------- /Voice/Screen Calls Based on Block List with Python/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.7.4 2 | async-timeout==3.0.1 3 | asyncio==3.4.3 4 | attrs==20.3.0 5 | certifi==2020.12.5 6 | chardet==3.0.4 7 | click==7.1.2 8 | Flask==1.1.2 9 | idna==2.10 10 | itsdangerous==1.1.0 11 | Jinja2==2.11.2 12 | MarkupSafe==1.1.1 13 | multidict==5.1.0 14 | PyJWT==2.0.1 15 | PySocks==1.7.1 16 | pytz==2020.5 17 | requests==2.25.1 18 | signalwire==2.0.2 19 | six==1.15.0 20 | twilio==6.16.4 21 | typing-extensions==3.7.4.3 22 | urllib3==1.26.3 23 | Werkzeug==1.0.1 24 | yarl==1.6.3 -------------------------------------------------------------------------------- /Voice/Sentiment Analysis with Python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | ADD app.py / 4 | 5 | RUN pip install flask 6 | RUN pip install signalwire 7 | 8 | EXPOSE 5000 9 | 10 | CMD [ "python", "./app.py" ] 11 | -------------------------------------------------------------------------------- /Voice/Sentiment Analysis with Python/example.env: -------------------------------------------------------------------------------- 1 | MICROSOFT_KEY= -------------------------------------------------------------------------------- /Voice/Voicemails to Email IVR with NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | WORKDIR /app 4 | 5 | # Install app dependencies 6 | COPY package*.json ./ 7 | RUN npm install 8 | 9 | # Bundle app source 10 | COPY index.js . 11 | 12 | EXPOSE 3000 13 | 14 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Voice/Voicemails to Email IVR with NodeJS/env.example: -------------------------------------------------------------------------------- 1 | PRIMARY_SALES=+15557788999 2 | SECONDARY_SALES=+15554433222 3 | RECRUITERS_GROUP=+15556677888,+15559998877 4 | ACCOUNTING_GROUP=+15554455777 5 | JOBS_EMAIL=jobs@yourdomain.com 6 | ACCOUNT_EMAIL=accounts@yourdomain.com 7 | 8 | EMAIL_FROM=me@samples.mailgun.org 9 | MAILGUN_DOMAIN=your-Mailgun-domain 10 | MAILGUN_API_KEY=your-Mailgun-api-key -------------------------------------------------------------------------------- /Voice/Voicemails to Email IVR with NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node_ivr", 3 | "version": "1.0.0", 4 | "description": "An example SignalWire Node.js app", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js" 9 | }, 10 | "author": "Luca Pradovera ", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@signalwire/node": "^2.3.3", 14 | "express": "^4.17.1", 15 | "mailgun-js": "^0.22.0" 16 | }, 17 | "devDependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /Voice/Weather Phone IVR - NodeJS Relay v4/.env.sample: -------------------------------------------------------------------------------- 1 | PROJECT_ID= 2 | API_TOKEN= 3 | PHONE_NUMBER= -------------------------------------------------------------------------------- /Voice/Weather Phone IVR - NodeJS Relay v4/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | # Create app directory 4 | WORKDIR /usr/src/app 5 | 6 | # Install app dependencies 7 | COPY package.json ./ 8 | COPY yarn.lock ./ 9 | 10 | RUN npm install 11 | 12 | # Bundle app source 13 | COPY . . 14 | 15 | # Start app 16 | CMD [ "node", "index.js" ] -------------------------------------------------------------------------------- /Voice/Weather Phone IVR - NodeJS Relay v4/README.md: -------------------------------------------------------------------------------- 1 | # Build your own Weather Phone IVR with Realtime API 2 | 3 | 📖 [Read the full guide](https://developer.signalwire.com/apis/docs/weather-phone-in-nodejs-with-signalwire-realtime-api?relay_version=relayv4) 4 | 5 | This code sample is a simple weather phone IVR application that uses the [SignalWire Realtime API](https://developer.signalwire.com/sdks/reference/realtime-sdk/relay-v4) to provide current weather report to the caller in Washington DC either as a phone call or text. 6 | 7 | 8 | 9 | --- 10 | 11 | ### To run this sample 12 | 13 | 1. Fill in the Project ID and the API token from your SignalWire dashboard in the `.env.sample` file. 14 | 2. Buy a number from the SignalWire Dashboard, configure it to use Relay with context `office`. 15 | 3. Add that number to the `.env.sample` file under `PHONE_NUMBER`. 16 | 4. Rename the `.env.sample` file to `.env`. 17 | 5. Run this with `yarn install` then `yarn start` in the project directory. 18 | Alternatively, you can use Docker instead: 19 | 20 | a. `docker build . -t weather-ivr` to build the container using the dockerfile already in the repo. 21 | 22 | b. `docker run -d weather-ivr` to run it. 23 | 24 | For more information on how to run this sample, or for a more detailed guide, please read the [guide](https://developer.signalwire.com/apis/docs/weather-phone-in-nodejs-with-signalwire-realtime-api?relay_version=relayv4). 25 | -------------------------------------------------------------------------------- /Voice/Weather Phone IVR - NodeJS Relay v4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weatherphoneivr", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "type": "module", 7 | "scripts": { 8 | "start": "nodemon index.js" 9 | }, 10 | "dependencies": { 11 | "@signalwire/realtime-api": "^4.0.0", 12 | "axios": "^0.27.2", 13 | "dotenv": "^16.0.1", 14 | "libphonenumber-js": "^1.10.6" 15 | }, 16 | "devDependencies": { 17 | "forever": "^4.0.3", 18 | "nodemon": "^1.18.4" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Voice/Weather Phone IVR - NodeJS/.env.sample: -------------------------------------------------------------------------------- 1 | PROJECT_ID= 2 | API_TOKEN= 3 | PHONE_NUMBER= -------------------------------------------------------------------------------- /Voice/Weather Phone IVR - NodeJS/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | # Create app directory 4 | WORKDIR /usr/src/app 5 | 6 | # Install app dependencies 7 | COPY package.json ./ 8 | COPY yarn.lock ./ 9 | 10 | RUN npm install 11 | 12 | # Bundle app source 13 | COPY . . 14 | 15 | # Start app 16 | CMD [ "node", "index.js" ] -------------------------------------------------------------------------------- /Voice/Weather Phone IVR - NodeJS/README.md: -------------------------------------------------------------------------------- 1 | # Build your own Weather Phone IVR with Realtime API 2 | 3 | 📖 [Read the full guide](https://developer.signalwire.com/apis/docs/weather-phone-in-nodejs-with-signalwire-realtime-api) 4 | 5 | This code sample is a simple weather phone IVR application that uses the [SignalWire Realtime API](https://developer.signalwire.com/client-sdk/reference/rt-exports) to provide current weather report to the caller in Washington DC either as a phone call or text. 6 | 7 | ### 📞 Dial [+17712093222](tel:+17712093222) ☎ for a **live demo** of this code. 8 | 9 | --- 10 | 11 | ### To run this sample 12 | 13 | 1. Fill in the Project ID and the API token from your SignalWire dashboard in the `.env.sample` file. 14 | 2. Buy a number from the SignalWire Dashboard, configure it to use Relay with context `office`. 15 | 3. Add that number to the `.env.sample` file under `PHONE_NUMBER`. 16 | 4. Rename the `.env.sample` file to `.env`. 17 | 5. Run this with `yarn install` then `yarn start` in the project directory. 18 | Alternatively, you can use Docker instead: 19 | 20 | a. `docker build . -t weather-ivr` to build the container using the dockerfile already in the repo. 21 | 22 | b. `docker run -d weather-ivr` to run it. 23 | 24 | For more information on how to run this sample, or for a more detailed guide, please read the [guide](https://developer.signalwire.com/apis/docs/weather-phone-in-nodejs-with-signalwire-realtime-api). 25 | -------------------------------------------------------------------------------- /Voice/Weather Phone IVR - NodeJS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weatherphoneivr", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "nodemon index.js" 8 | }, 9 | "dependencies": { 10 | "@signalwire/realtime-api": "^3.1.0", 11 | "axios": "^0.27.2", 12 | "dotenv": "^16.0.1", 13 | "libphonenumber-js": "^1.10.6" 14 | }, 15 | "devDependencies": { 16 | "forever": "^4.0.3", 17 | "nodemon": "^1.18.4" 18 | } 19 | } 20 | --------------------------------------------------------------------------------