├── .gitignore ├── package.json ├── phaxio.js └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "Chad Smith", 4 | "email": "chad@nospam.me", 5 | "url": "http://twitter.com/chadsmith" 6 | }, 7 | "contributors": [ 8 | { 9 | "name": "Francis Gulotta", 10 | "email": "wizard@roborooter.com", 11 | "url": "http://rbrtr.com" 12 | } 13 | ], 14 | "name": "phaxio", 15 | "description": "Send faxes with the Phaxio API", 16 | "keywords": [ 17 | "fax", 18 | "phaxio" 19 | ], 20 | "version": "1.0.0", 21 | "homepage": "https://github.com/chadsmith/node-phaxio", 22 | "repository": { 23 | "type": "git", 24 | "url": "git://github.com/chadsmith/node-phaxio.git" 25 | }, 26 | "engines": { 27 | "node": ">=4.0.0" 28 | }, 29 | "main": "./phaxio.js", 30 | "dependencies": { 31 | "mime": "1.2.x", 32 | "request": "^2.87.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /phaxio.js: -------------------------------------------------------------------------------- 1 | var mime = require('mime'), 2 | fs = require('fs'), 3 | path = require('path'), 4 | request = require('request'); 5 | 6 | var Phaxio = module.exports = function(api_key, api_secret) { 7 | this.api_key = api_key; 8 | this.api_secret = api_secret; 9 | this.host = 'https://api.phaxio.com'; 10 | this.endpoint = '/v1'; 11 | }; 12 | 13 | Phaxio.prototype.sendFax = function(opt, cb) { 14 | if (!opt.to) { 15 | return cb(new Error("You must include a 'to' number.")); 16 | } 17 | if (!opt.filenames && !opt.string_data) { 18 | return cb(new Error("You must include filenames or string_data.")); 19 | } 20 | return this.request('/send', opt, cb); 21 | }; 22 | 23 | Phaxio.prototype.cancelFax = function(faxId, cb) { 24 | if (!faxId) { 25 | return cb(new Error('You must include a fax id.')); 26 | } 27 | return this.request('/faxCancel', { 28 | id: faxId 29 | }, cb); 30 | }; 31 | 32 | Phaxio.prototype.faxStatus = function(faxId, cb) { 33 | if (!faxId) { 34 | return cb(new Error('You must include a fax id.')); 35 | } 36 | return this.request('/faxStatus', { 37 | id: faxId 38 | }, cb); 39 | }; 40 | 41 | Phaxio.prototype.fireBatch = function(batchId, cb) { 42 | if (!batchId) { 43 | return cb(new Error('You must provide a batchId.')); 44 | } 45 | return this.request('/fireBatch', { 46 | id: batchId 47 | }, cb); 48 | }; 49 | 50 | Phaxio.prototype.closeBatch = function(batchId, cb) { 51 | if (!batchId) { 52 | return cb(new Error('You must provide a batchId.')); 53 | } 54 | return this.request('/closeBatch', { 55 | id: batchId 56 | }, cb); 57 | }; 58 | 59 | Phaxio.prototype.provisionNumber = function(opt, cb) { 60 | if (!opt.area_code) { 61 | return cb(new Error('You must provide an area code.')); 62 | } 63 | this.request('/provisionNumber', opt, cb); 64 | }; 65 | 66 | Phaxio.prototype.releaseNumber = function(number, cb) { 67 | if (!number) { 68 | return cb(new Error('You must provide a number.')); 69 | } 70 | return this.request('/releaseNumber', { 71 | number: number 72 | }, cb); 73 | }; 74 | 75 | Phaxio.prototype.numberList = function(opt, cb) { 76 | if (typeof opt === 'function') { 77 | cb = opt; 78 | opt = {}; 79 | } 80 | return this.request('/numberList', opt, cb); 81 | }; 82 | 83 | Phaxio.prototype.areaCodes = function(opt, cb) { 84 | if (typeof opt === 'function') { 85 | cb = opt; 86 | opt = {}; 87 | } 88 | return this.request('/areaCodes', opt, cb); 89 | }; 90 | 91 | Phaxio.prototype.accountStatus = function(cb) { 92 | return this.request('/accountStatus', {}, cb); 93 | }; 94 | 95 | Phaxio.prototype.testReceive = function(opt, cb) { 96 | if (!opt.filenames) { 97 | return cb(new Error('You must provide a filename')); 98 | } 99 | return this.request('/testReceive', opt, cb); 100 | }; 101 | 102 | Phaxio.prototype.attachPhaxCodeToPdf = function(opt, cb) { 103 | if (typeof opt.x !== 'number' || typeof opt.y !== 'number') { 104 | return cb(new Error("x and y need to be numbers")); 105 | } 106 | if (!opt.filename) { 107 | return cb(new Error("You must provide a filename")); 108 | } 109 | return this.request('/attachPhaxCodeToPdf', opt, cb, true); 110 | }; 111 | 112 | Phaxio.prototype.createPhaxCode = function(opt, cb) { 113 | if (typeof opt === 'function') { 114 | cb = opt; 115 | opt = {}; 116 | } 117 | return this.request('/createPhaxCode', opt, cb, opt.redirect); 118 | }; 119 | 120 | Phaxio.prototype.getHostedDocument = function(opt, cb) { 121 | if (!opt.name) { 122 | return cb(new Error('You must provide a document name.')); 123 | } 124 | return this.request('/getHostedDocument', opt, cb, true); 125 | }; 126 | 127 | Phaxio.prototype.faxFile = function(opt, cb) { 128 | if (!opt.id) { 129 | return cb(new Error('You must include a fax id.')); 130 | } 131 | return this.request('/faxFile', opt, cb, true); 132 | }; 133 | 134 | Phaxio.prototype.request = function(resource, opt, cb) { 135 | if (typeof cb !== 'function') { 136 | cb = function() {}; 137 | } 138 | 139 | opt = opt || {}; 140 | opt.api_key = opt.api_key || this.api_key; 141 | opt.api_secret = opt.api_secret || this.api_secret; 142 | 143 | var multipart = []; 144 | 145 | var filenames = opt.filenames; 146 | delete opt.filenames; 147 | 148 | var addPart = function(name, body) { 149 | multipart.push({ 150 | 'content-disposition': 'form-data; name="' + name + '"', 151 | body: body 152 | }); 153 | }; 154 | 155 | var _iterator = function(v) { 156 | addPart(name, v); 157 | }; 158 | 159 | for (var key in opt) { 160 | 161 | if (opt.hasOwnProperty(key)) { 162 | 163 | var name = key; 164 | 165 | if (Array.isArray(opt[key])) { 166 | name = name + '[]'; 167 | opt[key].forEach(_iterator); 168 | } else if (typeof opt[key] === "boolean" || typeof opt[key] === "number") { 169 | addPart(name, opt[key].toString()); 170 | } else { 171 | addPart(name, opt[key]); 172 | } 173 | } 174 | } 175 | 176 | var reqBody = { 177 | method: 'POST', 178 | uri: this.host + this.endpoint + resource, 179 | headers: { 180 | 'content-type': 'multipart/form-data;' 181 | }, 182 | multipart: multipart, 183 | encoding: 'binary', 184 | agent: false 185 | }; 186 | 187 | var responseCb = function(err, res, body) { 188 | // phaxio isn't too picky about response types 189 | if (res && (true || res.headers['content-type'] === 'application/json')) { 190 | try { 191 | body = JSON.parse(body); 192 | } catch (e) { 193 | //err = err || e; 194 | } 195 | } 196 | 197 | cb(err, body, res); 198 | }; 199 | 200 | if (!filenames) { 201 | return request(reqBody, responseCb); 202 | } 203 | 204 | filenames = Array.isArray(filenames) ? filenames : [filenames]; 205 | 206 | var files = 0; 207 | filenames.forEach(function(filename, index) { 208 | files++; 209 | fs.readFile(filename, function(err, data) { 210 | if (err) { 211 | return cb(err); 212 | } 213 | 214 | files--; 215 | multipart.push({ 216 | 'content-disposition': 'form-data; name="filename[]"; filename="' + path.basename(filename) + '"', 217 | 'content-type': (mime.lookup(filename) || 'application/octet-stream'), 218 | body: data 219 | }); 220 | if (files === 0) { 221 | return request(reqBody, responseCb); 222 | } 223 | }); 224 | }); 225 | 226 | }; 227 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # node-phaxio 2 | 3 | Send faxes with [Phaxio](http://www.phaxio.com). It's completely asynchronous. 4 | 5 | If you perfer a promised based api, take a look at our fork [phaxio-promise](https://github.com/reconbot/node-phaxio-promise) 6 | 7 | ## Installation 8 | 9 | `npm install phaxio` 10 | 11 | ## Usage overview 12 | 13 | ```javascript 14 | var Phaxio = require('phaxio'), 15 | phaxio = new Phaxio('e222........................', '62e5........................'), 16 | callback = function(err,data){console.log(data);}; 17 | 18 | phaxio.sendFax({ 19 | to: '13165555555', 20 | string_data: 'Faxing from Node.js', 21 | string_data_type: 'text' 22 | },callback); 23 | ``` 24 | Response 25 | ```javascript 26 | { success: true, 27 | message: 'Retrieved fax successfully', 28 | data: 29 | { id: '111111', 30 | num_pages: '0', 31 | cost: 0, 32 | direction: 'sent', 33 | status: 'queued', 34 | is_test: 'true', 35 | requested_at: 1344829113, 36 | recipients: [ { number: '13165555555', status: 'queued' } ] 37 | } 38 | } 39 | 40 | ``` 41 | 42 | ## Constructor 43 | 44 | ### new Phaxio(key, secret); 45 | 46 | Returns a phaxio object with your keys set on the object. 47 | 48 | ## Methods 49 | 50 | ### phaxio.sendFax(options, callback); 51 | 52 | ```javascript 53 | opt = { 54 | // always required can be an array of a single string 55 | to = ['xxxxxxxx', 'xxxxxxxxx'], 56 | // one of these is required 57 | filenames = ['path','path','path'], 58 | string_data = 'String of data for phaxio to parse' 59 | //optional 60 | string_data_type: '', 61 | batch: "and othe phaxio options" 62 | } 63 | 64 | phaxio.sendFax({ 65 | to: '13165555555', 66 | filenames: ['coverletter.doc', 'resume.pdf'] 67 | }, function(err,res) { 68 | console.log(res); 69 | }); 70 | 71 | phaxio.sendFax({ 72 | to: '13165555555', 73 | string_data: 'http://www.google.com/', 74 | string_data_type: 'url' 75 | }); 76 | 77 | var batchID; 78 | phaxio.sendFax({ 79 | to: ['13165555555', '19135555555'], 80 | filenames: 'my-cat.jpg', 81 | batch: true 82 | }, function(err,res) { 83 | if(res.batchId){ 84 | batchId = res.batchId; 85 | } 86 | }); 87 | ``` 88 | 89 | ### phaxio.cancelFax(faxId, callback) 90 | 91 | Cancels the fax `faxId` 92 | ```javascript 93 | phaxio.cancelFax('123456', function(err, res) { 94 | console.log(res); 95 | }); 96 | ``` 97 | 98 | ### phaxio.faxStatus(faxId, callback) 99 | 100 | Returns the status of `faxId` 101 | ```javascript 102 | phaxio.faxStatus('123456', function(err, res) { 103 | console.log(res); 104 | }); 105 | ``` 106 | 107 | ### phaxio.fireBatch(batchId, callback) 108 | 109 | Fires the batch `batchId` 110 | ```javascript 111 | phaxio.fireBatch(batchId); 112 | ``` 113 | ### phaxio.closeBatch(batchId, callback) 114 | 115 | Closes the batch `batchId` 116 | ```javascript 117 | phaxio.closeBatch('123456'); 118 | ``` 119 | ### phaxio.provisionNumber(options, callback); 120 | 121 | Provisions a number in area code `area_code` 122 | ```javascript 123 | phaxio.provisionNumber({ 124 | area_code: '212', 125 | callback_url: 'http://localhost/' 126 | }, function(res) { 127 | console.log(res); 128 | }); 129 | ``` 130 | ### phaxio.releaseNumber(number, callback) 131 | 132 | Releases the number `number` 133 | ```javascript 134 | phaxio.releaseNumber('8475551234', function(err, res) { 135 | console.log(res); 136 | }); 137 | ``` 138 | ### phaxio.numberList([options,] callback) 139 | 140 | Returns user phone numbers matching optional params `area_code` or `number` 141 | ```javascript 142 | phaxio.numberList(function(err, res) { 143 | console.log(res); 144 | }); 145 | 146 | phaxio.numberList({ area_code: '847' }, function(err, res) { 147 | console.log(res); 148 | }); 149 | ``` 150 | ### phaxio.accountStatus(callback) 151 | 152 | Returns the account status 153 | ```javascript 154 | phaxio.accountStatus(function(err, res) { 155 | console.log(res); 156 | }); 157 | ``` 158 | ### phaxio.testReceive(options, callback) 159 | 160 | Simulates receiving a fax containing the PhaxCode in `filename` with optional params `from_number` and `to_number` 161 | ```javascript 162 | phaxio.testReceive({filenames: 'PhaxCode.pdf'}, function(err, res) { 163 | console.log(res); 164 | }); 165 | 166 | phaxio.testReceive({ 167 | from_number: '3165555555', 168 | to_number: '9135555555', 169 | filenames: 'PhaxCode.pdf' 170 | }, function(err, res) { 171 | console.log(res); 172 | }); 173 | ``` 174 | 175 | ### phaxio.attachPhaxCodeToPdf(options, callback) 176 | 177 | Returns a PDF of `filenames` with a PhaxCode at the `x`,`y` location specified with optional params `metadata` and `page_number` 178 | ```javascript 179 | phaxio.attachPhaxCodeToPdf({ 180 | filenames: 'resume.doc', 181 | x:0, 182 | y:5 183 | },function(err, buffer) { 184 | fs.writeFile(path.join(__dirname, 'resume-with-PhaxCode.pdf'), buffer, 'binary'); 185 | }); 186 | 187 | phaxio.attachPhaxCodeToPdf({ 188 | filenames:'kittens.pdf', 189 | x:5, 190 | y:25, 191 | metadata: 'Fax with kittens', 192 | page_number: 5 193 | }, function(err, buffer) { 194 | fs.writeFile(path.join(__dirname, 'kittens-with-PhaxCode.pdf'), buffer, 'binary'); 195 | }); 196 | ``` 197 | ### phaxio.createPhaxCode([options,] callback) 198 | 199 | Creates a new PhaxCode with optional `metadata` param and returns the URL or returns a PDF if optional `redirect` param is true 200 | ```javascript 201 | phaxio.createPhaxCode(function(err, res) { 202 | console.log(res); 203 | }); 204 | 205 | phaxio.createPhaxCode({ metadata: 'Awesome', redirect: true }, function(err, buffer) { 206 | fs.writeFileSync(path.join(__dirname, 'Awesome-PhaxCode.pdf'), buffer, 'binary'); 207 | }); 208 | ``` 209 | ### phaxio.getHostedDocument(options, callback) 210 | 211 | Returns the hosted document `name` with a basic PhaxCode or custom PhaxCode if `metadata` is set 212 | ```javascript 213 | phaxio.getHostedDocument({name:'order-form'}, function(err, buffer) { 214 | fs.writeFileSync(path.join(__dirname, 'order-form.pdf'), buffer, 'binary'); 215 | }); 216 | 217 | phaxio.getHostedDocument({ 218 | name:'order-form', 219 | metadata: 'Referred by Chad Smith' 220 | }, function(err, buffer) { 221 | fs.writeFileSync(path.join(__dirname, 'order-form-with-referral-code.pdf'), buffer, 'binary'); 222 | }); 223 | ``` 224 | ### phaxio.faxFile(options, callback) 225 | 226 | Returns the thumbnail or PDF of fax requested, optional `type` specifies _p_df (default), _s_mall or _l_arge thumbnail 227 | ```javascript 228 | phaxio.faxFile({id:'123456'}, function(err, buffer) { 229 | fs.writeFileSync(path.join(__dirname, 'fax-123456.pdf'), buffer, 'binary'); 230 | }); 231 | 232 | phaxio.faxFile({ 233 | id:'123456', 234 | type:'l' 235 | }, function(err, buffer) { 236 | fs.writeFileSync(path.join(__dirname, '123456.jpg'), buffer, 'binary'); 237 | }); 238 | ``` 239 | ## TODO 240 | 241 | * Receiving [fax callbacks](http://www.phaxio.com/docs/api/receive/receiveCallback) 242 | * Support for [faxList](http://www.phaxio.com/docs/api/general/faxList) 243 | 244 | See the [issue tracker](http://github.com/chadsmith/node-phaxio/issues) for more. 245 | 246 | ## Author 247 | 248 | [Chad Smith](http://twitter.com/chadsmith) ([chad@nospam.me](mailto:chad@nospam.me)). 249 | [Francis Gulotta](http://twitter.com/reconbot) ([rbrtr.com](http://www.rbrtr.com)) 250 | 251 | ## License 252 | 253 | This project is [UNLICENSED](http://unlicense.org/) and not endorsed by or affiliated with [Phaxio](http://www.phaxio.com). 254 | --------------------------------------------------------------------------------