By Michael Chen · Published July 20, 2026 · Updated July 20, 2026 · 9 min read
Quick Answer: A fax SDK is a language-specific library that wraps a fax REST API. Most developers working with the mFax API skip an SDK entirely — the send endpoint is a single
POSTwith two fields. For providers like Phaxio and Telnyx, official SDKs exist for Node.js, Python, PHP, and Ruby if you prefer idiomatic wrappers.
When a developer searches for a "fax SDK," they usually want one of two things: a ready-made library they can npm install or pip install, or confirmation that an SDK is unnecessary for the API they're targeting. This guide covers both.
We'll compare the official SDK offerings from four fax API providers — mFax, Telnyx, Phaxio, and RingCentral — explain when a raw HTTP client beats a dedicated library, and show working code in Node.js, Python, and PHP for each approach.
If you're evaluating which fax API to use in the first place, see our fax API comparison first. If you already know you want the mFax API and just need copy-paste code, jump to the mFax code examples below.
What Is a Fax SDK?
A fax SDK (Software Development Kit) is a language-specific wrapper around a fax REST API. Instead of constructing raw HTTP requests, you call a function:
// Phaxio Node.js SDK
const phaxio = new Phaxio(apiKey, apiSecret);
await phaxio.faxes.create({ to: '+14155551234', content_url: fileUrl });// mFax API — no SDK needed
const form = new FormData();
form.append('to', '+14155551234');
form.append('file', fileBuffer, 'document.pdf');
await fetch('https://developers.mfax.to/v1/faxes', {
method: 'POST',
headers: { 'Authorization': 'Bearer zk_live_...' },
body: form,
});SDKs provide benefits like typed response objects, automatic retry logic, and idiomatic method names. They also add a dependency, an extra abstraction layer, and occasional version-lag when a provider updates their API.
Use an SDK when:
- Your language is officially supported and the SDK is actively maintained
- You're sending many faxes and want built-in retry/rate-limit handling
- Your team prefers typed interfaces to raw JSON responses
Skip the SDK when:
- The API is simple enough that HTTP calls are cleaner (mFax is a prime example)
- Your language isn't supported by an official library
- You want to minimize production dependencies
SDK Support by Provider
| Provider | Node.js | Python | PHP | Ruby | HIPAA BAA | Pricing |
|---|---|---|---|---|---|---|
| mFax API | fetch / axios | requests | Guzzle / cURL | Net::HTTP | Yes (all plans) | From ~$9/mo |
| Telnyx | telnyx (npm) | telnyx (pip) | — | telnyx (gem) | Yes (on request) | ~$0.007/page + DID |
| Phaxio (Sinch) | phaxio (npm, 2018) | phaxio (pip, 2017) | phaxio/phaxio (2019) | phaxio (gem, 2023) | Yes (free BAA) | ~$0.07/page + $2/mo number |
| RingCentral | @ringcentral/sdk | ringcentral (pip) | ringcentral-php | ringcentral-ruby | Yes (on request) | Custom |
The table above covers the four most common providers. "—" means no official SDK exists for that language; developers use standard HTTP clients instead. Dates next to the Phaxio packages are their last published release — see the Phaxio section for why that matters.
Go and .NET
Most fax providers under-invest in Go and .NET SDKs. For both languages, direct REST calls with
the standard library (net/http or System.Net.Http.HttpClient) are the practical path — and
work identically across providers.
mFax API — No SDK Required
The mFax API is the simplest fax API to integrate. The send endpoint accepts only two fields — to (the recipient's fax number in E.164 format) and file (your PDF) — which means a raw HTTP request is shorter and clearer than any SDK wrapper would be.
API base URL: https://developers.mfax.to/v1
Auth: Authorization: Bearer zk_live_… (created in your mFax Business dashboard)
Node.js (fetch)
import { readFile } from 'node:fs/promises';
import FormData from 'form-data';
const form = new FormData();
form.append('to', '+14155551234');
form.append('file', await readFile('invoice.pdf'), 'invoice.pdf');
const res = await fetch('https://developers.mfax.to/v1/faxes', {
method: 'POST',
headers: {
'Authorization': 'Bearer zk_live_YOUR_API_KEY',
...form.getHeaders(),
},
body: form,
});
const { uuid, status } = await res.json();
console.log('Fax queued:', uuid, status); // "queued"Python (requests)
import requests
with open('invoice.pdf', 'rb') as f:
response = requests.post(
'https://developers.mfax.to/v1/faxes',
headers={'Authorization': 'Bearer zk_live_YOUR_API_KEY'},
files={'file': ('invoice.pdf', f, 'application/pdf')},
data={'to': '+14155551234'},
)
fax = response.json()
print(fax['uuid'], fax['status']) # "queued"PHP (Guzzle)
use GuzzleHttpClient;
$client = new Client();
$response = $client->post('https://developers.mfax.to/v1/faxes', [
'headers' => ['Authorization' => 'Bearer zk_live_YOUR_API_KEY'],
'multipart' => [
['name' => 'to', 'contents' => '+14155551234'],
['name' => 'file', 'contents' => fopen('invoice.pdf', 'r'),
'filename' => 'invoice.pdf'],
],
]);
$fax = json_decode((string) $response->getBody(), true);
echo $fax['uuid'] . ' — ' . $fax['status'];Tracking Delivery
After sending, poll GET /v1/faxes/{uuid} until status becomes delivered or failed. For production, configure a webhook instead — set the endpoint URL in your mFax Business dashboard and listen for fax.delivered and fax.failed events.
const statusRes = await fetch(`https://developers.mfax.to/v1/faxes/${uuid}`, {
headers: { 'Authorization': 'Bearer zk_live_YOUR_API_KEY' },
});
const { status, failure_reason } = await statusRes.json();
// status: "queued" | "sending" | "delivered" | "failed"mFax API access is included on every mFax Business plan — no separate API pricing, no additional sign-up. Plans start from around $9/mo (billed annually) and include a virtual fax number, HIPAA compliance with a signed BAA, and team seats.
Telnyx — Official SDKs for Node.js, Python, Ruby, Go
Telnyx publishes maintained official SDKs for four languages. The SDK wraps their full communications platform — voice, messaging, and fax — so it is more complex to set up than a dedicated fax library.
Install:
npm install telnyx # Node.js
pip install telnyx # Python
gem install telnyx # Ruby
go get github.com/team-telnyx/telnyx-go # Go
Node.js
const Telnyx = require('telnyx');
const telnyx = new Telnyx('KEY01...');
const fax = await telnyx.faxes.create({
connection_id: 'YOUR_CONNECTION_ID', // required: your Telnyx Fax Application ID
to: '+14155551234',
from: '+18005559876', // your Telnyx DID
media_url: 'https://yourhost.com/invoice.pdf',
});
console.log(fax.data.id, fax.data.status);Telnyx requires a Connection ID and DID
Unlike mFax and Phaxio, Telnyx requires you to provision a Fax Application (Connection ID) and a dedicated phone number (DID) before you can send a single fax. Add 20–30 minutes of setup for new accounts. The per-page rate (~$0.007) is the lowest of any provider, but the setup complexity — and a BAA you have to request through sales rather than sign yourself — makes it less convenient for smaller healthcare teams.
Python
import telnyx telnyx.api_key = 'KEY01...' fax = telnyx.Fax.create( connection_id='YOUR_CONNECTION_ID', to='+14155551234', from_='+18005559876', media_url='https://yourhost.com/invoice.pdf', ) print(fax.id, fax.status)
Best for: High-volume outbound faxing where per-page cost matters most and you already have a Telnyx account for other communications (voice/SMS).
Phaxio (Sinch Fax) — Broadest Language Coverage, Aging Libraries
Phaxio has official packages for all four major web backend languages — the broadest coverage of any fax-specific provider. The catch is maintenance. Phaxio is now part of Sinch, and new integrations are pointed at the Sinch Fax API, with a documented migration path from Phaxio v2.1. The legacy client libraries have not kept pace:
| Package | Latest release |
|---|---|
phaxio (npm) | 1.0.0 — July 2018 |
phaxio (PyPI) | 0.3 — September 2017 |
phaxio/phaxio (Packagist) | 2.0.2 — March 2019 |
phaxio (RubyGems) | 2.1.2 — November 2023 |
The API these wrap still works, and the Ruby gem is the only one maintained in recent years. For a new build, call the REST API directly rather than pinning a library that last shipped in 2017.
Install:
npm install phaxio # Node.js
pip install phaxio # Python
composer require phaxio/phaxio # PHP
gem install phaxio # Ruby
Node.js
const Phaxio = require('phaxio');
const phaxio = new Phaxio('API_KEY', 'API_SECRET');
const fax = await phaxio.faxes.create({
to: ['+14155551234'],
content_url: 'https://yourhost.com/invoice.pdf',
// or use file with a Buffer for local files
});
console.log(fax.id, fax.status); // "queued"PHP
require 'vendor/autoload.php';
use PhaxioPhaxio;
$phaxio = new Phaxio('API_KEY', 'API_SECRET');
$fax = $phaxio->faxes->create([
'to' => '+14155551234',
'content_url' => 'https://yourhost.com/invoice.pdf',
]);
echo $fax->id . ' — ' . $fax->status;Pricing: 7¢ per page for US and Canada, 10¢ international, plus $2/mo per phone number. There is no monthly minimum. The BAA is free to sign in the dashboard — no enterprise contract and no minimum spend, which makes it one of the most accessible HIPAA-ready fax APIs for a small healthcare team.
Best for: Ruby shops that want an idiomatic wrapper, and any project with unpredictable volume that benefits from pay-per-page with a free BAA.
RingCentral — Broadest Language Coverage, Enterprise Complexity
RingCentral's SDK covers the most languages — Node.js, Python, PHP, Ruby, Go, and .NET — and fax is one feature among many in their unified communications platform. The fax endpoint is part of their REST API, but the SDK's authentication flow (OAuth 2.0 with JWT or authorization code grant) adds setup overhead compared to simpler bearer-token APIs.
Install:
npm install @ringcentral/sdk # Node.js
pip install ringcentral # Python
composer require ringcentral/ringcentral # PHP
import SDK from '@ringcentral/sdk';
const rc = new SDK({
server: SDK.server.production,
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
});
await rc.platform().login({ jwt: 'YOUR_JWT_TOKEN' });
const FormData = (await import('form-data')).default;
const form = new FormData();
form.append('json', JSON.stringify({
to: [{ phoneNumber: '+14155551234' }],
faxResolution: 'High',
}), { contentType: 'application/json' });
form.append('attachment', fs.createReadStream('invoice.pdf'));
await rc.platform().post(
'/restapi/v1.0/account/~/extension/~/fax',
form
);RingCentral setup overhead
RingCentral requires registering an application in their developer portal, obtaining OAuth credentials, and either implementing an authorization flow or generating a JWT token. For a pure fax integration, this is considerable overhead versus a simple bearer-token API like mFax.
Best for: Enterprises already standardized on RingCentral's communication platform who want to add fax to an existing RingCentral integration.
SDK vs. Direct REST: Which Should You Use?
The right answer depends on your language and provider:
| Scenario | Recommendation |
|---|---|
| Using mFax API (any language) | Direct REST — the API has 2 fields; no SDK needed |
| Node.js or Python + Telnyx | Use the official SDK |
| PHP or Ruby + Phaxio | Use the official SDK |
| Go or .NET (any provider) | Direct REST with standard HTTP client |
| New integration, uncertain provider | Start with mFax API — switch later if needed |
| HIPAA required on a budget | mFax Business (BAA on every plan, from ~$9/mo) |
The practical rule: use a direct REST call unless the provider's SDK meaningfully reduces your code. The mFax API is the clearest example — the SDK would be 50 lines of wrapper for a 10-line fetch call.
Handling Webhooks (All Providers)
Every major fax API sends delivery receipts via webhooks. The event payload contains the fax ID, status, and failure reason. Register your webhook URL in the provider dashboard, then handle POST requests from the provider:
app.post('/webhooks/fax', (req, res) => {
const { event, data } = req.body;
if (event === 'fax.delivered') {
console.log('Fax delivered:', data.uuid);
} else if (event === 'fax.failed') {
console.error('Fax failed:', data.uuid, data.failure_reason);
// failure_reason: "user_busy" | "no_answer" | "no_fax_signal" | "number_out_of_service"
}
res.status(200).send('ok');
});The mFax API signs webhook payloads with an X-Zelda-Signature header (HMAC-SHA256 over "<timestamp>.<rawBody>"). Verify the signature before processing to prevent spoofed events.
For a complete fax API integration walkthrough — including error handling, retry logic, and environment variables — see our how to send a fax via API guide.
Choosing the Right Fax API + SDK
Here's the shortest decision path:
- Need HIPAA without negotiating a contract? → mFax Business (BAA on every plan) or Phaxio/Sinch Fax (free BAA in the dashboard)
- Lowest per-page cost? → Telnyx (~$0.007/page, BAA on request)
- Ruby with a maintained SDK? → Phaxio (the
phaxiogem is the freshest of their libraries) - Already on RingCentral? → RingCentral SDK
- Everything else → mFax API — one endpoint, two fields, zero SDK setup
For a deeper comparison of API pricing and provider reliability, see the best fax API guide and fax API pricing breakdown.
Get Started with the mFax API
mFax Business includes API access on every plan — no separate developer tier, no extra fees. Build your own plan with the live calculator at mfax.to/business: set exactly the seats and monthly pages you need, from about $9/mo (billed annually). HIPAA compliance, a signed BAA, a virtual fax number, and the full API are included from the first dollar.
Browse the full API reference at developers.mfax.to and send your first fax in under five minutes — no SDK install, no complex auth flow, just a Bearer token and a POST.