├── .env.example ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── fax.js ├── index.js ├── package-lock.json ├── package.json └── testpage.pdf /.env.example: -------------------------------------------------------------------------------- 1 | # URL of the API endpoint. You probably don't have to change this. 2 | BASE_URL=https://api.sipgate.com/v2 3 | 4 | # your Personal-Access-Token and the ID 5 | # Open https://app.sipgate.com and create a new token by navigating to "Benutzereinstellungen" -> "Personal-Access-Tokens" 6 | TOKEN_ID=YOUR_SIPGATE_TOKEN_ID 7 | TOKEN=YOUR_SIPGATE_TOKEN 8 | 9 | # Choose a Faxline ID to be used. 10 | # You can use the "/{userID}/faxlines" endpoint to list the available faxline IDs for a given user (see https://api.sipgate.com/v2/doc#/faxlines/getUserFaxlines). 11 | # Alternatively you can use the Node.JS library (see https://github.com/sipgate-io/sipgateio-node-examples#list-common-ids) 12 | FAXLINE_ID=YOUR_SIPGATE_FAXLINE_ID 13 | 14 | # Choose the fax number of the recipient. 15 | # The recomended format is the E.164 standard. (see https://en.wikipedia.org/wiki/E.164) 16 | RECIPIENT=+49012345678901 17 | 18 | # Choose the path of the pdf file to send. 19 | PDF_FILE_PATH=./testpage.pdf 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Run tests on pull request and auto merge dependabot pull requests 2 | 3 | on: pull_request 4 | 5 | permissions: write-all 6 | 7 | jobs: 8 | dependabot_merge: 9 | uses: sipgate-io/dependabot-automerge/.github/workflows/dependabot_automerge.yml@main 10 | secrets: inherit 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/vim,git,macos,linux,intellij+all,visualstudiocode,node 2 | # Edit at https://www.gitignore.io/?templates=vim,git,macos,linux,intellij+all,visualstudiocode,node 3 | 4 | ### Git ### 5 | # Created by git for backups. To disable backups in Git: 6 | # $ git config --global mergetool.keepBackup false 7 | *.orig 8 | 9 | # Created by git when using merge tools for conflicts 10 | *.BACKUP.* 11 | *.BASE.* 12 | *.LOCAL.* 13 | *.REMOTE.* 14 | *_BACKUP_*.txt 15 | *_BASE_*.txt 16 | *_LOCAL_*.txt 17 | *_REMOTE_*.txt 18 | 19 | ### Intellij+all ### 20 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 21 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 22 | 23 | # User-specific stuff 24 | .idea/**/workspace.xml 25 | .idea/**/tasks.xml 26 | .idea/**/usage.statistics.xml 27 | .idea/**/dictionaries 28 | .idea/**/shelf 29 | 30 | # Generated files 31 | .idea/**/contentModel.xml 32 | 33 | # Sensitive or high-churn files 34 | .idea/**/dataSources/ 35 | .idea/**/dataSources.ids 36 | .idea/**/dataSources.local.xml 37 | .idea/**/sqlDataSources.xml 38 | .idea/**/dynamic.xml 39 | .idea/**/uiDesigner.xml 40 | .idea/**/dbnavigator.xml 41 | 42 | # Gradle 43 | .idea/**/gradle.xml 44 | .idea/**/libraries 45 | 46 | # Gradle and Maven with auto-import 47 | # When using Gradle or Maven with auto-import, you should exclude module files, 48 | # since they will be recreated, and may cause churn. Uncomment if using 49 | # auto-import. 50 | # .idea/modules.xml 51 | # .idea/*.iml 52 | # .idea/modules 53 | 54 | # CMake 55 | cmake-build-*/ 56 | 57 | # Mongo Explorer plugin 58 | .idea/**/mongoSettings.xml 59 | 60 | # File-based project format 61 | *.iws 62 | 63 | # IntelliJ 64 | out/ 65 | 66 | # mpeltonen/sbt-idea plugin 67 | .idea_modules/ 68 | 69 | # JIRA plugin 70 | atlassian-ide-plugin.xml 71 | 72 | # Cursive Clojure plugin 73 | .idea/replstate.xml 74 | 75 | # Crashlytics plugin (for Android Studio and IntelliJ) 76 | com_crashlytics_export_strings.xml 77 | crashlytics.properties 78 | crashlytics-build.properties 79 | fabric.properties 80 | 81 | # Editor-based Rest Client 82 | .idea/httpRequests 83 | 84 | # Android studio 3.1+ serialized cache file 85 | .idea/caches/build_file_checksums.ser 86 | 87 | ### Intellij+all Patch ### 88 | # Ignores the whole .idea folder and all .iml files 89 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 90 | 91 | .idea/ 92 | 93 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 94 | 95 | *.iml 96 | modules.xml 97 | .idea/misc.xml 98 | *.ipr 99 | 100 | # Sonarlint plugin 101 | .idea/sonarlint 102 | 103 | ### Linux ### 104 | *~ 105 | 106 | # temporary files which can be created if a process still has a handle open of a deleted file 107 | .fuse_hidden* 108 | 109 | # KDE directory preferences 110 | .directory 111 | 112 | # Linux trash folder which might appear on any partition or disk 113 | .Trash-* 114 | 115 | # .nfs files are created when an open file is removed but is still being accessed 116 | .nfs* 117 | 118 | ### macOS ### 119 | # General 120 | .DS_Store 121 | .AppleDouble 122 | .LSOverride 123 | 124 | # Icon must end with two \r 125 | Icon 126 | 127 | # Thumbnails 128 | ._* 129 | 130 | # Files that might appear in the root of a volume 131 | .DocumentRevisions-V100 132 | .fseventsd 133 | .Spotlight-V100 134 | .TemporaryItems 135 | .Trashes 136 | .VolumeIcon.icns 137 | .com.apple.timemachine.donotpresent 138 | 139 | # Directories potentially created on remote AFP share 140 | .AppleDB 141 | .AppleDesktop 142 | Network Trash Folder 143 | Temporary Items 144 | .apdisk 145 | 146 | ### Node ### 147 | # Logs 148 | logs 149 | *.log 150 | npm-debug.log* 151 | yarn-debug.log* 152 | yarn-error.log* 153 | 154 | # Runtime data 155 | pids 156 | *.pid 157 | *.seed 158 | *.pid.lock 159 | 160 | # Directory for instrumented libs generated by jscoverage/JSCover 161 | lib-cov 162 | 163 | # Coverage directory used by tools like istanbul 164 | coverage 165 | 166 | # nyc test coverage 167 | .nyc_output 168 | 169 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 170 | .grunt 171 | 172 | # Bower dependency directory (https://bower.io/) 173 | bower_components 174 | 175 | # node-waf configuration 176 | .lock-wscript 177 | 178 | # Compiled binary addons (https://nodejs.org/api/addons.html) 179 | build/Release 180 | 181 | # Dependency directories 182 | node_modules/ 183 | jspm_packages/ 184 | 185 | # TypeScript v1 declaration files 186 | typings/ 187 | 188 | # Optional npm cache directory 189 | .npm 190 | 191 | # Optional eslint cache 192 | .eslintcache 193 | 194 | # Optional REPL history 195 | .node_repl_history 196 | 197 | # Output of 'npm pack' 198 | *.tgz 199 | 200 | # Yarn Integrity file 201 | .yarn-integrity 202 | 203 | # dotenv environment variables file 204 | .env 205 | .env.test 206 | 207 | # parcel-bundler cache (https://parceljs.org/) 208 | .cache 209 | 210 | # next.js build output 211 | .next 212 | 213 | # nuxt.js build output 214 | .nuxt 215 | 216 | # vuepress build output 217 | .vuepress/dist 218 | 219 | # Serverless directories 220 | .serverless/ 221 | 222 | # FuseBox cache 223 | .fusebox/ 224 | 225 | # DynamoDB Local files 226 | .dynamodb/ 227 | 228 | ### Vim ### 229 | # Swap 230 | [._]*.s[a-v][a-z] 231 | [._]*.sw[a-p] 232 | [._]s[a-rt-v][a-z] 233 | [._]ss[a-gi-z] 234 | [._]sw[a-p] 235 | 236 | # Session 237 | Session.vim 238 | 239 | # Temporary 240 | .netrwhist 241 | # Auto-generated tag files 242 | tags 243 | # Persistent undo 244 | [._]*.un~ 245 | 246 | ### VisualStudioCode ### 247 | .vscode/* 248 | !.vscode/settings.json 249 | !.vscode/tasks.json 250 | !.vscode/launch.json 251 | !.vscode/extensions.json 252 | 253 | ### VisualStudioCode Patch ### 254 | # Ignore all local history of files 255 | .history 256 | 257 | # End of https://www.gitignore.io/api/vim,git,macos,linux,intellij+all,visualstudiocode,node -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sipgate logo 2 | 3 | # sipgate.io Node.js send fax example 4 | 5 | To demonstrate how to send an Fax, we queried the `/sessions/fax` endpoint of the sipgate REST API. 6 | 7 | For further information regarding the sipgate REST API please visit https://api.sipgate.com/v2/doc 8 | 9 | ## Prerequisites 10 | 11 | - Node.js >= 10.15.3 12 | 13 | ### How To Use 14 | 15 | Install dependencies: 16 | 17 | ```bash 18 | npm install 19 | ``` 20 | 21 | ## Configuration 22 | 23 | Create the .env file by copying the .env.example. Set the values according to the comment above each variable. 24 | 25 | The token must have the `sessions:fax:write` and `history:read` scopes. 26 | For more information about personal access tokens visit our [website.](https://www.sipgate.io/rest-api/authentication#personalAccessToken) 27 | 28 | The `FAXLINE_ID` uniquely identifies the extension from which you wish to send your fax. Further explanation is given in the section [Fax Extensions](#fax-extensions). 29 | 30 | Although the API accepts various formats of fax numbers, the recommended format for the `RECIPIENT` is the [E.164 standard](https://en.wikipedia.org/wiki/E.164). 31 | 32 | `PDF_FILE_PATH` expects an either relative or absolute file path to your desired PDF file to be sent. 33 | 34 | Run the application: 35 | 36 | ```bash 37 | node index.js 38 | ``` 39 | 40 | ## How It Works 41 | 42 | ```javascript 43 | const type = fileType(fs.readFileSync(PDF_FILE_PATH)); 44 | 45 | if (!type || type.mime !== "application/pdf") { 46 | console.error("The file must be a PDF"); 47 | process.exit(1); 48 | } 49 | ``` 50 | 51 | To check if the provided file is a PDF document we use the `file-type` module to ensure that the mime-type of the file is `application/pdf`. 52 | 53 | After getting the recipient number and filePath from the supplied arguments and checking the file is a PDF document, we call our `sendFax` function located in the [fax.js](./fax.js) and pass the `recipient` and the `filePath` as arguments. 54 | 55 | ```javascript 56 | const sendFaxResponse = await sendFax(RECIPIENT, PDF_FILE_PATH); 57 | ``` 58 | 59 | In the `sendFax` function, we first get the filename of the supplied file. 60 | 61 | ```javascript 62 | const filename = path.basename(PDF_FILE_PATH); 63 | const base64Content = readFileAsBase64(PDF_FILE_PATH); 64 | ``` 65 | 66 | After that we call our `readFileAsBase64` function which reads the file contents and Base64 encodes it. 67 | 68 | ```javascript 69 | const readFileAsBase64 = (filePath) => { 70 | const fileContents = fs.readFileSync(filePath); 71 | return Buffer.from(fileContents).toString("base64"); 72 | }; 73 | ``` 74 | 75 | We define the data object which contains the `faxlineId`, `recipient`, `filename`, and `base64Content`. 76 | 77 | ```javascript 78 | const data = { 79 | faxlineId: FAXLINE_ID, 80 | recipient, 81 | filename, 82 | base64Content, 83 | }; 84 | ``` 85 | 86 | We use the axios package for request execution. The 87 | `requestOptions` object contains the parameters `method`, `headers`, `auth`, `baseURL` and `data` (previously referred) which will be used by axios in order to send the desired http post request. The `auth` property takes a username and password and generates an HTTP Basic Auth header (for more information on Basic Auth see our [code example](https://github.com/sipgate/sipgateio-basicauth-node)). 88 | 89 | ```javascript 90 | ... 91 | const requestOptions = { 92 | baseURL: BASE_URL, 93 | method: 'POST', 94 | headers: { 95 | Accept: 'application/json', 96 | 'Content-Type': 'application/json', 97 | }, 98 | auth: { 99 | username: TOKEN_ID, 100 | password: TOKEN, 101 | }, 102 | data, 103 | }; 104 | 105 | try { 106 | const sendFaxResponse = await axios(`/sessions/fax`, requestOptions); 107 | return sendFaxResponse; 108 | } catch (error) { 109 | console.error('Error:', error.message); 110 | return null; 111 | } 112 | ... 113 | ``` 114 | 115 | The `axios` instance takes the request URL and `requestOptions` as arguments and process the desired http request. The request URL consists of the base URL defined above and the endpoint `/sessions/fax`. 116 | 117 | Next we check if status of our `sendFaxResponse` is 200, meaning that the request to send the fax was successfully received. 118 | **Note:** Although the Api returns the status 200 it does not mean that the fax was sent. It was only added to a queue for sending. 119 | 120 | To check the status of the fax we use the `sessionId`, returned by the `sendFax` function, and pass it to the `fetchFaxStatus` function. In this example we use `setInterval` to check the status of the fax every five seconds. 121 | 122 | ```javascript 123 | if (sendFaxResponse && sendFaxResponse.status === 200) { 124 | console.log("Fax added to the sending queue."); 125 | 126 | const { sessionId } = sendFaxResponse.data; 127 | 128 | setInterval(async () => { 129 | const faxStatus = await fetchFaxStatus(sessionId); 130 | 131 | if (faxStatus) { 132 | console.log("Checking fax status -", new Date()); 133 | console.log(faxStatus); 134 | 135 | if (faxStatus.faxStatusType === "SENT") { 136 | console.log("The Fax was sent successfully."); 137 | process.exit(1); 138 | } 139 | } else { 140 | console.error("Could not get fax status."); 141 | process.exit(1); 142 | } 143 | }, 5000); 144 | } 145 | ``` 146 | 147 | In the `fetchFaxStatus` function we use axios again to query the `/history/{sessionId}` endpoint to get the history entry for our fax. In this case we are only interested in the `faxStatusType`. 148 | 149 | ```javascript 150 | const fetchFaxStatus = async (sessionId) => { 151 | try { 152 | const historyResponse = await axios(`/history/${sessionId}`, { 153 | baseURL: BASE_URL, 154 | method: "GET", 155 | headers: { 156 | Accept: "application/json", 157 | "Content-Type": "application/json", 158 | }, 159 | auth: { 160 | username: TOKEN_ID, 161 | password: TOKEN, 162 | }, 163 | }); 164 | return { 165 | faxStatusType: historyResponse.data.faxStatusType, 166 | }; 167 | } catch (error) { 168 | console.error("Error:", error.message); 169 | return null; 170 | } 171 | }; 172 | ``` 173 | 174 | The `faxStatusType` can contain the following values: 175 | 176 | - `PENDING`: The fax was added to the queue for sending, but the sending process has not started yet 177 | - `SENDING`: The fax is currently being sent 178 | - `FAILED`: The fax could not be sent 179 | - `SENT`: The fax was sent successfully 180 | - `SCHEDULED`: The fax is scheduled for sending at the specified timestamp (it is not `PENDING` because it is not waiting in the queue of faxes to be sent yet) 181 | 182 | ### Fax Extensions 183 | 184 | A Fax extension consists of the letter 'f' followed by a number (e.g. 'f0'). The sipgate API uses the concept of Fax extensions to identify devices within your account that are enabled to send Fax. In this context the term 'device' does not necessarily refer to a hardware Fax but rather a virtual representation. 185 | 186 | You can find out what your Fax extension is as follows: 187 | 188 | 1. Log into your [sipgate account](https://app.sipgate.com/w0/routing) 189 | 2. Use the sidebar to navigate to the **Routing** (_Telefonie_) tab 190 | 3. Click on any **Fax** device in your routing table 191 | 4. Select any option (gear icon) to open the corresponding menu 192 | 5. The URL of the page should have the form `https://app.sipgate.com/w0/routing/dialog/{option}/{faxlineId}` where `{faxlineId}` is your Fax extension. 193 | 194 | ### Common Issues 195 | 196 | #### Fax added to the sending queue, but sending failed 197 | 198 | Possible reasons are: 199 | 200 | - PDF file not encoded correctly in base64 201 | - PDF file with text fields or forms are not supported 202 | - PDF file is corrupt 203 | 204 | #### HTTP Errors 205 | 206 | | reason | errorcode | 207 | | ----------------------------------------------------------------------------------------------------------------------------------------------------- | :-------: | 208 | | bad request (e.g. request body fields are empty or only contain spaces, timestamp is invalid etc.) | 400 | 209 | | tokenId and/or token are wrong | 401 | 210 | | your account balance is insufficient | 402 | 211 | | no permission to use specified Fax extension (e.g. Fax feature not booked or user password must be reset in [web app](https://app.sipgate.com/login)) | 403 | 212 | | wrong REST API endpoint | 404 | 213 | | wrong request method | 405 | 214 | | invalid recipient fax number | 407 | 215 | | wrong or missing `Content-Type` header with `application/json` | 415 | 216 | | internal server error or unhandled bad request | 500 | 217 | 218 | ### Related 219 | 220 | - [axios](https://github.com/axios/axios) 221 | - [file-type](https://github.com/sindresorhus/file-type) 222 | 223 | ### Contact Us 224 | 225 | Please let us know how we can improve this example. 226 | If you have a specific feature request or found a bug, please use **Issues** or fork this repository and send a **pull request** with your improvements. 227 | 228 | ### License 229 | 230 | This project is licensed under **The Unlicense** (see [LICENSE file](./LICENSE)). 231 | 232 | ### External Libraries 233 | 234 | This code uses the following external libraries 235 | 236 | - axios: 237 | Licensed under the [MIT License](https://opensource.org/licenses/MIT) 238 | Website: https://github.com/axios/axios 239 | 240 | - file-type: 241 | Licensed under the [MIT License](https://opensource.org/licenses/MIT) 242 | Website: https://github.com/sindresorhus/file-type 243 | 244 | --- 245 | 246 | [sipgate.io](https://www.sipgate.io) | [@sipgateio](https://twitter.com/sipgateio) | [API-doc](https://api.sipgate.com/v2/doc) 247 | -------------------------------------------------------------------------------- /fax.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | 5 | require('dotenv').config() 6 | const { BASE_URL, TOKEN_ID, TOKEN, FAXLINE_ID } = process.env; 7 | 8 | const readFileAsBase64 = filePath => { 9 | const fileContents = fs.readFileSync(filePath); 10 | return Buffer.from(fileContents).toString('base64'); 11 | }; 12 | 13 | const sendFax = async (recipient, filePath) => { 14 | const filename = path.basename(filePath); 15 | const base64Content = readFileAsBase64(filePath); 16 | 17 | const data = { 18 | faxlineId: FAXLINE_ID, 19 | recipient, 20 | filename, 21 | base64Content, 22 | }; 23 | 24 | const requestOptions = { 25 | baseURL: BASE_URL, 26 | method: 'POST', 27 | headers: { 28 | Accept: 'application/json', 29 | 'Content-Type': 'application/json', 30 | }, 31 | auth: { 32 | username: TOKEN_ID, 33 | password: TOKEN, 34 | }, 35 | data, 36 | }; 37 | 38 | try { 39 | const sendFaxResponse = await axios(`/sessions/fax`, requestOptions); 40 | return sendFaxResponse; 41 | } catch (error) { 42 | console.error('Error:', error.message); 43 | return null; 44 | } 45 | }; 46 | 47 | const fetchFaxStatus = async sessionId => { 48 | try { 49 | const historyResponse = await axios(`/history/${sessionId}`, { 50 | baseURL: BASE_URL, 51 | method: 'GET', 52 | headers: { 53 | Accept: 'application/json', 54 | 'Content-Type': 'application/json', 55 | }, 56 | auth: { 57 | username: TOKEN_ID, 58 | password: TOKEN, 59 | }, 60 | }); 61 | return { 62 | faxStatusType: historyResponse.data.faxStatusType, 63 | }; 64 | } catch (error) { 65 | console.error('Error:', error.message); 66 | return null; 67 | } 68 | }; 69 | 70 | module.exports = { sendFax, fetchFaxStatus }; 71 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const fileType = require('file-type'); 2 | const fs = require('fs'); 3 | 4 | const { sendFax, fetchFaxStatus } = require('./fax'); 5 | 6 | require('dotenv').config() 7 | const { RECIPIENT, PDF_FILE_PATH } = process.env; 8 | 9 | (async () => { 10 | const type = fileType(fs.readFileSync(PDF_FILE_PATH)); 11 | 12 | if (!type || type.mime !== 'application/pdf') { 13 | console.error('The file must be a PDF'); 14 | process.exit(1); 15 | } 16 | 17 | console.log('Add fax to the sending queue...'); 18 | const sendFaxResponse = await sendFax(RECIPIENT, PDF_FILE_PATH); 19 | 20 | if (sendFaxResponse && sendFaxResponse.status === 200) { 21 | console.log('Fax added to the sending queue.'); 22 | const { sessionId } = sendFaxResponse.data; 23 | 24 | setInterval(async () => { 25 | const faxStatus = await fetchFaxStatus(sessionId); 26 | 27 | if (faxStatus) { 28 | console.log('Checking fax status -', new Date()); 29 | console.log(faxStatus); 30 | 31 | if (faxStatus.faxStatusType === 'SENT') { 32 | console.log('The Fax was sent successfully.'); 33 | process.exit(1); 34 | } 35 | } else { 36 | console.error('Could not get fax status.'); 37 | process.exit(1); 38 | } 39 | }, 5000); 40 | } 41 | })(); 42 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sipgateio-sendfax-node", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "sipgateio-sendfax-node", 9 | "version": "1.0.0", 10 | "license": "Unlicense", 11 | "dependencies": { 12 | "axios": "^0.21.1", 13 | "dotenv": "^16.0.2", 14 | "file-type": "^11.1.0" 15 | }, 16 | "engines": { 17 | "node": "10.15.3" 18 | } 19 | }, 20 | "node_modules/axios": { 21 | "version": "0.21.4", 22 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", 23 | "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", 24 | "dependencies": { 25 | "follow-redirects": "^1.14.0" 26 | } 27 | }, 28 | "node_modules/dotenv": { 29 | "version": "16.0.2", 30 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz", 31 | "integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==", 32 | "engines": { 33 | "node": ">=12" 34 | } 35 | }, 36 | "node_modules/file-type": { 37 | "version": "11.1.0", 38 | "resolved": "https://registry.npmjs.org/file-type/-/file-type-11.1.0.tgz", 39 | "integrity": "sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g==", 40 | "engines": { 41 | "node": ">=6" 42 | } 43 | }, 44 | "node_modules/follow-redirects": { 45 | "version": "1.15.1", 46 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", 47 | "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", 48 | "funding": [ 49 | { 50 | "type": "individual", 51 | "url": "https://github.com/sponsors/RubenVerborgh" 52 | } 53 | ], 54 | "engines": { 55 | "node": ">=4.0" 56 | }, 57 | "peerDependenciesMeta": { 58 | "debug": { 59 | "optional": true 60 | } 61 | } 62 | } 63 | }, 64 | "dependencies": { 65 | "axios": { 66 | "version": "0.21.4", 67 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", 68 | "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", 69 | "requires": { 70 | "follow-redirects": "^1.14.0" 71 | } 72 | }, 73 | "dotenv": { 74 | "version": "16.0.2", 75 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz", 76 | "integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==" 77 | }, 78 | "file-type": { 79 | "version": "11.1.0", 80 | "resolved": "https://registry.npmjs.org/file-type/-/file-type-11.1.0.tgz", 81 | "integrity": "sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g==" 82 | }, 83 | "follow-redirects": { 84 | "version": "1.15.1", 85 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", 86 | "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sipgateio-sendfax-node", 3 | "version": "1.0.0", 4 | "description": "A demonstration on how to send a fax using the sipgate REST API.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "keywords": [], 10 | "author": "sipgate.io", 11 | "repository": "https://github.com/sipgate-io/sipgateio-sendfax-node", 12 | "engines": { 13 | "node": "10.15.3" 14 | }, 15 | "license": "Unlicense", 16 | "dependencies": { 17 | "axios": "^0.21.1", 18 | "dotenv": "^16.0.2", 19 | "file-type": "^11.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /testpage.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sipgate-io/sipgateio-sendfax-node/adb81f472760d22223e9398a525e4b2de6bbfb88/testpage.pdf --------------------------------------------------------------------------------