Javis OS
Javis OS는 기업가를 돕는 에이전시 AI로, 업무를 지원하고 함께 성장합니다
문서 표현·인코딩·프로토콜·운송료·수신자 상태까지 통합한 팩스 비용 최적화
Joint fax-cost optimization across document representation, MH/MR/MMR/JBIG encoding, T.30/T.38 protocols, carrier tariffs and verified recipient state.
비즈니스Python · TypeScriptGitHub @DMontgomery40온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Self-hosted, open source, fax-sending API. HIPAA compliant. This fax API includes MCP (Model Context Protocol) support for AI assistant integration.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Faxbot is a proprietary, self-hosted fax platform with a web Admin Console, a REST API, cloud and SIP providers, and integrations for AI assistants. It helps organizations send and receive documents, choose delivery routes, track costs, and deliver incoming documents to the inboxes staff already use.
This README describes the current source checkout. Published packages and deployed installations may have fewer features; the roadmap distinguishes implemented capabilities from planned work and experiments.README 전문 보기 ↗Faxbot is a proprietary, self-hosted fax platform with a web Admin Console, a REST API, cloud and SIP providers, and integrations for AI assistants. It helps organizations send and receive documents, choose delivery routes, track costs, and deliver incoming documents to the inboxes staff already use.
This README describes the current source checkout. Published packages and deployed installations may have fewer features; the roadmap distinguishes implemented capabilities from planned work and experiments.
New Faxbot-owned work requires prior written permission from David Montgomery for use, modification, distribution, resale, or hosting. Contact [email protected] for permission. The setup instructions below are for authorized users. See LICENSE for the terms.
Earlier MIT releases retain their existing permissions, including material already released on public development branches. LICENSE-MIT preserves that notice; it does not license new proprietary additions. Third-party components keep their own licenses.
TELNYX_API_KEY, what Telnyx billed for each sent and received trunk call, separately from delivery status. Unknown charges stay unknown and a route with an unknown cost is never called the cheapest. A sent fax or received call with no charge and no estimate (for example an answered call whose length was never reported) is left out of every total and counted as "not priced yet" beside it, never as $0. See delivery routes.faxbot faxes received owners give each received document an owner who acknowledges it and marks it done, with an optional operational acknowledgement target per installation or mailbox, one escalation to a backup person, and a per-item evidence export. An owner must already be able to see the document; assignment never grants access. See Owners in Received.faxbot faxes expected record a fax before it arrives: its reference (such as PO 483), what should come, from whom and by when. Faxbot closes it only when a received fax carries that exact reference in its subaddress, a partner's registered form, a Direct message it answers or an email subject pattern you set; a fax from a known number, partner or address is only proposed for you to confirm. Open work can be imported from another system's CSV or JSON export, and after that system's outage the next export is sorted into already done, new and held for you. See Expected faxes.The API serves the console at /admin/ui/. Its left panel has six areas, each page at its own address (such as #/delivery/trunk), and Send a fax at the top for people who may send:
Every address from before the six areas still opens the page that does that job now, with its query, and says once where the page moved from. An address that names no page, or a page you may not open, shows its own short message instead.
Screens follow the signed-in user's permissions, use plain words outside Developer, and show settings only the owner may change disabled to everyone else. See the console guide and Setup Wizard.
Copy the bootstrap configuration:
cp .env.example .env
Replace the example credentials, set a strong installation API_KEY, and choose a provider using its setup guide. For an initial document-only evaluation, set FAX_DISABLED=true before the first startup: jobs remain held and are not reported as successful transmissions.
Set the public URL and console origins for your deployment. Console sessions require HTTPS. For an HTTP-only Docker evaluation on a trusted private network, explicitly set FAXBOT_ALLOW_INSECURE_HTTP_SESSIONS=true; see authentication for the transport requirements.
Build and start the API and console:
docker compose up -d --build api
SIP/Asterisk installations also need the asterisk service and a configured trunk; follow the Asterisk guide.
Open http://localhost:8080/admin/ui/ for a local HTTP evaluation, or /admin/ui/ on your configured HTTPS address. Sign in with the installation key to create the first owner, then use a named account for daily work.
Health checks are available at /health and /health/ready. /health/ready answers 200 when Faxbot is ready for what it is set up to do (sending, receiving or both) and 503 otherwise, the same rule faxbot admin health uses for its exit code. Readiness does not prove that a fax has been delivered. Faxbot starts even when it cannot sign in to its fax engine (Asterisk): readiness, the dashboard and Settings give the reason in one sentence, sends are refused with it, and Faxbot keeps trying. The Compose file restarts the api and asterisk services after any exit, including Restart Faxbot in the console.
Credentials in .env (provider keys, passwords and secrets) are read at every start and are the values in force; the console shows them as Set in .env and they are changed there, followed by docker compose up -d (a plain docker compose restart keeps the old values). API_KEY (the installation key) is read only at the first start, and other settings are managed in the console after that. Follow any requested restart (Settings offers Restart now) and confirm the active settings before transmitting. Held test jobs remain held when sending is enabled later.
Open Administration → AI analysis to choose OpenAI, OpenRouter, or another OpenAI-compatible API. Enter the API base address, model identifier and API key, save them, and test the connection. The owner can then enable analysis and choose a refresh interval; zero means manual refresh only. Keys are encrypted with the installation's existing secret storage and are never returned in full to the console or command line.
Run analysis queues a saved report. The model can read bounded operational evidence about outbound delivery outcomes, attempt costs and calls avoided. It receives no fax documents, fax numbers or saved provider credentials. It cannot send a fax or change settings. Existing cost calculations and rule-based recommendations continue to update from records without an LLM. AI advice is additional interpretation; estimates, reported charges and settlements remain separate, and the analysis does not claim to total subscriptions, inbound charges or unmatched bills.
The console shows when analysis last completed, its model and evidence, whether it is stale, and any refresh failure. A failed refresh keeps the previous successful report. The same controls are available with faxbot admin analysis configure, test, run and status; faxbot savings analysis reads the saved report. Use --key-prompt or --key-stdin when configuring the model key. No model provider is contacted until you enable analysis or explicitly test its connection.
Use the Python SDK or Node.js SDK to call Faxbot's API:
pip install faxbot
npm install faxbot
Another system can hand a PDF to the work queue with POST /imports and a small JSON manifest; see import documents. An email mailbox or a watched folder can do the same without any code, under Delivery setup → Email and folders (faxbot delivery connectors).
Faxbot's AI assistant servers (Node and Python) work over stdio and Streamable HTTP. The Python server also offers the older SSE transport, which is removed in the next release. Remote requests use the caller's own Faxbot identity. See MCP setup and transport authentication.
The faxbot command does what the Admin Console does, apart from its built-in terminal, under the same six areas: after faxbot send and faxbot status come overview, savings, faxes, delivery, recipients and admin. The command names from before the six areas (received, sent, forms, expected, numbers, providers, costs, access and system, and renamed commands such as costs savings) still work, hidden from help, so scripts keep running. Every setting can be read and changed with faxbot admin settings. Output is readable by default and --json for scripts.
docker compose exec api faxbot admin health
FAXBOT_API_KEY=... faxbot send +15551234567 referral.pdf
With Faxbot stopped, faxbot admin recover-owner, backup, restore and migrate recover owner access, back up and restore an installation, and upgrade its database. See Command line and the command reference.
The iOS companion connects to your Faxbot server to send faxes and check status. Pair it with a short-lived, single-use code from the console. See the iOS guide for setup and TestFlight invitations.
Contributions should keep the console usable, preserve provider capability checks, and update the README, roadmap, and affected operator documentation in the same change as the capability.
Reference pages under docs/generated/ are generated from code. The README/roadmap, agent instructions and planning sources are maintained separately. AI prose proposals are restricted to permitted documentation pages, including when applied locally.
Checked items are implemented in the current source checkout. Unchecked items are planned or require validation; they are not claims about a release date or measured savings.
Destination-aware prices agree across recipient recommendations, plan allowances and attempt estimates. Unknown international prices stay unknown, separate destination tariffs do not consume domestic allowances, and extra provider accounts retain their own applicable rate cards. Verified with synthetic routing, HTTP and accounting checks; this correction does not claim a joint optimizer over every document, account, batch and sending time.
Opt-in operational AI analysis with encrypted OpenAI-compatible credentials, OpenRouter support, bounded read-only evidence tools, durable manual and scheduled refreshes, visible freshness/failure state, and matching console/CLI controls. Verified with synthetic data and mocked model responses; live model-provider validation is separate.
Number dependency answers and checked move plans are available in Delivery setup → Number moves and faxbot delivery numbers advice, dependencies and move. Record account readiness, carrier cutover and receipt tests, review evidence, and finish or abandon the plan. Faxbot does not place a port order or send a receipt-test fax automatically.
Durable outbound jobs, uncertain-outcome handling, server-side idempotency, and held test jobs.
Database validation avoids repeatedly rebuilding superseded schema descriptions. Historical upgrades, unknown-schema refusal, and all table, column and index checks remain in place.
Users, groups, roles, scoped keys, sessions, mailbox access, and single-use mobile pairing.
Cost-aware route selection, versioned rate cards, attempt costs, and separate reconciliation of the charges SignalWire, Sinch and Phaxio report for each sent fax. Sinch's and Phaxio's charges are read only once the provider says the fax is finished, with the account that sent it; a later different price is a correction, and a fax with no reported price stays unpriced, never $0 or the estimate.
Sinch Fax API as a sending route beside the SIP trunk and HumbleFax, ranked by its published $0.045 a page and then by what it really cost per delivered fax. A send Sinch refuses (key, project, balance, number or document, or a request to slow down) or that never reached Sinch fails for certain and goes by the next route with Sinch's reason; any other lost answer waits for a person and is never sent again. A Sinch failure takes another route only when no page can have arrived. The Sinch page and give the exact Incoming webhook URL to paste into Sinch, from the server's public address or a separate address for Sinch, and where a user name and password go in it. Tested with simulated Sinch and Phaxio APIs; the live send, receipt and charges are pending.
Fax servers through Faxbot, live: the SR140 stand-in sending to the partner install as its gateway (an accepted fax delivered over Telnyx, the refusals for a wrong password, an emergency number, a premium number, a country not allowed and a full hourly limit, and a failure notice), then a real RightFax server with an SR140 (FDTool on a Windows VM with its trial licence), checking its T.38 version and whether its Primary Gateway mode answers the digest challenge.
An analog line and keys after answer, live: one gateway on one flat-rate line with a local and a toll call checked against the next carrier bill, and one real phone menu reached with keys after answer. A V.34 (33.6 kbit/s) fax modem is reachable only on such a line: a hardware Class 1.0 modem under HylaFAX+ (Class1EnableV34Cmd) in place of the gateway. Faxbot's engines stop at V.17, and that hookup is a note, not something Faxbot sets up.
A live HISP: one Direct message each way with a real HISP account, with its certificate found in DNS or LDAP, the trust bundle checked, and the "processed" and "dispatched" confirmations received; and whether that HISP wants Faxbot or itself to sign and encrypt.
A live FHIR endpoint: a DocumentReference accepted by a real FHIR server through SMART Backend Services, with the public key set registered by its address; whether it takes the patient by medical record number, by a search or only after patient matching (and which details its matching needs), the document type and category it wants, and whether it also needs an encounter.
Live partner discovery: the acceptance install finds the partner Faxbot from a real call to it, through the partner's SSL Fax address (its CSA) and its /.well-known/faxbot-direct answer, and enrolls it with the challenge fax.
Live dense pages: a packed fax over Telnyx to a machine that takes unlimited length and to an A4-only one, a Faxbot-to-Faxbot packed fax split back on receipt, blank-bottom trimming to a machine without error correction, and one test fax per cloud provider (Sinch first) to see whether it sends a long page unchanged.
Several provider accounts at once, chosen for each fax by the organization's rules, in the console and the command line. The screens and commands are built and tested with synthetic data against the agreed API:
Future work will extend Faxbot from document delivery into accountable correspondence across industries. Build on existing access controls and delivery infrastructure, retaining separate inbound and outbound providers. The enterprise architecture maps implemented foundations, partial capabilities and proposed interfaces. This direction does not expand Phase 1 or the four fixes above.
POST /imports, faxbot faxes received import), a mailbox-scoped owned queue (owners in Faxes → Received, faxbot faxes received owners), operational acknowledgement targets with one escalation to a backup person, and a permission-scoped evidence export. Transport delivery, email delivery and acknowledgement remain separate events. Tested with synthetic documents only; not validated against a customer system. See Owners in Received.faxbot faxes expected hold an expectation (reference, what is expected, from whom, owning mailbox, due time as an operational target) before anything arrives. Only a stable reference closes one: the exact reference in the fax subaddress, a partner's registered form field, a Direct message ID or the message it answers (In-Reply-To, References), or an email subject pattern the admin saves. A known sender's number, partner or Direct address within the window, or text from an approved extraction, only proposes a match for a person. Required parts never close automatically, and a required revision closes only when the arrival states that revision. Overdue expectations escalate once to the mailbox's backup person. A saved CSV or JSON column mapping imports open work under the generic import's identity rules: replays add nothing, a changed row waits for review, a new revision replaces an open one, and rows a later full export no longer lists are reported and stay open. Outage mode records what was done by fax or email while a source system was down, against original IDs, and sorts the next export into already done, new and held lists; Faxbot never sends or submits anything for it. The report lists missing expectations and received faxes that answered nothing apart from the match rate, and each expectation has an evidence export. Matching runs when a received fax becomes work, so an idle installation does no matching. Migration 0064. Tested with synthetic data on SQLite and PostgreSQL; not run against a real ERP, EHR or partner yet, and no OCR or extraction service exists to call the proposal-only extraction entry point.Any control required by a selected real workflow is a prerequisite to using its records, regardless of stage number. Templates must state their scope, version, required settings, evidence and remaining organizational responsibilities. Customer-specific forms and integrations stay optional; these capabilities are not yet implemented as an enterprise workflow.
Enterprise software acceptance uses synthetic/local tests. Live customer end-to-end validation is separate and never a CI, merge or release requirement; see the testing boundary.
Collecting a fax by polling (T.30), so the site whose calls are cheaper places the call: Faxbot’s SSL Fax engine calls another site’s fax server once and collects the fax it holds for you, which lands in Received from that number. It is off for every number until you turn it on (a number's Details in Recipients, Collect faxes from this number, faxbot recipients polling NUMBER --on). Select Collect now, run faxbot recipients collect NUMBER, or set an optional timetable. The panel shows what the number sent you in the last 30 days and what your own phone line would pay to collect it. Each collection and result are kept (database revision 0059), and shared database claims prevent two server workers from collecting the same scheduled request. A missing or uncertain result blocks further manual and scheduled collections. A later confirmed receipt can resolve a missing result; a recorded uncertain result currently has no manual reconciliation control, so collection remains blocked for that number. Check Received and the fax engine before any further action. The other server’s polling password is kept encrypted and sent only with the call. Earlier loopback checks used a stock HylaFAX+ peer with nothing waiting to collect; no live external polling validation was performed during this recovery.
Holding a fax for another site to collect (polled transmission): Faxbot's SSL Fax engine can now be polled. With a number's Details in Recipients, Faxes this number collects from Faxbot turned on for a number (faxbot recipients hold NUMBER --on), you hold a document for it (faxbot recipients hold-fax NUMBER FILE, or the panel), optionally behind a selective polling address and a polling password that site must give; when that number calls, the engine offers the fax in its DIS and sends it when the caller asks for it (ITU-T T.30 DTC), so the other site pays for the call. Each held fax and what happened to it (collected by whom, refused for a wrong address or password, withdrawn) is kept (database revision 0062). The engine change is HylaFAX+ patch 0002 (hylafax/patches/); its held-document rules are tested at build time, and the loopback proves a collected fax lands in Received with identical pixels and that a wrong address is refused (case s). Not yet tried: a poller other than HylaFAX+ (the engine keeps HylaFAX's direction bit on the frames it sends after the turnaround, which HylaFAX+ and spandsp ignore), the T.38 path, and holding an ordinary send automatically for an opted-in number (today you hold a document on purpose).
Measure fax negotiation, lossless compression, and error-correction choices before enabling adaptive transport behavior. Measured now on every SIP trunk fax call, sent or received: the SSL Fax engine reports the starting and lowest speed, the number of trainings, compression, resolution and error correction for the whole call from its session log, and the built-in engine reports only the last page's speed and resolution; on a number's in , (and ) each call with a number is joined with the far machine's frames, which add the built-in engine's starting and lowest speed, trainings, compression and error correction. Anything an engine does not report is shown as not reported. Each fax's details on and say how its call went, and the trunk page under (and ) lists calls, success rate, seconds per confirmed page and calls per delivered fax for each compression, error correction and speed. A decision rule now uses these records per number, once its own calls show the same problem more than once: the starting speed steps down after failed trainings (both engines), the SSL Fax engine moves to the next more robust lossless compression after two failures in a row with one (JBIG, then MMR, MR, MH; the pages stay the same), and error correction is turned on where pages failed without it and the far machine supports it. It never turns error correction off or lowers resolution, a number's own limits always win, and each change has one sentence on the fax's details. The rule has run only on synthetic call histories; live negotiation data is still four SSL Fax engine calls over Telnyx T.38 (two received, two sent, on 2026-10-06), so this stays unchecked until live calls confirm it.
faxbot delivery providers callbacks The Telnyx Fax API as a sending route billed by the page, so a per-page route can be measured beside the trunk (by the minute) and HumbleFax (a flat plan). Faxbot uploads the pages each attempt chose to Telnyx's media storage and sends the fax by name, so Telnyx needs no link back to the server, then checks the fax's status with Telnyx until it is done. Busy, no answer, no fax machine and anything Telnyx refuses before the call fail for certain with a plain reason and may go by another route; a dropped call or any other reason waits for a person and is never sent again, and a lost answer to the send itself waits for its fax ID. Its published price, $0.007 a page plus the call's minutes at Telnyx's US outbound SIP rate ($0.005 a minute, whole minutes; telnyx.com/pricing/fax, read 13 October 2026), is its rate card, so route choice and estimates rank it with the others. A Telnyx Fax API account, and a trunk with the Telnyx preset, that has no rate card saved in Faxbot is priced by Telnyx's published price, and the estimate says whose price it is and when Faxbot read it ("Telnyx's published price, read 3 October 2026"; both pages read again on 13 October 2026, unchanged); a price you enter for the account always wins. Before, such an account read "none of your routes had a price" and cost routing could not rank it. It uses the Telnyx API key the trunk already has. The console's Telnyx Fax API page (choose it under Add or change a provider) and faxbot delivery providers accounts fax-application create the Fax Application in your Telnyx account and save its ID; faxbot delivery providers configure telnyx_fax and accounts add --provider telnyx_fax set it up from the command line. With Telnyx's public key saved, Telnyx's signed results notices make Faxbot check the fax at once. Route choice prices it from its card before each send, but a sent fax's own cost stays unknown (never $0) until Faxbot reads Telnyx's records of the call's length, which is next. It does not receive faxes yet. Tested with a simulated Telnyx API only; nothing has run against a real Telnyx account yet.
Your Telnyx balance, before it stops your faxes. With a Telnyx API key set (the trunk's key, which the Telnyx Fax API also uses), Faxbot reads your Telnyx balance every 15 minutes, again at once when a Fax API send fails because Telnyx turned the account off, and at once after a burst of calls the carrier refused (three SIP 404 or 403 refusals within five minutes, on the trunk's calls or the Fax API's; at most once every five minutes). When the credit available falls below the level you set (Delivery setup → Providers & accounts → Delivery routes, Warn when your Telnyx balance is below, or faxbot delivery providers trunk balance --warn-below 10), or, left empty, below a week of your usual Telnyx spending (Faxbot's own cost records for its Telnyx routes over the last four weeks, or $5 when it has none), Overview (Needs attention and the sending board) and faxbot overview say so in one sentence, such as "Your Telnyx balance is $3.10, about 4 days of your usual faxing. When it reaches $0, Telnyx stops your calls in both directions. Add funds in the Telnyx portal under Billing." At $0 or less, or when Telnyx reports the account turned off, the warning says sending and receiving through Telnyx have stopped, and Faxbot skips its Telnyx routes, so a fax goes by your next route and says why. A Fax API send Telnyx fails because the account is turned off is a certain failure before any page. On 13 October 2026 Telnyx turned an account off at -$1.38: calls to its numbers got SIP 404 and Faxbot showed nothing. Tested with a simulated Telnyx balance answer only.
Telnyx charges for every trunk call, sent and received: matched by SIP Call-ID or by a unique number-and-time match (ambiguous records stay unmatched and are counted; a full page of records without a page count is never taken as the whole window; a call settles only once every record matched to it is priced; a record Telnyx still has not priced a week after the call settles the call with that part marked never priced, so the fax reads "Telnyx charged $0.005 for part of this call and never priced the rest, so its full cost is unknown." and counts as never priced in full, never as the priced part alone. The week is Faxbot's own limit, because Telnyx documents no time by which a price is final (read 6 October 2026)), kept with corrections and never changing delivery; shown per route in Spending, in Sent's fax details and in Received, and with faxbot savings spending, reconcile and fax. Calls Telnyx billed that Faxbot has no record of (such as a received fax whose hand-over failed) count in spending on their own line and attach to the received fax when exactly one matches. Route recommendations never call an unknown cost the cheapest; a flat plan reads "Included in your HumbleFax plan ($10 a month)." and counts its fee once per 30 days. Each provider in use gets its published price (Phaxio, Sinch, SignalWire, HumbleFax, SIP trunk carriers; read 2026-10-03) as an editable rate card on start, and the Overview reads the same spending as Costs. Spending, the Overview and faxbot savings spending count faxes and calls with no price apart ("2 faxes and 1 call not priced yet") instead of adding them as $0, and calls the carrier never priced in full apart from those ("1 call never priced in full"; only its priced part is in the total). (Live on 3 October 2026: the sent calls' $0.01 and $0.005 and a received call's $0.0032 showed against the right faxes. Matching by the captured SIP Call-ID and the unrecorded-call sweep are tested with synthetic records only.)
Charges from every source Faxbot can read, and monthly invoices for the rest (Savings & optimization → Charges and Savings & optimization → Invoices, faxbot savings charges [sweep] and faxbot savings invoices add|list|show, migration 0051):
faxbot savings spending give each cloud provider its own received line, apart from the trunk's calls ("Received faxes: Sinch $0.42 for 6 faxes"), with estimates from the receiving price where nothing was reported and a flat plan's faxes as included. A fax with no price is counted as not priced yet, never $0.FLOWROUTE_ACCESS_KEY and FLOWROUTE_SECRET_KEY on the Flowroute trunk page. Gamma, BT One Voice and Telstra SIP Connect publish no call-record API that Faxbot could find (searched 8 October 2026), and their trunk pages send you to Savings & optimization → Invoices instead. Shared intake queue and SMTP email delivery, with console management. Each delivered email keeps the addresses the email server accepted, at that moment; Faxes → Received, faxbot faxes received deliveries list and the evidence export name them, and say plainly when an email from before migration 0022 has none recorded. They never show the connector's addresses today in their place.
Enrolled direct partners, encrypted original-PDF delivery, signed receipts, and controlled fax fallback.
Recipient-approved case packets, accepted-document history, and preview, in the console (Faxes → Case packets, with the recent cases listed) and through the API (GET /cases).
Case documents carry their source, version and purpose. The same file sent for another purpose, or labelled as a newer version, is a separate entry. Fax success makes a document "delivered". It becomes "acknowledged" only through a partner's signed receipt, the receiving team acknowledging a packet delivered to one of your own numbers, a received acknowledgement fax, or a person's note. Acknowledgements expire after each recipient's reuse period (90 days unless set; it can also be unlimited). "Recipient couldn't find it" sends a document in full next time. Repair: send the full packet resends every kept original as a new fax, for a reason a person records; Faxbot never does this on its own. Kept originals follow Keep sent fax files in Storage & retention: the cleanup removes one once it has not been added or sent for that long, and a repair names each document retention removed. All of this is in Faxes → Case packets and faxbot faxes cases accept|invalidate|reuse|repair. Tested with synthetic data on SQLite and PostgreSQL, including the 188-to-56-page case example from the research. No real recipient has acknowledged a packet yet.
Case packets built from a recipient's checklist. A checklist lists document types, a version and a "dated within N days" limit for each, and whether each is required. Checklists are versioned and never change once saved. Faxbot picks from the originals kept in the case the same way every time and gives a reason for each pick, then lists the missing items. A person checks the selection before it is sent, and a required item can be left out only when the person says the recipient agreed. Suggestions for missing items compare titles and stay off unless the owner turns them on; no language model is connected. This is in Faxes → Case packets → Build a packet from a checklist and faxbot faxes cases add|originals|build|checklist|suggestions, with one synthetic example checklist. Real forms' checklists belong to integrations.
Savings & optimization → Savings results: calls saved by sending together, fax calls avoided by direct delivery and pages case packets did not send again, each marked an estimate, from GET /routing/savings and faxbot savings results. Case packets count from when Faxbot started recording what each packet left out. A saving that cost more, such as a shared call billed above what separate calls would have cost, is summed as it is and said plainly ("About $0.03 more spent than saved in the last 30 days."), never turned into $0. Route prices are worded in each card's own unit ("about $0.005 a minute, at least 1 minute"), and the Send preview estimates the document being sent ("About $0.01 for this 2-page fax"). Savings & optimization → Opportunities says what will appear there until it has something to suggest.
How Faxbot saves money, at the bottom of Overview and in faxbot savings mechanisms (GET /routing/savings/mechanisms): one catalogue (routing/mechanisms.py) of every way Faxbot saves money, from preparing the document to receiving, plus the advice you act on, each with whether it is on (and why not, including a switch Faxbot made itself), whether it works on this installation (and what it needs), how far it is proven (live call, test lab, or built and tested only) and whether it worked on your faxes in the last 30 days. The map shows no money: each card opens its own part of Savings & optimization → Savings results (new parts count lightened pages, faxes by their cheapest route or through a plan, partner relays, continuations, partner repairs, Direct and FHIR deliveries and junk calls turned away, and compare seconds a page on fax over IP and audio fax), or its section of Savings & optimization → Opportunities. test_savings_mechanisms.py fails when a Savings part or Recommendations section has no entry. Tested with synthetic records on SQLite and PostgreSQL.
Savings & optimization → Capabilities and faxbot savings capabilities (GET /routing/capabilities, routing/capabilities.py): every mechanism in the catalogue, grouped by the outcome it serves (spend less on sending; smaller documents and shorter calls; avoid repeated calls and documents; work better with regular recipients; recover delivery with less waste; lower receiving and service costs; explain results and choose improvements). Each shows On or Off, Works here or Not here and how far it is proven, and is marked Ready to turn on when it is off but works here. The page filters by on, off, ready to turn on, needs something and experimental, and keeps the filter in its address (?show=ready, faxbot savings capabilities --filter ready). Each capability has its own page (?key=, faxbot savings capabilities show KEY): what it does, an example, what it needs (each prerequisite in place, missing, not needed yet or not checked yet, with who or what satisfies it and a link), where its setting lives with the command that changes it, and what it did here with a link to its figures. Every capability, in the list and on its own page, says what it did here, counted from this installation's own records (routing/capability_here.py for those with no part on Savings results): the faxes or calls it acted on in the last 30 days, the faxes your providers billed that Faxbot has no record of, or, for advice, how many suggestions its section has now. Where Faxbot keeps no record of what something did, the line says so. It never shows money. test_capabilities.py fails when a catalogue entry has no capability, and checks that every address opens a page and every command runs as shown. Tested with synthetic records on SQLite and PostgreSQL.
Cost per delivered fax for each number you fax, per route over the last 30 days. Every attempt counts toward the cost, failed and uncertain ones too: the carrier's or provider's charge where it was reported, otherwise the rate card applied to the call's measured duration and pages, with its minimum charge. Only delivered faxes divide it, and a flat plan reads "Included in your plan", never as a free route. The Recipients list shows it per route, a number's Details in Recipients adds each route's delivered share, average pages and average call time, and faxbot recipients list and show print the same. Once two reliable routes have each delivered 3 faxes to a number, Faxbot sends by the one that cost less per delivered fax and says so in one sentence, which Sent's details and faxbot faxes sent show repeat; a preferred route still wins, and nothing is ever sent again because of it. Savings & optimization → Opportunities and faxbot savings opportunities list numbers whose preferred route cost more than another route, or where a flat plan that already includes faxes has delivered to the number reliably, each with Use this route. The figures were checked by hand against a copy of the live install on 5 October 2026 (Telnyx to the one number with real traffic: 9 of 14 faxes delivered, $0.0089 per delivered fax). Choosing routes by them is proven with synthetic data only, because no number there has two metered routes yet. Negotiated speed and error correction are not part of the figure.
Sending together: short faxes to the same number share one SIP trunk call. It is off unless an operator records that the recipient agreed. A number holds faxes only on a trunk billed per call or with a minimum. Each number has a longest wait (default 10 minutes), a page cap (default 30) and a choice of whether different senders may share a call. Send now sends at once and takes the waiting faxes with it. Each document follows a separator page unless the recipient agreed to another way of marking documents (next line). Each fax keeps its own result, mapped from the call's confirmed pages, and nothing is sent again automatically. Sent's fax details show each fax's share of the charge, and the shares of one call add up exactly to its charge (largest remainder, in call order); the number's Details shows calls saved and an estimate of money saved. Available in the console, the API and faxbot recipients together. Tested with synthetic faxes and over a local T.38 test line (two faxes in one call, and a call cut after the first fax); a live combined call is pending. See sending together.
Fewer pages in a shared call: each number chooses how its shared calls mark each document, in the sending-together part of a number's Details in Recipients or with faxbot recipients set --index-page, --page-headers or --separator-pages. The choices are a separator page before each document (the default), one index page listing each document's page range, reference, page count and sender, or a line Faxbot adds above every page ("Document 2 of 5 · page 1 of 4 · reference · sender") with no page added. The last two save N−1 or N pages per shared call, and each needs the recipient's agreement, recorded with who and when. Cover sheets and barcode pages inside a document are always sent. Page marks are used only while the header text and sending number are set, because the fax engine's own header line above them must show the date, time, sender and sending number (47 CFR 68.318(d)); otherwise the call uses separator pages and the number's Details says why. Each fax's result is mapped against its call's page ranges. A call reported sent with a page missing leaves the faxes after the gap for a person, and nothing is sent again automatically. Charge shares follow each fax's own pages, and Savings & optimization → Savings results counts separator pages left out apart from calls saved. Migration 0025 adds the setting and each call's layout. Tested in synthetic form on SQLite and PostgreSQL (the rendered pages, outcomes, shares and savings); the live check comes at integration, with the owner's own HumbleFax number as the agreeing recipient.
Carrier SIP trunk presets with T.38, per-call records, and native faxes priced by the trunk carrier. Proven live over Telnyx on 3 October 2026: a two-page fax sent to a cloud fax line and a fax received back, both configured entirely in the console.
Fax over a SIP trunk from behind a router with no published or forwarded ports: Asterisk registers and starts every flow itself, with audio fax for new calls one click away when T.38 data cannot come back. Proven live in both directions from behind a home router in audio mode; over Telnyx, T.38 data did not come back through a router that changes port numbers.
Encrypted trunk registration by default, Faxbot's internet address found by STUN, and one plain sentence per trunk call (for example "no fax data came back from the carrier") in Recent calls, Sent, the Overview and faxbot delivery providers trunk.
faxbot command line covering the product, with stopped-server owner recovery, backup, restore, and database upgrades.
A busy database never costs a fax its result. On SQLite, Faxbot's database now runs in write-ahead-log mode, so console and API reads never wait for a write, and every commit is still flushed to disk before it counts. A fax result that finds the database busy is tried again up to three times over about 30 seconds, with each try logged and its cause. The built-in engine's results are saved in the order Asterisk sent them, without holding up the API. A busy database while a fax is being prepared, before its call, never fails the fax: it goes back to the queue for a moment, nothing is sent, and it then goes once. If a built-in engine fax's result is still lost, the fax waits for a person 45 minutes after its call started (a fax call's 30-minute limit plus a margin) ("Faxbot lost this call's result; check whether it arrived before sending again"), and it is never sent again by itself. A write that holds the database's write lock for more than 2 seconds is logged with where it ran. faxbot admin backup writes the database as one self-contained file, and restore removes a leftover -wal or -shm file before putting the copy in place. Tested with real lock contention on SQLite, and on PostgreSQL where it applies; not yet run on live traffic.
The command line follows the console's six areas: faxbot send and status, then overview, savings, faxes, delivery, recipients and admin, with plain help. The earlier group names (received, sent, forms, expected, numbers, providers, costs, access, system) and renamed commands (costs savings is now savings results, costs recommendations is savings opportunities, costs advice is savings facts, numbers reply is delivery identity, numbers npi is admin npi, providers rules is delivery rules, recipients cases is faxes cases) still work, hidden from help, as the same commands; the reference lists every command. Command names from before the console's areas (such as jobs and inbound) no longer work, and the release notes give the new name for each. faxbot admin settings set accepts every setting by name. Tests fail when a setting or an operator route is missing from the console or the command line. faxbot faxes received counts, delivery providers efax status, admin settings reload, recipients together check, savings received and savings plans --in-use read the same as the console; faxes sent evidence and faxes sent confirm-receipt show and settle an uncertain fax without sending it again; admin health ends with exit code 0 when Faxbot is ready for what it is set up to do (sending, receiving or both), so a receive-only install passes; the faxes received commands take either a received fax's ID or its owners-list ID.
How often Faxbot checks its internet address, the S3 bucket check in Diagnostics, the address phones use on your network and the documentation address are settings, changeable without a restart; an installation that set them in .env keeps its values. Each has its place in the console (the trunk page, Administration → System health, Administration → Keys & phones, Administration → Developer), as do the Telnyx charges key, console restarts, the plugin switches (Administration → Developer → Provider plugins) and the installation's time zone (the Setup wizard's first step).
The console follows six areas (Overview, Savings & optimization, Faxes, Delivery setup, Recipients, Administration), with group headings in Delivery setup and Administration, an address for every page, every setting at its mapped home and plain words outside Administration → Developer; a saved provider change shows the new names at once. Send a fax stays at the top of the panel for people who may send. All 52 earlier addresses, the older destination names and the provider pages open their new home with their query; an unknown address and a page you may not open each show their own message. See the console guide.
System in plain words: Audit log (who did what, filtered by person and action), the database in Diagnostics (kind, reachable or not, what it holds, and a warning for a file outside the data folder), Logs with plain column names, and environment-only settings shown read-only where they matter ("Set in .env" or "Not set", never a secret's value; GET /admin/settings deployment). Settings only the owner may change are shown disabled with one sentence to everyone else (owner_only), and Diagnostics' two switches apply separately. The API & SDKs quickstart installs the SDKs' current version.
Diagnostics that test what an administrator relies on, read-only: the sending and receiving accounts' sign-ins (HumbleFax, eFax), faxes waiting to be confirmed, the last fax each way, received faxes Faxbot stopped fetching, each email delivery's sign-in (no message sent), the fax engine and carrier trunk, disk space, records, time zone and security, each as one sentence with a button to the page that fixes it (faxbot admin diagnostics run|show). Scripts & checks under Administration → Developer adds one test fax, shows the address a receiving provider calls, and lists what the fax engine reports (trunk sign-ins, checked addresses, calls and faxes in progress; faxbot admin diagnostics engine). Server actions that could not run in the container (tunnel start and stop) are gone. The repository's helper scripts were each run against a live API: the received-fax helpers were rewritten (inbound-smoke.sh, inbound-watch.sh; read-only keys revoked on exit, no placeholder documents), the key demo never places a call, and four scripts that checked or edited .env for settings Faxbot no longer reads from it, or did one-time work, were removed.
One E.164 destination per fax, read for the installation country (UK and US), stored on the job, with versioned idempotent replays.
No blank TXT page from a final line break; one-bit TIFF pages stay one-bit in generated PDFs.
Stable send-operation ids in both SDKs, both MCP servers and the console, with an explicit resume path and no automatic resend.
Source-derived reference documentation and scoped AI prose proposals, with maintained planning outside the generated tree.
Credentials in .env read at every start (carrier names such as TELNYX_PASS accepted), shown as Set in .env; a new installation starts with no fax provider until one is chosen.
Setup Wizard chooses one provider for sending and one for receiving, shows one section per provider in use (the SIP trunk whenever it sends or receives) and saves each step as you move on, with Restart now when a change waits for a restart. Every screen and faxbot call each provider by one name, and the trunk by its carrier or phone system, such as Telnyx.
Apply and connect (and faxbot delivery providers trunk apply) writes the SIP trunk, restarts the Compose install's Asterisk to load it once no call is up, waits, and shows the trunk check on the same screen; no host shell is needed (tested with a simulated Asterisk manager; first live restart pending).
The Setup Wizard ends with an optional test: one test page sent only when asked and followed live to its outcome sentence and carrier cost, and a live wait for a fax sent to the installation's number (tested with simulated faxes; live test pending).
Audio fax chosen by Faxbot when T.38 cannot work: after a T.38 call gets no fax data back, or on a network that changes port numbers, new calls use audio fax and the switch says why, with Try T.38 again (the failed fax is never resent). The fax marker on outgoing calls is on by default, and readiness waits until a SIP trunk is set up for each direction that uses it.
Network for fax over IP: Faxbot checks its network at start, on Apply, every few minutes and on Check again, and tells where it runs (Colima on its own network, the Mac's shared network or directly on the local network; Docker Desktop; a computer behind a router; a cloud server; a server with its own address) and whether T.38 data can come back (port numbers kept or changed, an internet provider that shares addresses). T.38 turns itself off when it cannot and back on once the network is fixed (two checks in a row when unattended), never resending a fax; network open means T.38 is tried first and audio carries the fax when the carrier declines. Faxbot opens its fax ports on the router itself (PCP, then NAT-PMP, then UPnP; renewed, closed at stop, with a switch to turn it off), and with the fax ports published (docker-compose.fax-ports.yml) and the internet address entered it treats them as forwarded. The trunk page, the Setup wizard, the Overview, System diagnostics and faxbot delivery providers trunk network status|check|router-ports show it, with the exact fix per platform in Network for fax over IP; the Mac install creates Colima on the local network from the start. Proven live on 4 October 2026: after Colima was recreated on the local network, the start check turned T.38 back on by itself and a 2-page T.38 fax went through over Telnyx. Docker Desktop, cloud hosts and real router port opening are tested with fixtures and stand-in routers only.
Telnyx's fax over IP (T.38) setting checked per trunk number: with a Telnyx API key, Faxbot reads each number's T.38 fax gateway and its connection's T.38 re-invite source (read-only, at start, on Apply and on Check again) and says in one sentence on the trunk page, in Diagnostics and in faxbot delivery providers trunk status when a number would receive faxes as audio. Turn on T.38 (or faxbot delivery providers trunk telnyx t38-on NUMBER) changes only that number's T.38 gateway, keeping its other media settings, then reads it back; each change is audited, and a refusal gives the Telnyx portal steps. The setting was found off on the owner's number and turned on through the API by the lead on 5 October 2026 (verified live); Faxbot's own check and button are tested against a stand-in Telnyx only.
No hand-made shared secrets between Faxbot's containers: Faxbot creates the Asterisk manager password when the SIP trunk first comes into use and Asterisk picks it up by itself (a password in .env still wins), and the Setup Wizard says whether received faxes reach Faxbot instead of asking for the inbound secret (start-script and startup tests; live first boot pending).
A fax received over the SIP trunk always reaches Received: Faxbot creates the Asterisk inbound secret itself, a failed hand-over is logged and named in Recent calls, Check trunk status and the Overview, and an image that was never handed over is brought in automatically or with faxbot faxes received recover (tested with synthetic images; recovery of a live orphan pending).
Avaya IP Office and Aura as Your phone system: Faxbot connects as a SIP trunk on the local network. The phone system and Faxbot recognise each other by address, and the codec order follows the installation country. Numbers are dialled as a phone there dials them, with an outside-line prefix. The phone system override (docker-compose.phone-system.yml) publishes SIP and a small media range (default 20 ports; Asterisk refuses more than 100) on FAXBOT_LAN_ADDRESS only, and the console says what to give the administrator, with Avaya's checklist and sources. Tested with exact trunk files and a loopback proof: T.38 and audio faxes both ways to a stand-in phone system behind a simulated Docker host. Live Avaya sign-off pending.
UK and Australian carrier presets: Gamma, BT One Voice (new trunks start with audio fax because BT turns T.38 into audio) and Telstra SIP Connect, with the UK switch-off and BT's own fax statements in the setup guide. None publishes a price, so their rate cards say so. Tested against Faxbot's own Asterisk only; live BT, Gamma and Telstra sign-off pending.
eFax (US, UK and Australia) through the eFax Enterprise API: sending with eFax's status, receiving by asking eFax for new faxes (each fax recorded before it is downloaded, resumed after a restart, and deleted from eFax only when turned on, with refused deletions retried for seven days; an optional signed eFax notification makes Faxbot check eFax at once and its contents are never used), keys in .env, an eFax section in the Setup Wizard and Settings, faxbot admin settings validate efax, and eFax's published plans with source and date (faxbot savings plans efax; the API itself is priced by quote). Built from eFax's published API specification and tested against a fake; not yet run against a real eFax account. See eFax setup.
SSL Fax through Faxbot's own HylaFAX+ 7.0.11 engine (the Compose service hylafax): faxes over the SIP trunk go through it, and its pages go over SSL Fax when the other fax machine offers it, as an ordinary fax otherwise, on the same call. One dial and one try per fax; a fax the engine cannot take (sending together, engine not running) goes through the built-in engine and Sent says why. When the carrier turns a call away before it is answered, the fax in Sent and the call in Recent calls give the carrier's own answer, not the "line was busy" HylaFAX reports for every such ending: a refusal (SIP 603, 403, 401 or 407: check that your carrier account allows calls to that country), a number the carrier could not reach as dialled (404, 484 or 604: check the number), no answer or unavailable (408, 480 or 487: try later), the carrier unavailable (500, 502 or 503: try later), and busy only for 486 or 600. Each of these still ended before any fax data, so another route may take the fax as after a busy line, and a refusal or an unknown number never counts as a busy hour for that number. Faxes the built-in engine sends over the trunk get the same sentences, where they read "The call did not connect." before: a hang-up handler on each call it places reports the carrier's answer before Asterisk's own result, which carries none. Asterisk reads the SIP answer from the trunk call once it ends; an Asterisk image built before this change sends only the call's Q.850 cause, which still names a refusal or an unknown number. On 13 October Telnyx answered 603 for countries its outbound profile did not allow and 404 for numbers it could not route, and each of those faxes read "busy"; the new answers are tested with simulated calls in every order their reports can arrive, not yet against a carrier or in the loopback proof. Received faxes go through it too: Asterisk tries the engine's fax lines one at a time, first free line first, and the built-in engine answers when no line is free. Every 25 seconds the engine checks that its fax daemons and each line's modem and fax getty are still running, and starts again by itself when one has stopped; the trunk page then says "Faxbot's fax engine lost a fax line and is starting again." (or "Faxbot's fax engine stopped and is starting again." for its own daemons). Between checks it reads only a status file per line, so an idle engine uses about half as much processor time as before (0.86% of one core instead of 1.54% in the loopback proof). An audio send on which the engine heard no fax machine puts it back on T.38 for its next call, so the engine never stays on a mode that fails, and an audio call no longer asks the carrier for T.38. On 11 October every audio send over Telnyx ended 3 seconds after Telnyx's own T.38 request, which nothing on an audio call answers; with T.38 back, a test fax to the same number went through. Every page the engine sends carries the header line 47 CFR 68.318(d) requires (date and time, your header text, the sending number and the page number), in a font that fits the top of the page at fine and at standard resolution. In the loopback proof it changed only the top 30 rows of each page at fine resolution and the top 16 at standard: rows that were white on ordinary, packed and encoded pages, which still decode exactly, and the header line reads back as written at both resolutions. When a free line does not answer, the built-in engine takes that fax, the engine restarts by itself as soon as no fax is going through, and the trunk page and System diagnostics say so for a day; Restart the fax engine on the trunk page and faxbot delivery providers trunk restart-engine do the same by hand. The engine sees only its own folders (never Faxbot's data folder or Asterisk's files), reports with its own secret and keeps every result until Faxbot takes it; a restart mid-call leaves the fax uncertain and it is never sent again. Each engine call's record follows the engine's own result, whichever report arrives first: a received fax reads as received with its pages, a received call that left no fax still gets a record and a sentence, and speed and compression are recorded only when the call agreed them. A T.38 call on which the engine heard no fax machine moves only the engine to audio fax (the built-in engine keeps T.38; Apply and connect tries T.38 again), and that fax takes its next route. Faxbot shows and stores each caller's number with its country code, the same way for both engines. The trunk page, Sent's details, a number's Details in Recipients (whether a fax machine takes faster pages, and its own speed and error correction), Savings & optimization → Savings results (an estimate priced with the carrier's billing increment) and faxbot delivery providers trunk status, sent show, recipients limits and costs savings show it. Tested with a local loopback proof (SSL Fax over audio and across T.38 gateways, an unreachable or private listener falling back, a refused T.38 request, a received fax, a restart mid-call). Live over Telnyx on 5 October 2026: an audio fax sent by the engine (31 seconds connected, one billed minute) and a 2-page fax received; its T.38 send heard no fax machine. A capture showed why: behind a router that keeps port numbers and forwards none, Telnyx's T.38 data is let in only after Faxbot sends from its T.38 port, and nothing on Faxbot's side sent first. Faxbot's Asterisk now sends three T.38 no-signal packets as soon as a T.38 stream starts (asterisk/patches), proven in the loopback proof behind a stand-in for such a router. Live with that fix, one T.38 engine send went through and the next failed: the carrier's T.38 began with a V.21 preamble that carried no frame, and the T.38 gateway in spandsp 0.0.6 then kept its V.21 transmitter running, so the engine never heard the answer. Faxbot's Asterisk now ends such a preamble (asterisk/patches/0002), proven by replaying the captured T.38 packets into the same spandsp; every T.38 stream also leaves one line in the Asterisk log (where the first packets went, packets each way, whether the gateway engaged). On 6 October the first fax received over T.38 failed: the carrier passed on a speed test that had gone wrong on its side, and Faxbot then kept sending filler to its fax engine for seconds, so the engine could not ask the sender to slow down. Faxbot now stops that filler (asterisk/patches/0003). Replaying the call shows the engine's request now reaches the sender, and faxes that worked replay unchanged; a fax received over T.38 with this fix is not yet proven live. Live over Telnyx on 10 and 11 October, SSL Fax carried the pages between two Faxbot installations in both directions, after training at 14,400 bit/s first time, and on 11 October the engine's T.38 sends to a public test fax line went through 3 of 3 at the line's top speed. Earlier that day the same sends mostly failed to train while the virtual machine running that installation stalled; a healthy host is part of what the engine needs. See SSL Fax engine.
The fax engine for one fax. POST /fax takes engine (auto, the default; builtin; hylafax) and faxbot send takes --engine, for a call over the SIP trunk: builtin always places it on the built-in engine, even while the SSL Fax engine runs; hylafax uses the SSL Fax engine when it is running and otherwise the built-in engine, as with no choice, never waiting or failing for it. Faxes sent together in one call always go on the built-in engine. The choice is kept with the fax when it is accepted (an entry in its delivery history, so no migration), so a retry or a claim after a restart keeps it, and a replay with the same idempotency key and another engine is refused. Sent details and faxbot faxes sent show say it in one sentence ("You chose the built-in engine for this fax."), and after the call why the built-in engine carried it ("You chose the SSL Fax engine for this fax, but it is not running, so the built-in engine sent it."). Send a fax offers it as Fax engine (Automatic, Built-in engine or SSL Fax engine) when a carrier trunk is set up, and its estimate follows the choice. Tested with synthetic faxes on SQLite; not yet used on a live call.
Savings & optimization → Opportunities → Plans: whether each monthly plan, such as HumbleFax's $10 unlimited plan, is worth its fee at your traffic. For the last 30 days and the 30 before, it shows the faxes the plan carried (sent and received), the fee for the days Faxbot has records for, the fee per fax, and what the same faxes would have cost on the cheapest other route that is reliable for those numbers: the cost per delivered fax where there is enough evidence, otherwise the rate-card estimate. Faxes received through the plan are priced on the carrier trunk, plus the carrier's rental to keep the plan's number; when the carrier publishes no rental, the advice states no saving and the rent row reads "Not published". Another flat plan is never offered as a free way, and faxes to your own numbers count as tests: a test to a number that receives into Faxbot, or to the plan's own number, needs no other way, while a test to another number of yours that does not receive into Faxbot (such as a HumbleFax number faxed over the trunk) is a paid call and is priced, with a note saying how many there were. The advice is "Keep it", "Worth reviewing" (with the monthly difference, what to do and one sentence for each caveat, such as moving the plan's number first) or "Too little history"; Faxbot never cancels anything. The same advice is in GET /routing/recommendations/plans and the Plans section of faxbot savings opportunities. It is tested with synthetic faxes on SQLite and PostgreSQL. On a copy of the live installation's records (5 October 2026, two days of history), HumbleFax's plan reads "Worth reviewing", with the reminder to move its number to Telnyx before cancelling. The plan's number is the one HumbleFax reports for the account, because no sending number is configured, and every fax the plan carried in those two days was a test between the installation's own numbers. Without that number Faxbot would say "Keep it", because Telnyx delivered only 11 of 16 faxes to it, below the 80% reliability bar.
Savings & optimization → Opportunities → Receiving: advice from the received calls Faxbot recorded on its carrier trunk. Faxbot replays those calls through shared lines (Telnyx sells them as inbound channels) and says which local numbers could share them and which should stay billed by the minute. It chooses on one 30-day period and checks the choice on the next, and it never advises a choice that would have given a caller a busy signal. Toll-free and international numbers, Canadian ones included, stay billed by the minute. The same section lists numbers with two calls or fewer in the last 30 days with their monthly rental, and works out the monthly fees of the fax services in use. Every figure is an estimate shown with its time window, and Telnyx's channel, minute and number prices ship with their source and the date they were read (5 October 2026). Faxbot only recommends and never changes a carrier account. The same advice is in GET /routing/recommendations/receiving and in the Receiving section of faxbot savings opportunities. It is proven with synthetic traffic only (20 numbers, on SQLite and PostgreSQL); the live installation has one day of calls, so it says it needs 60 days of history first.
Advice from history in Savings & optimization → Opportunities, each section saying plainly when there is too little to go on, with every figure an estimate and an unknown cost never shown as $0. None of it changes a setting or sends anything.
faxbot recipients toll-free. The NPI registry (NPPES) can suggest a number but never approves one.faxbot delivery providers trunk telnyx name-lookup-off change only that setting, are audited and read the setting back.faxbot savings opportunities and its subcommands fax-marker, billing-steps, partners, service-numbers and toll-free.Only owners can use the console Terminal by default. Host Operators no longer can, unless an owner gives them a role that includes it, and the Audit log records every terminal session.
Faxes to your own numbers arrive inside Faxbot with no call. A fax to one of the installation's receiving numbers (the SIP trunk's numbers when Faxbot receives over the trunk, and the direct-delivery card's number) becomes a received fax at once, and mailbox rules and email delivery treat it like any other. Received and faxbot faxes received list show that it arrived through This Faxbot, and Sent and faxbot faxes sent show say "No call needed; it went straight into Received." with the reason. Each sent fax is recorded as received once, so a retry or a restart never makes a second copy; if it cannot be delivered here, it goes by its normal route, and a lost answer is settled from the records. A preferred route still wins. The setting "Deliver faxes to your own numbers inside Faxbot" (local_delivery_enabled, on by default) turns it off, and one fax can ask for a real call (send_by_call on POST /fax, faxbot send --by-call, a checkbox on the Send screen); the Setup wizard's test fax always does. A HumbleFax account number is not treated as your own here, even while Faxbot receives through HumbleFax, so a fax to it still places a real call and comes back in through HumbleFax; one shared rule (routing/own_numbers.py) defines both "receives into this Faxbot" and "an account number of yours". Savings & optimization → Savings results counts the calls avoided, with an estimate where a rate card prices the call. Migration 0020 adds the received-fax source and the per-fax request. Tested with synthetic faxes on SQLite and PostgreSQL; not yet checked live.
Faxbot dials a recipient's approved toll-free number. When a recipient has approved a toll-free number for the same intake, a fax accepted while that approval holds dials it and still names the recipient you entered; withdrawing the approval changes new faxes only. Every attempt records the number it dialed before it is sent (migration 0027), and Sent details and faxbot faxes sent show say "Dialed 1-800-555-0100, the toll-free number Example Clinic approved on October 3, 2026." Route choice knows what each route charges to call a toll-free number and what caller ID it needs; Savings & optimization → Prices & plans and faxbot savings rate-cards list them with their source (read 7 October 2026: Telnyx lists such calls as free, AnveoDirect charges $0.00182 a minute, and prices that are not published stay unknown). A route that cannot call the toll-free number, or a trunk with no caller ID, calls the number entered instead, and a definite failure calling the toll-free number moves the fax to the number entered; an uncertain call is never sent again. Each call is priced by the number it dialed, carrier charges are matched on it, and Savings & optimization → Savings results reports what the approved toll-free numbers saved on their own line, noting that their owners pay for those calls. Tested with synthetic faxes and fake providers on SQLite and PostgreSQL; not yet run against a real carrier or a real toll-free number.
Received faxes keep their history. When fetching a document stopped and a person or the provider set it going again, Faxbot first keeps that stop (when, how many attempts, the last problem, and who or what resumed it), and the fax reads "Failed twice before Phaxio reported it again on …" in Faxes → Received, the API and faxbot faxes received get. eFax deletion retries are kept in their own records, so the report eFax gave is never written again after it arrives. Migration 0022 adds these records and moves existing eFax retries out of the reports. Tested with synthetic faxes on SQLite and PostgreSQL, including the upgrade and downgrade with existing rows.
Faxes wait for room instead of colliding. Faxbot calls a number only while it has room (one call at a time by default, because a fax line answers one call at a time; set per recipient in a number's Details in Recipients or with faxbot recipients set --calls-at-once), and calls over the SIP trunk only while the trunk has a free line (Calls at once, by default the fax lines) and has not started its calls for this second (New calls per second, by default the carrier's published limit: 5 for Telnyx, the most it takes without a surcharge, read 6 October 2026). Calls coming in use trunk lines too. A fax that cannot start waits and never fails for it; Sent and faxbot faxes sent show say why in one sentence, and the Overview counts the faxes waiting for a free line. A call with an uncertain result keeps its number and line until its result is known or you settle it as delivered or not delivered (the fax then ends as delivered or failed, and the next fax to the number goes at once), and every hold ends 30 minutes after the call was submitted. The holds come from the delivery records themselves, so a restart neither loses nor doubles them. Urgent faxes (the Urgent box on Send, faxbot send --urgent, urgent on POST /fax) go first and skip sending-together waits; otherwise the sender served least recently goes next, so one sender's batch cannot hold up everyone else. The trunk page and faxbot delivery providers trunk limits show and change the trunk limits with the carrier's sources. Migration 0021 adds the urgent flag and the per-recipient limit. Tested with synthetic faxes on SQLite and PostgreSQL, including a simulation in which waiting costs fewer calls than dialing into a busy line; not yet checked on live traffic.
Faxes are scheduled around each recipient. A fax can carry a send-by time (Send by on Send a fax, faxbot send --by 17:00, or send_by on POST /fax), and Faxbot never holds it past the last moment that still leaves room for a second try; faxes due within the hour go right after urgent ones, and Sent and faxbot faxes sent show say when a fax may miss its time. A recipient can ask for faxes only in certain hours, in its own time zone (a number's Details in Recipients, When to send, or faxbot recipients schedule). Faxbot also learns the hours a number is usually busy, unanswered or answered by no fax machine, from the last 30 days of calls: at least three days at that hour, older days counting less, weekdays pooled unless one day of the week has enough calls of its own, and a successful call in that hour starting it over. When a failed try may be charged (eFax, and every route that does not publish whether it charges), an ordinary fax waits for the hour to end; when it costs nothing (Phaxio credits failed faxes back, HumbleFax is a flat plan; read 7 October 2026), the fax only goes after other faxes waiting for the same line. Urgent faxes ignore both, a held fax stays ready and never fails for waiting, and Sent says why it waits in one sentence. Faxbot also learns, from the same 30 days of phone-line calls on both engines, how long a page takes and how often calls fail after the fax machine answers at each hour, for each number (every number on the line when it has too few calls of its own). An ordinary fax waits, for up to 12 hours and never past its send-by time, for a later hour only when this hour is clearly worse than the number's usual one: a quarter more time a page on a route billed by the minute, or 40% of answered calls failing. It then goes at that hour, and Sent says why in one sentence, such as "calls to this number take about 50% less time a page before 11:00 AM". The predictor prices the hour the same way, and When to send and faxbot recipients schedule list the learned hours. Tested on synthetic call histories on SQLite and PostgreSQL; not yet run against live traffic.
The fax engines run with the least privilege they need. Asterisk, which reads the carrier's calls and fax data, runs as its own unprivileged user; the SSL Fax engine's daemons work as uucp. Both Compose services drop every capability except the few their start scripts need, and nothing in Asterisk's container can gain more; starting each image without each of those capabilities shows what breaks (api/tests/test_engine_processes.py). On the shared data folder, Asterisk can read only the pages it sends and the secret it hands received faxes over with; Faxbot's database and documents are Faxbot's alone. Faxbot's changes to Asterisk and HylaFAX+ must apply exactly or the image build stops, and the T.38 gateway changes build only against the spandsp 0.0.6 they were checked against. The gateway logs the first signal it repairs in a call and counts the rest in the call's T.38 line, so the far end cannot flood the log. SSL Fax pages travel encrypted, but Faxbot cannot confirm who is at the other end, so SSL Fax is as private as an ordinary fax call, not more. Proven in the loopback proof with the Compose settings, and running on the live test install since 2026-10-06, where an upgraded data volume took the new file modes and the live fax checks (a T.38 receive, an engine T.38 send, two faxes to one busy number and delivery to the installation's own number) passed.
Receiving through HumbleFax, by Faxbot asking HumbleFax for new faxes, so nothing has to reach Faxbot from the internet. Turn on Receive faxes from HumbleFax on the HumbleFax provider page (or choose HumbleFax as the receiving provider), and Faxbot checks every minute by default (from every 30 seconds to every hour), with a Check now button and a line saying when it last checked and what it found (faxbot delivery providers humblefax status and check; faxbot delivery providers configure humblefax receive=true poll_seconds=120). HumbleFax can receive beside another receiving provider, such as the carrier trunk. Each fax is recorded once by its HumbleFax ID before its PDF is downloaded with the account's keys, so a restart or a second listing never makes a second copy, and a failed download retries on the usual schedule and keeps its history. The first check also brings in the faxes HumbleFax received in the last 30 days; later checks start a day before the newest fax Faxbot has. Faxbot never deletes anything at HumbleFax, and it spaces its requests to stay under HumbleFax's limit of 5 a second. It uses three read calls from HumbleFax's API reference (read 7 October 2026) and is tested against a fake HumbleFax on SQLite and PostgreSQL; the live check on a real HumbleFax number comes at integration.
What a fax would cost, before it is sent. One shared predictor works out, for each route, the time on the line, the pages billed and the cost of a fax to a number. The time comes from the size of each page in the prepared fax image, or from typical pages, at the speed earlier successful calls to that number reached; the setup and page-handshake defaults come from two measured calls, and calls to a number replace them. The bill follows the route's rule: by the minute with its step and minimum, by the page, by the call, the greater of pages or started minutes (Fax.Plus's rule), or a monthly plan, where a fax adds nothing until a page allowance runs out. Numbers are priced by class: toll-free, abroad by country (AnveoDirect's public rate deck and Phaxio's 10 cents a page, read 7 October 2026), and local. A route that publishes no price for the class reads as unknown, never as free. Send a fax shows "What would this cost?" for the chosen route once the document's pages are known, and GET /routing/predict and faxbot savings predict price a fax on every sending route without sending it. Checked with synthetic recorded calls only.
The fax coding measured on each fax's own pages, and calls priced by their expected bill. Before each attempt on Faxbot's own engines, the layout chooser measures the lossless codings MH, MR, MMR and JBIG on that attempt's pages (JBIG with jbigkit's T.85 tools, installed in the API image, and with the options the SSL Fax engine sends with, so the measured size is the size on the line) and prices each layout with the smallest coding the call may use. MH is always usable. MR and MMR are used only when the receiving machine's own capabilities allow them, and JBIG only when a call has put that machine's capabilities on record: the built-in engine's frames, or the SSL Fax engine's own log of what the machine takes (database revision 0059). To a machine not on record yet, the SSL Fax engine is asked for nothing and picks the most compact coding itself, JBIG where the machine offers it, and the time is priced at the smallest measured coding: on the loopback, three shaded pages took 58 seconds of transfer in JBIG and 108 in MH. MMR and JBIG are used only with error correction, which Faxbot never turns off for them. A coding that failed twice in a row to the number is never used, nor anything past your compression setting. On AR's synthetic pages, MH came out 20% smaller than MMR on a shaded table, 30% on a tinted form and 34% on a noisy gray scan, while MMR was about half the size of MH on black text; the numbers match Codex's libtiff 4.7.1 measurements exactly. The shared predictor uses the measured sizes, and its old fixed ratios only for a coding it did not measure. It now prices a call by its expected bill over the spread of its time rather than by rounding the average: a call of 59 or 61 seconds with equal odds bills 90 seconds expected on 60-second steps. Each number's spread is learned from its own recorded calls, with an assumed 15% either way until it has 3. The built-in engine has no JBIG and gets the smallest measured coding. The coding goes with the call only when it narrows what the engine would take by itself. On the SSL Fax engine it goes as the job's data format, which HylaFAX+'s own coding conversion used to ignore. Faxbot now hands it back through the engine's job controls, and engine learning's compression change now goes the same way (not yet proven on a call of its own). On the built-in engine it goes as FAXBOT_COMPRESSION, which Asterisk patch 0006 reads. Each attempt keeps the coding it asked for, what was measured and why (database revision 0056); what the call actually used comes from the engines' own records. The Fax coding line in Sent's details and faxbot faxes sent show say "Sent with MH: 20% shorter than MMR for these pages." faxbot savings fax <id> adds what was measured, and faxbot savings predict --file DOC (POST /routing/predict, for people who may send faxes) measures a document before it is sent. Send a fax and the dry run say when 9 in 10 such calls finish only once the number has 3 recorded calls of its own; until then Send a fax says the trunk's time on the line is an estimate, and it leaves the coding comparison to Sent's details. Proven with synthetic pages, fake engines, the real predictor and the SSL Fax engine's loopback (MH asked and used; JBIG kept and used). No live call has used a measured coding yet.
The account is chosen after measuring its best pages (brief 84, database revision 0067). Before, Faxbot chose the account from the fax's page count and only then prepared that account's best pages, so an account that is cheaper once its pages are packed or coded could lose to one priced on raw pages. Now, when a fax's route is chosen by cost among several accounts (no rules, or a cheapest or automatic rule), each account the fax may use is priced on its own rate card for the number it calls, and every way it may send the pages is measured and priced on that tariff: the pages as they are always, long pages, fax-friendly renderings and each lossless coding where allowed. The route policy then ranks the accounts again by each one's best measured price, with every rule, cost cap, preference, reliability record and plan hold applied as before, and the account bound sends exactly the pages it was priced on. Nothing is written for a losing account. The attempt keeps the account, its pages, their expected bill, the cheapest other account compared and the SHA-256 of the file the call sends, written before the submission marker and never changed; if the document, the account's price for the number or what the recipient accepts changes before it is sent, the fax is chosen again at once. Measuring never makes a fax miss its claim: the worker renews the claim while it prepares a fax, measuring stops 10 seconds before the claim would end (the accounts are then ranked by page count, noted in the fax's history), drawn pages and measured codings are kept for the fax's next attempt, and an attempt given up because its preparation outlived its claim is logged with how long it took. A database too busy to record the choice makes the fax wait a moment instead of failing it. Sent details and faxbot faxes sent show say it in one sentence ("Sent through Page trunk as 1 long page: about $0.004 instead of $0.005 through Telnyx as 1 long page."), and Send a fax and faxbot savings predict --file (POST /routing/predict) measure the document the same way and name the account and pages the worker would use, with the runner-up; GET /routing/predict and the page-count estimate are marked approximate. Page preparation now prices an extra account by its own rate card, not its provider's first account's. Route ranking always uses the shared predictor, never the older 30 seconds plus 30 seconds a page, and an unknown price never ranks ahead of a known one among routes within budget. A flat plan past its normal-use budget goes after every route within budget, priced or not, and the route that goes first says why ("HumbleFax is past your normal-use budget this month, so this fax goes by Telnyx trunk."); as the only route left, the plan still takes the fax and says it is past its budget (13 October 2026: before, HumbleFax past its budget still went first as "included" whenever the routes beside it had no price). A route you chose for the number, a rule's own order and a scarce plan's held room are unchanged. An account whose provider does not serve the number's country is left out instead of ranked: HumbleFax takes only US and Canadian numbers (its terms, section D.5, read 9 October 2026), including none of the other +1 countries. A trunk with no published price for a country is priced by the rate its own carrier records showed for calls there, said as learned with its date; a published price or a row you saved always comes first. A fax sent from a mailbox is priced by the caller ID its call presents (the mailbox's reply number, read as the call reads it), so a carrier price that depends on the caller ID follows it. Faxes whose rules fix the account order keep that order. Sending time is priced in money too: a carrier's published prices by time of day are kept as data with their source and date (Andrews & Arnold's UK peak, off-peak and weekend rates, read 10 October 2026, apply once a card for that carrier is saved), and an ordinary fax waits for a later hour its recipient allows, within 12 hours and its send-by time, only when its call on its own account costs less then (other accounts are not yet priced by the hour); a faster hour that bills the same is no longer waited for. Faxes waiting to share a call are grouped into the calls that cost least in all, each call billed on its own (exact for up to 10 faxes, arrival order otherwise), when that is cheaper than arrival order, and a shared call can go on long pages when the receiving machine takes them: each long page's call pages are kept, so a call that confirmed only some long pages marks the faxes on the first unconfirmed one as possibly arrived, never as not sent. Scarce plans count the pages each attempt really sends, and a choice made inside a plan is made again when the plan's room changed. A call with error correction (always with MMR or JBIG) is predicted with about 3.3 seconds more for each 65,536-octet error-correction block a page needs past its first, so a page just over a block edge costs a whole exchange more. Prices in different currencies are never compared as plain numbers: money ranks accounts only within one currency, and your order decides between currencies, which Sent says in one sentence. Ranking can convert at an exchange rate you set, but there is no setting for that rate yet. Proven with the measured 12-candidate counterexample (two synthetic accounts, invented rates) through the real delivery worker against a brute-force oracle, brute-force checks of the sending-time and partition searches, on SQLite and PostgreSQL; no live fax has gone this way yet, and scarce-plan allocation does not yet weigh each waiting fax's measured pages.
Smaller pages without changing a pixel (lossless tuning in the SSL Fax engine, HylaFAX+ patch 0003): every MR page goes with the fewest-bytes reset schedule T.4 allows, chosen by dynamic programming over each row's measured codes and the bytes the engine really sends (its EOL alignment, and the minimum line time without error correction); and JBIG pages go with the smallest of 12 T.85 settings (typical prediction, the two-line template and moved template pixels at L0 128). On the 20-page synthetic corpus a tinted form went from 88,526 to 57,974 bytes in MR and from 29,003 to 5,629 in JBIG, and a photograph from 53,853 to 15,990 in JBIG; black text barely changes. Tuned JBIG goes only where the receiving machine is known to decode it: pages over SSL Fax (the engine decides per page), an enrolled partner whose signed statement says its own Faxbot answers its number, or a number you turned it on for with its warning, because a receiving machine confirms a JBIG page before decoding it. A tuned page a machine refuses makes that number's later calls plain for that coding, with no resend. The engine no longer replaces an MR file in an MR session with its fixed schedule, and no longer switches a coding Faxbot measured and asked for to MH by its own file-size guess (the second place HylaFAX overrode Faxbot's choice). Faxbot measures MR and JBIG exactly as the engine sends them, checked byte for byte against the engine on the corpus and at image build. The setting is Make pages smaller without changing them in the trunk's fax settings (faxbot admin settings set sip_fax_tune_coding=false), on by default; each number has its own switch under a number's Details in Recipients and faxbot recipients tuning, and Sent's Fax coding line says "JBIG, tuned" or "MR, tuned schedule" (faxbot faxes sent show). Database revision 0063. The patch changes the engine's version, so what Faxbot learned from the SSL Fax engine's calls starts again once after the update. The built-in engine (spandsp) still codes MR on its fixed schedule. Proven at image build and with synthetic tests; the loopback run is in progress and no real receiver has taken a tuned page yet.
The engine for sending rules your organization writes. The organization, each mailbox and each workflow can have its own rules: limits (never use these accounts, require direct delivery or encryption, cap the cost, hold for approval or until a time window, place a real call, never dial an approved alternate number) and routing rules read top to bottom (use one account, try accounts in order, the cheapest reliable of several, the sender’s site’s accounts, or the automatic choice), with the page layout, the approved alternate number and what to do when a trunk is busy. A mailbox or workflow can only narrow the organization’s rules, and an organization rule marked mandatory cannot be replaced. Each draft is checked before publishing (names that don’t exist, rules an earlier one always catches, limits that leave a rule no account, a cap no account can meet) and replayed against your last 200 faxes. Publishing creates a numbered version that is never changed afterwards, with history, differences and restore, and is audited. A dry run (POST /routing/explain) says which route a fax would take and why. With no rules, a fax gets exactly the automatic choice Faxbot makes today. With 500 rules in each of three scopes, deciding took about 0.4 ms (95th percentile on the development machine), and a test keeps it under 5 ms. Database revisions 0029 and 0030 add the tables.
Provider accounts: several accounts at once, a second account at the same provider and a second trunk included (Delivery setup → Providers & accounts → Accounts, faxbot delivery providers accounts list|show|add|update|enable|disable|default-sending|default-receiving|health, /admin/providers/accounts). The first account of each provider is the one its own provider page sets up, read from those settings exactly as before, so an installation with no extra account stores, profiles and digests its configuration unchanged. Extra accounts are kept inside the encrypted configuration revision with their credentials, which are never shown again, so a fax accepted under one revision never picks up later credentials. Adding or changing an account is an audited configuration change that needs the provider permission and is checked against the version the screen read. Each account has a site, sends and receives switches, an on switch, the numbers it receives on (a number belongs to one receiving account), faxes or lines at once, calls a second for a trunk, and a daily spending limit that resets at local midnight. Health is worked out from Faxbot's own records: ready, not set up, turned off, waiting for the first fax, failing (most of its last faxes failed, or its provider refused it), or spending limit reached. An account that receives by notification shows the address to give its provider and, for an extra account, the path to add to a webhook tunnel. The sending rules see every sending account; with no rules, the automatic choice is exactly today's. Routes, route choices and costs are kept by account, so an extra account can be the default for sending beside the first account of the same provider, each with its own rate card and costs. Tested with synthetic credentials on SQLite and PostgreSQL and with the real faxbot delivery providers accounts commands against a local server; not yet run with two real accounts at one provider.
Receiving on several accounts at once, and receiving rules. Every account that receives listens at the same time.
/sinch-inbound/<key>, /phaxio-inbound/<key>, /efax-inbound/<key>), checked with that account's own user name and password or signature. Phaxio's signature covers the account's own address. An address whose account is off answers "not found" and is audited. Until an extra account receives, each provider's original address behaves exactly as before.faxbot delivery numbers add|update|explain) can match any of your numbers, the account or its site, the sender's number or its beginning, the subaddress the sender's machine gives, and days and times in your time zone. They can choose the mailbox, email through a chosen connector or no email, mark the work item urgent (urgent items come first in Work), and keep the fax for a number of days. That is the cleanup age, not a legal hold. They are read in order; the first that matches places the fax. A rule with conditions can share a number with a plain rule and is read before it, so one number with a subaddress per department reaches each department. A subaddress only chooses where a fax goes: it is the sender's statement, so it never gives anyone access.POST /access/inbound-rules/explain say where a fax would go. With no options, placement and email are exactly as before.faxbot delivery numbers add|update --forwarded-from). Faxbot reads the network's statement from the received call (the Diversion and History-Info headers, and a signed diversion PASSporT in the Identity header, RFC 8946) on both fax engines. When a rule depends on it, Faxbot checks the signature against the certificate the PASSporT names: fetched only over HTTPS from a public address, valid at the time of the call, signed within 60 seconds and addressed to this number. A forwarding is verified only when that certificate chains to a certificate authority you trust: you add the STIR/SHAKEN certificate authorities (STI-CAs) under Delivery setup → Numbers → Forwarded calls you can verify or with faxbot delivery numbers forwarded-trust list|add|remove, by pasting their PEM certificates or giving the address of a list you can reach, read once. Each change is an audited configuration change. The STI-PA gives its list of approved STI-CAs only to registered service providers, through its API with their account, so ask your carrier for it or download it with your own STI-PA account. Anyone with a web server could name a certificate, so a signature that checks against a certificate you do not trust is shown as not verified. By default such a rule takes only a verified forwarding; with --forwarded-unsigned (or the console's box) it also takes one that is not verified, but never one whose signature failed. Chain checks are proven with a synthetic root, intermediate and signing certificate; no real STI-CA list or carrier certificate has been tried. The received fax records the forwarding number and how far it was checked, and the work item shows it in one sentence (migration 0054). Proven with synthetic headers, a synthetic signing key and certificate, and two Asterisk containers, where a signed forwarding still checked after Asterisk carried it. Whether Telnyx or other carriers pass a diversion PASSporT or Diversion header to their customers has not been seen on a live call.Tested with synthetic faxes and fake providers on SQLite and PostgreSQL. Not yet run against real providers: two accounts at one provider, Phaxio, eFax and a second HumbleFax account receiving, and whether real carriers and Telnyx carry a SUB.
Sending rules in delivery. When a fax is accepted, Faxbot decides its route envelope from its facts and your rules, in the same transaction as the fax: the accounts it may use and in what order, the cost cap, the holds, the number it dials and the page layout. Each attempt chooses only inside it, and the fax's own default account is never a drop-back the rules exclude; a last check before anything leaves Faxbot refuses an unrecorded route. Send a fax, faxbot send and POST /fax take the mailbox it is sent from (one you work in), its workflow and its labels. A fax no route can take (every allowed account off, refused, busy or over the cap) waits in Sent with one sentence, never failed and never sent another way; someone with the new Approve faxes permission (Owner and Administrator by default, database revision 0032) approves, refuses with a reason, or sends it anyway by an account only a cost cap or an outage left out, and anyone can check again (faxbot faxes sent approve|refuse|check-again, faxbot faxes sent list --held, /routing/holds). An approval binds to the document, the number and the rules' versions, and a held fax never goes in a shared call before it is released (a threaded test races approvals against two sending workers on PostgreSQL). Time windows open by themselves. A fax whose route a rule chose moves to its next account only after a call that ended before any fax data, by each provider's documented codes (the SSL Fax engine's, Asterisk's with no page sent, Phaxio's line errors, Sinch's call errors, SignalWire's busy and no-answer, HumbleFax's "did not pick up"; Documo's codes come from search results and eFax publishes none, so eFax gets no such fallback). After the first try and two more, each ending before any fax data, the fax waits in Sent naming the accounts it tried, and Check again tries only accounts not tried yet; faxes no rule decides fall back exactly as before. "Require encryption" is met by direct delivery or by SSL Fax on the trunk for a number that has used it before. Cheapest and automatic routes rank by the shared predictor and each plan's budget (toll-free numbers by Telnyx, the rest by HumbleFax while its budget lasts, then Telnyx, then Sinch), with minute allowances priced; a plan's fax reads "In your plan", never $0.00, and an unknown price says so (faxbot savings fax --to, /routing/quote, Try a fax). Each attempt's cost comes from the pages it actually sent (dense sheets, encoded pages), and Spending agrees with the savings line. Why this route (faxbot faxes sent route, /routing/faxes/{id}/route) tells each attempt's account, what it skipped and how it ended; Apply the current rules to waiting faxes never touches a fax already sent or uncertain. Sending recommendations draft a rule for a number, and one for a country where the same account was cheaper for several numbers. Proven with synthetic data, provider fixtures built to each API reference and fake routes on SQLite and PostgreSQL; not yet run against a real busy number, a real approval in the console, a real HumbleFax plan quote, or two real accounts at one provider.
Several trunks, sites and prices by where calls start.
sip) gets its own section set in Asterisk's file (trunk-<key>-endpoint, -aor, -auth, -identify, -reg) beside the first trunk, whose file stays byte for byte as before. Each trunk keeps its own carrier, sign-in, numbers, caller ID, number format, codecs, fax over IP (T.38) switch and lines. Faxes go out over the trunk their account names, on both engines, and Faxbot dials only trunks it wrote into Asterisk's file. A received fax records the trunk it came in on (its endpoint sets FAXBOT_TRUNK; when two trunks share a carrier's addresses, the number it called decides). A half-filled second trunk is left out with a sentence and never stops the first. The trunk page and faxbot delivery providers trunk status|telnyx --account KEY show one trunk at a time, and Telnyx's fax over IP check runs per Telnyx trunk with that trunk's own API key.faxbot faxes sent show say "Your own trunk can't call its own number with one line, so this fax went through HumbleFax." (with the route's name). A fax that did not ask for a real call never goes over the trunk to the trunk's own number, as a route or as a fallback. Found by the live pilot on 2026-10-10 (a pin to the trunk was silently dropped); tested through the real planner and worker on SQLite and PostgreSQL. A call over a trunk to its own number has not yet run live since the change: on 2026-10-04 one such call ended with a T.38 negotiation error.faxbot savings fax --to NUMBER --from-site SITE, Savings & optimization → Prices & plans). You can enter your own rows for a sending card, such as a contract rate from one office (Add a price by where calls start under Savings & optimization → Prices & plans, faxbot savings rate-rows ROUTE --replace FILE); migration 0033 keeps them, and a new price supersedes an old one without changing it.faxbot savings opportunities trunks): each trunk's monthly fee, busiest time, faxes and cost per sent fax, and when one trunk's faxes fit on another, what cancelling it would save. Advice only: Faxbot never cancels a trunk.faxbot delivery providers trunk send-only list|add|remove): a number you already have, such as your main office number, shown as caller ID and station ID but never received on here, so a fax to it is a real call and it is never your reply number. Faxbot names a trunk number you rent only to send from, with what releasing it would save.Tested with synthetic trunks, calls and bills on SQLite and PostgreSQL. Not yet run against real systems: a second trunk at a real carrier, two trunks at one carrier told apart by the number called, prices by origin from carriers we do not use, trunk advice on real multi-trunk bills, and a carrier verifying a send-only number.
Prices by the caller ID a call shows (migration 0069). Carriers price calls to many countries, most of all in the EU, by the caller ID: in Twilio's published voice price file (read 2026-10-09) a call to an Austrian landline costs $0.155 a minute, or $0.016 with a caller ID from the EEA or North America. Import a carrier's deck for a sending card (Savings & optimization → Prices & plans → Prices by caller ID, faxbot savings rate-rows ROUTE --caller-id-deck FILE): Twilio's file is read as published, and any other carrier's deck in Faxbot's own layout (destination prefix, origination type local, EEA, non-surcharged or surcharged as Telnyx defines them, the caller-ID prefixes that qualify, and the price). Telnyx keeps its deck inside Mission Control and has not published its columns, so it is imported in Faxbot's layout. Each account is priced with the caller ID its calls would actually show; a cheaper row applies only to a caller ID you confirmed on that account with your evidence, and a local row also needs your confirmation that the number was bought there (faxbot delivery providers trunk caller-ids|confirm-caller-id|withdraw-caller-id). Until then the call is priced at the dearer row and the cheaper one is shown as not confirmed; anonymous or malformed caller IDs get the surcharged row. Quotes, caps and route ranking use the same prices, so a site trunk whose own number you confirmed wins when it is cheaper; Faxbot never changes a caller ID to reach a cheaper row. Tested with synthetic decks in Twilio's exact layout on SQLite and PostgreSQL. Not yet run against a real carrier's deck download or invoice.
Registered senders (migration 0069). Some recipients accept a faxed instruction only from the number registered with them: Garanti BBVA's 2025 banking services agreement (clause 7.4) needs no confirmation for an instruction from a registered fax number. Pin a recipient to the trunk, caller ID and station ID registered with it (Recipients → Recipients → Registered senders, faxbot recipients register-sender|registered-senders|unregister-sender). Faxes to it then go only by that trunk, only while the trunk's calls show exactly that caller ID and station ID (worked out the way the call sets them), by a plain call: no other account, approved alternate number, partner relay, direct delivery, peer tunnel, sending together or changed pages. When the trunk cannot send, or its call ends before any page, the fax waits in Sent with one sentence, and "send anyway" offers only the registered trunk; it never goes from another number. Faxbot never changes a trunk's caller ID to match a pin. The fax's files are kept past retention as the sender's evidence, with each call's answering station; Sent details and faxbot faxes sent sender-evidence FAX_ID [--original requested|sent] show them and record a request for the original. Tested with synthetic faxes through the real worker, planner and holds on SQLite and PostgreSQL. Not yet run against a real recipient that checks the sending number.
When a line's copper closes (migration 0070). France closes its copper network, and the phone lines on it, commune by commune (ARCEP: lot 3 in January 2027, lots 4 and 5 through 2028 and 2029, all lines by the end of 2030). Give each French site its commune code in the organization's sites, and import Orange's commune-level trajectory file or the government copy on data.gouv.fr (Delivery setup → Number moves → When lines close, faxbot delivery numbers import-closures FILE --source orange|gouv --file-date DATE): each site and each French number at it shows its commercial and technical closure dates with the file and its date, Orange's own file winning over an older copy, and a warning a year before with a reminder to run the receipt test from another route. The government copy's columns were read from its export on 10 October 2026 (35,305 communes, dataset dated 20 October 2025; the export of just the five columns Faxbot reads is 1.6 MB); Orange's own file needs a browser to download and its layout is not confirmed, so you save it with the same columns. For lines a carrier closes by letter (Canada, Israel and Italy publish no usable schedule), record the carrier's notice date per line (faxbot delivery numbers line-notice NUMBER --closes DATE) for the same warning. Advice only. Tested with synthetic files on SQLite and PostgreSQL; not yet run against Orange's own file.
Country service rules for the UAE and Saudi Arabia: a guard, never a ban. TDRA's FAQ (VoIP Regulatory Policy 2.0) says calls over the internet in the UAE must come from a licensee (e& or du), a provider working with one or one TDRA approved; CST licenses virtual voice services (its VVSP permit, under Decision 510/1445 of February 2024). Faxbot cannot see a provider's licence, so each account whose site, or installation, is in one of these countries shows the rules with their sources as not confirmed until you confirm them with your evidence (on that account's row in Delivery setup → Providers & accounts, so an installation without a trunk sees them too, and on the trunk page; faxbot delivery providers accounts country-rules --confirm ACCOUNT --country AE --evidence TEXT). Faxes are never blocked for it. Read 10 October 2026; not yet checked with either regulator.
Your fax lines matched to carrier discontinuance lists and contract end dates (migration 0077). Import your line inventory as CSV or Excel (Delivery setup → Number moves → Line inventory and carrier dates, faxbot delivery numbers move import-inventory FILE): number, service address, carrier, product or USOC, wire center, distribution area, contract end, use (fax, alarm, elevator, emergency or other) and monthly price; only the number is required. Import AT&T's Discontinued TDM Service Areas workbook exactly as AT&T publishes it on CLEC Online, or another carrier's discontinued or grandfathered list as a CSV with the documented columns (faxbot delivery numbers move import-carrier-list FILE). AT&T's workbook was downloaded and read on 10 October 2026: 100,512 locations in 21 states and 3,994 wire centers, dated 5 November 2016 to 16 March 2026. It lists wire centers and the distribution areas inside them, not street addresses, so Faxbot matches a line only by its wire center (from AT&T's customer service record) and, where AT&T lists only parts of a wire center, its distribution area. It never guesses a match from a city or a street, and it never flags another carrier's line. Contract end dates become each line's contract-end date beside any carrier letter. Every line with a date set by a carrier list, a letter or a contract goes to the top of the retirement plan (Advice and moves, faxbot delivery numbers move inventory) with its source and date, including dated fax lines no Faxbot account receives on yet; alarm, elevator and emergency lines are left out of the plan because they need their own replacement. Advice only. Tested with synthetic files on SQLite and PostgreSQL, and AT&T's real workbook was read in full (verification only, never a fixture); not yet run against a customer's inventory.
Encrypted audio fax trunks. Swisscom Smart Business Connect (TLS only, encrypted audio with SRTP, G.711, T.38 off with the reason, error correction on, one registration per account, a second trunk on the same account is not loaded), from Innovaphone's December 2024 profile, which found T.38 failing where its 2021 profile and Enreach's guide found it working. Telekom CompanyFlex, which requires encrypted calls on another provider's internet access and carries encrypted fax only as audio (T.30): list your Telekom line's internet address (the trunk page, faxbot delivery providers trunk own-access ADDRESSES); at every network check Faxbot requalifies the trunk by itself, signing in over TLS with SRTP and audio fax on any other or unknown access, and turning T.38 on again on your Telekom line over TCP only when that was its own decision, with one sentence beside the setting. Asterisk's file carries media_encryption=sdes only over TLS, and the real Asterisk 22.11 image loads it with res_srtp running. Tested with Faxbot's own Asterisk and synthetic network checks; not yet run against a live Swisscom or Telekom trunk.
Channels at measured peak and one page for a fax server's renewal (migration 0078). Import another fax server's or phone system's call records for a named system (Savings & optimization → Opportunities → Fax server renewal, faxbot savings opportunities import-calls FILE --system NAME): Asterisk's Master.csv, Cisco Unified CM CDR files, RightFax's DocTransport audit log (level 3 or 4), GFI FaxMaker's activity export, or a documented CSV (start, end or duration, direction, channel, number). Each layout was read from the vendor's documentation on 10 October 2026; OpenText publishes no call-record export layout for XM Fax that Faxbot could find, so that history goes through the CSV. Faxbot reports, for each system and for its own trunk calls, the most calls at once, the 99th percentile of the hourly peaks, a by-hour-of-day table, and the licensed channels that never carried a call (from RightFax's channel numbers) or were never needed at the same time (faxbot savings opportunities channels). Enter the renewal (product, date, amount, licensed channels, source) and the numbers Faxbot receives on beside it (faxbot savings opportunities renewal --system NAME --renews DATE --amount AMOUNT), and import the old server's number-to-user routing as a CSV (number, user, email, cover sheet; import-routing). The page then reads, in order: the amount and date (and, until ninety days before, the date to review it); the channels needed at peak and what the unneeded ones are worth at the renewal's average price per channel, or at the price per channel on the quote when you enter one (Price per channel on the quote, --per-channel 387.48; used for that page only and not saved), since the average also spreads the server, support and other licences over the channels; what Faxbot received on the parallel numbers and sent since the run began; and the numbers and users still to move (from the routing, else the line inventory's fax lines). Published figures appear beside it for comparison only, each with its source and read date (Cuyahoga County's RightFax maintenance of up to $26,756.71; a reseller's table of RightFax support dates; CDW's SR140 8-channel licence page, read 13 October 2026; Texas DMV's purchase order 14970, $387.48 a RightFax FoIP channel for 2024–25). Advice only. Tested with synthetic files on SQLite and PostgreSQL; not yet run against a real fax server's records or routing, and OpenText's user import format (ImpUser) is in a guide only verified customers can read.
Line windows and preflight between partners (migration 0084). With a partner you both choose to take part with (Recipients → Partners → Line windows and preflight, faxbot recipients partners windows partner PARTNER on), a fax that goes to it by phone (direct delivery off, or a rule, the court profile or a registered sender keeping it to a call) first asks the partner's Faxbot, signed, whether it accepts that document class (the fax's label or workflow, or case packet) and into which mailbox; a refusal holds the fax in Sent with the partner's reason before anything is sent, and is asked again once that answer expires. A yes is a signed, versioned statement with an expiry, never a receipt, and Sent says so. The partner then grants a short, signed window to start the call on the lines it offers partners (your trunk's lines less a reserve kept for callers that don't take part, or a number you set); a second sender queues for the next window instead of calling into a busy line, and a fax waits in Sent with "Waiting for 's line window until 14:20". A window is only permission to start a call: a fax whose last call has an unknown result is never started on a new one, and a new window is asked after a definite outcome such as a busy line. Urgent faxes and faxes that would miss their send-by time follow the receiver's policy (start without a window, or wait). A partner that doesn't take part, runs an older Faxbot (it answers 404) or doesn't answer within 10 minutes leaves the fax as it was before, and no answer is ever taken as a refusal. The Partners page shows the windows issued and received, the answers, the faxes received from callers that don't take part, and the measured retry picture: calls offered = faxes ÷ (1 − the share of calls that met a busy line or no answer), or that nothing is measured yet. Tested between two synthetic installations through the real signing, the real claim gate and the real delivery worker on SQLite and PostgreSQL; not yet run against a real partner.
California court profile (migration 0083), for filing with a court and serving papers by fax under California Rules of Court 2.304 to 2.306 (read 10 October 2026). A sender gives the case details on Send a fax ("Filing with a California court, or serving a party, by fax"), with faxbot send NUMBER FILE --court details.json or with POST /fax's court field; you can also apply the profile to a mailbox or a routing rule (Delivery setup → Routing rules → California court profile, faxbot delivery rules court attach mailbox|rule NAME), whose faxes are then refused until the sender gives them. For a filing, Faxbot puts the Judicial Council's own MC-005 cover sheet first, filled and flattened from the case details, checks that each listed document says "By fax" below its title (or that the sender confirms it on a scan), and takes no payment card: a fee goes on the court account you name. Under the profile the pages go exactly as given, by a fax call to the number given: no packing, shading, encoded pages, trimming, header notice, shared call, delivery inside Faxbot, direct delivery, partner relay or alternate number, and Sent says so. Sent also gives the service date (after 5 p.m. it moves to the next court day), the two-court-day extension and its three exceptions, a court's own published filing cut-off, and a transmission record with a draft proof of transmission or of service to download (faxbot delivery rules court record FAX_ID). Court days count the courts' published holidays for 2026 and 2027 and refuse to guess a later year; faxbot delivery rules court deadline DAY adds two court days to a deadline. Courts are leaving fax: of the 32 superior courts whose own pages say either way, 11 still take direct fax filing (most of them small courts, some only for narrow case types), 8 have repealed it since 2011 and 13 refuse it, each listed with its source (faxbot delivery rules court courts); the other 26 were not established, and each court's local rule decides. Tested with synthetic cases through the real POST /fax on SQLite and PostgreSQL; not yet run against a real court or a real served party.
Take the fax lines out of a POTS-replacement order (migration 0079). Enter the quote for a box that keeps analog ports alive over LTE or broadband: product, price per line a month, term, lines covered, ports per device and any price per device (Savings & optimization → Opportunities → Fax lines in a POTS-replacement order, faxbot savings opportunities pots --name NAME --per-line AMOUNT), or start from the one published per-line price Faxbot could read: Ooma AirDial at $39.95 a line a month including the device, data and service (TouchTone's partner sheet, revision of 25 August 2023, read 10 October 2026; Ooma itself prices AirDial by quote; --published ooma-airdial). From the line inventory's uses, Faxbot says what taking the fax lines out of the order removes from it each month and over the term, how many fewer devices that means, what one shared trunk costs for those numbers instead (its monthly fee and price per received minute from a rate card you saved for your trunk under Costs, else your trunk carrier's published prices, else the carrier with a published trunk fee and number price; a fee a carrier does not publish is said, never counted as zero; calls are priced by the minute, not guessed), and which alarm, elevator and emergency lines must stay because they need a port that works through an outage. Advice only. Tested with a synthetic inventory on SQLite and PostgreSQL; not yet run against a real POTS-replacement quote.
Where each number should live, your NPI record, and prices by where calls start (database revision 0055).
faxbot savings opportunities numbers): for each number your accounts receive on, what its last 30 days of received faxes and its own monthly price cost at the account that carries it and at each of your other accounts that receive. When another account costs less, Faxbot names it with the steps to move (port) the number for that pair of providers: what the current provider must give the new one, how the new one takes the number, its fee and its usual time, with sources read on October 8, 2026 (config/number_porting.json; a fee a provider does not publish stays unknown). An account whose numbers would cost less elsewhere, its fee included, is named too, such as a $10 HumbleFax plan whose one number would cost $1 at Telnyx. Toll-free numbers go only to accounts that take them, and an account that charges for each page received is never suggested. Advice only: Faxbot never ports, releases or cancels anything.faxbot admin npi list|add|remove|check): your NPIs, one per location, and the numbers the NPI registry (NPPES) lists for each, with the date it was read. A number with few calls that your NPI record still lists says "Still printed on your NPI record: keep it."faxbot send --recipient, faxbot recipients check): with the recipient's name, Faxbot warns when NPPES lists the number for another provider ("This number is listed for … in NPPES, not …"), or lists a different fax number for the provider you named. NPPES cannot be searched by number, so the first warning comes from records Faxbot has already read. When a fax is accepted, those stored records (with the recipient's saved name when the fax names none) are checked again without asking the registry, and any warning is kept with the fax and shown in Sent details and faxbot faxes sent show. It never stops a fax, and a registry error leaves the number not checked.faxbot savings opportunities sites, faxbot savings state-prices): a carrier's US prices for calls within one state and between states, such as AnveoDirect's published rate file, price each call from the state of its trunk's site (sites in the US take a state). With trunks at sites in two states, Faxbot says which site's trunk would send a state's faxes for less and the sending rule to add. Telnyx publishes one US price, so for Telnyx where a call starts changes nothing. Faxbot never changes caller ID to lower call charges (FCC, Truth in Caller ID; 47 CFR 64.1601).Tested with synthetic numbers, faxes, NPPES answers shaped like the registry API and rate files in AnveoDirect's layout, on SQLite and PostgreSQL. Not yet run against real systems: a live NPPES lookup, a real porting order, and a carrier's full rate file priced on real calls.
Dense pages: several original pages on one long fax page, as long as the receiving machine allows. Every sent call over the SSL Fax engine records what the other machine said in its handshake (the longest page it takes, A4, B4 or unlimited; its widest page; fine resolution; error correction; its minimum time per line) and how long that call took between pages. Until Faxbot has learned a machine, it assumes A4. Faxbot then stacks whole pages onto pages no longer than that limit (at most one metre for "unlimited"), pixel for pixel, with a faint dotted rule and a small "page 2 of 5" tag between them, cuts only at page boundaries, and splits a single page only when it is longer than the limit. On a call with error correction on one of Faxbot's own engines, it shares the pages out among the same number of long pages so that the fewest cross a 64 KiB partial-page edge, each of which costs one more turnaround on the line, by the coded size of each page in the coding the call uses; the cut inside a page longer than the limit stays where it is. The predictor prices each crossed edge (about 3.3 seconds, measured in loopback). It does so only when the route's billing says it saves: fewer billed pages on per-page routes, fewer end-of-page exchanges (about 3 seconds each) on per-minute routes, and room under a flat plan's fair use. A receiving Faxbot finds the rules and delivers the original pages, keeping the received image unchanged. For a machine without error correction, Faxbot also leaves out the blank bottom of pages it rendered from documents (never of scans or pictures), and a document that is really standard resolution, such as a forwarded fax, goes at standard resolution when it has a call of its own. It is on by default for the phone line and off for cloud providers until you check that the provider sends long pages unchanged. One layout chooser decides the pages of each attempt: it prices the pages as they are, dense pages and, for a recipient who agreed, encoded pages, all from the same original pages, and sends only the cheapest, so they never stack and a fax that moves to another route is decided again. A number's Details in Recipients shows what the machine takes and sets pages per sheet and blank space per number; Delivery setup → Providers & accounts → Delivery routes sets long pages per route and blank space for all faxes; Sent's details say "Sent as 2 long pages instead of 5" for the newest attempt, and Savings & optimization → Savings results has "Pages saved by packing". The command line has faxbot recipients show|set, faxbot delivery providers long-pages, faxbot faxes sent show and faxbot savings results. Proven with synthetic pages, synthetic session logs and fake routes only; no packed page has gone over a real call or through a cloud provider yet.
Peer fax: a fax to an enrolled partner that accepts fax images goes as the exact fax image a call would carry, over the encrypted direct channel, with no telephone call. The image is the fax's own engine image with the header line every page needs (47 CFR 68.318(d): date and time, sender and sending number) printed above each page, at the width a fax call uses. Its resolution, width, compression, page count and SHA-256 travel in the signed manifest, and the receiving Faxbot refuses an image that does not match them before it accepts anything. Fax images are on by default for every enrolled partner, with a switch per partner to turn them off (Recipients → Partners → Accept fax images, or faxbot recipients partners fax-images <partner> off). Each partner learns the choice from a signed statement sent at once, after an upgrade and after enrollment, and repeated in every receipt and answer. Every direct arrival, a fax image or an original, is now filed as a received fax, so mailbox rules, one email, an owner in Work and evidence apply as for any fax. Received, Sent and Work say "Delivered directly as a fax image by …; no telephone call", never "faxed", and Savings & optimization → Savings results counts the telephone calls avoided by direct fax images. Only a signed refusal sends the fax by its normal route in the same attempt; a lost answer is asked about, never sent again. Migration 0034 adds nullable columns only. Tested with two synthetic installations on SQLite and PostgreSQL; not yet run between two live installations.
A reply number on every fax you send (Delivery setup → Sending identity, faxbot delivery identity): the number printed in each page's header line and sent as the station ID, for the whole organization and, optionally, per mailbox. Faxbot accepts only a number one of your accounts gives you, whose faxes reach this Faxbot and, through a rule under Numbers, the same mailbox, and refuses any other with the reason. With none set (and no station ID), faxes show your cheapest number to receive on that reaches a mailbox: a flat plan first, then the lowest receiving price, never a toll-free number, a number billed by the page or one with no known price. The screen names numbers not to publish for receiving and says what caller ID each provider shows: calls show the reply number as caller ID only when it is one of the same trunk's numbers; otherwise they keep the line's number, with the reason. Both fax engines print the date and time, your header text, the reply number and the page on every page (47 CFR 68.318(d)); the SSL Fax engine sends each job's own station ID (UseJobTSI). "Send from mailbox" passes the mailbox once that send option exists.
Junk senders turned away before Faxbot answers (Delivery setup → Blocked senders, Mark as junk on a received fax, faxbot delivery blocked list|add|remove, faxbot faxes received block): Asterisk checks every call from your SIP trunk against the blocked list before anything answers and declines a listed caller with SIP 603, so the call is never answered and no fax arrives to triage. Only an administrator adds an entry, with a reason; it expires after 90 days unless chosen otherwise (Asterisk ignores an expired entry by itself), removal is one click and keeps who removed it, and callers who send no number or withhold it are never blocked. Every call turned away is recorded once, even one made while Faxbot was not connected to Asterisk, and each block and unblock writes an audit row. Faxbot loads the list into Asterisk when it connects and after every change, so a restarted Asterisk gets it back. Blocking applies to calls over the SIP trunk only.
What the far end's fax machine said, on every call of the built-in engine (Asterisk patch 0004, a number's Details in Recipients, Their fax machine, faxbot recipients fax-machine): its capabilities (DIS), the speeds each call trained at, failures to train, its internet address (CSA) and the subaddress a sender gave (SUB), and when fax over IP started and who asked, kept per call (migration 0036). Faxbot learns from its own calls only, never by placing a test call, per number for 30 days: a number whose calls switch to fax over IP only after Faxbot's ten-second wait gets asked at once; a number that keeps failing to train at one speed starts at the speed that worked, one speed lower again if it fails there too, down to 4,800 bit/s, on both fax engines; a caller whose line trained cleanly at 14,400 bit/s over audio is received at that speed. It also remembers, per number and direction, when fax over IP or audio fax failed after the far fax machine answered: with only fax over IP failing, faxes to that number go as audio fax for 30 days, and with only audio failing, Faxbot asks for fax over IP at the answer. Received calls are remembered and shown the same way, but Faxbot still answers them as usual: answering with audio fax only failed, on two Asterisks, for a caller that waits about ten seconds before asking for fax over IP, as Faxbot's own built-in engine does. A call whose fax over IP data never came back still moves the whole trunk to audio fax and teaches nothing about the number. Everything learned is forgotten when the trunk settings or a fax engine's build (its release and Faxbot's patches) change, changing back does not bring it back, and you can forget a number yourself (faxbot recipients fax-machine <number> --forget); each sent fax's details say what its call changed and why (migration 0048). The per-number memory has run only on synthetic call histories and the loopback lab, not on live carrier calls yet. Proven on spandsp 0.0.6: replaying two real send captures reproduces the far end's DIS bytes and three receive captures its DCS, and two Asterisk containers show fax over IP starting 0.8 s after the answer when asked at once (3.4 s otherwise). Internet Aware Fax (fax between fax servers, faster than a phone line) for a fax server you approve per number (another Faxbot or an IAF server such as an SR140; faxbot recipients iaf) or a partner office marked for it, never a carrier call by guesswork: four pages took 1.4 s instead of 29.4 s between two Asterisk containers, with the same pages.
Registered forms (Faxes → Forms, faxbot faxes forms). Import a fillable PDF, whose fields Faxbot reads (text, date and number formats, checkboxes, choices, radio buttons, signatures), or a PDF or SVG template with a field-position file. Each version is kept unchanged under the SHA-256 of its content, and a changed form becomes the next version. Faxbot draws the pages itself: the template is turned into black and white fax dots once, at import, and values are drawn with the DejaVu Sans font shipped with Faxbot and Faxbot's own text drawing, so the same form, values and renderer version give the same dots on any computer. To a verified direct partner, Faxbot sends only the values and the SHA-256 of each page it would have faxed. The partner's Faxbot fetches the form from you once if it lacks it, draws the pages, and files them in Received with the values attached ("Rendered from Referral v3; values attached") only when every page matches. If any page differs, nothing is filed, the partner asks for the full pages, and you decide whether to fax them (Send the pages as a fax, faxbot faxes forms fax); Faxbot never does that by itself, and a lost answer is settled by asking the partner. To anyone else the form goes as an ordinary fax of the same pages. Migration 0038 adds the forms, their versions and the record of forms sent and received. Tested with synthetic forms on SQLite and PostgreSQL: the same pages from two runs, from two processes and against a fixed reference, a fax of the pages that Faxbot's trunk conversion turns back into the same dots, and two installations exchanging forms. Not yet tried between two live installations; cloud fax services draw the PDF themselves, so the dot-for-dot promise covers the trunk path and partners, apart from the header line the fax engine adds to each page.
A monthly budget for each plan, and what each plan has used. HumbleFax's terms keep its unlimited plan for "normal, individual use" without naming a number, so Faxbot gives every flat plan a normal-use budget in pages and faxes, starting at 200 pages and 50 faxes a month (a cautious start, not a limit HumbleFax has promised; HumbleFax's terms read 7 October 2026), and counts what the plan carried, sent and received, since its billing day in the installation's time zone. Like HumbleFax, it counts a fax as the greater of its pages and its started minutes on the line wherever the time is known (a trunk call's own record, or the time HumbleFax reports for a received fax), and pages alone otherwise, saying so on screen; HumbleFax reports no time for the faxes it sends. Allowance plans count against their allowance and then cost their extra-page price (eFax's published plans: 200 pages, then $0.10 a page); a route can also have a minute allowance or a monthly commitment. Savings & optimization → Prices & plans → Your plans this month shows each plan's budget or allowance used and left, what is committed, the bill so far, a day-by-day burn-down, and whose bill a fax falls on when both sides are your own accounts; Change budget and faxbot savings plans budget save the setting plan_budgets, and faxbot savings plans show prints the same view. The shared predictor reads the same billing period, and prices a plan with the allowance and extra-page price you set, else the published plan's. budget_left and marginal in routing/plan_budget.py give the order the sending rules' "cheapest marginal" method should take (toll-free numbers by Telnyx for nothing, the rest by HumbleFax while its budget lasts, then Telnyx, then Sinch), proven on a synthetic month on SQLite and PostgreSQL, and route choice now ranks by it (see sending rules in delivery).
A scarce plan's last pages go to the waiting faxes they save the most on. When a plan has only a few included pages or minutes left (eFax's 200 pages, a normal-use budget near its end, a trunk's minute bundle), giving them to whichever fax comes first can push a dearer fax onto a paid route: two waiting 100-page faxes and 100 pages left, one costing $0.50 another way and the other $50, cost $50 first come, first served and $0.50 shared this way. Faxbot asks the planner what each waiting fax would do, takes first the pages of faxes that use the plan whatever it costs (their rules list it first, or no other route they may use has a known price), and shares the rest among the others as whole faxes, by what each would pay on its best other route, capped by the plan's own price for extra pages. It solves this exactly while the problem is small and otherwise by saving per page, with the gap to the best possible answer shown. Faxes already on their way count as using the plan, so two workers planning at once agree. A reserve keeps pages for faxes not sent yet only when earlier stretches as long as the time left until the plan starts again show, at a 95% lower bound, that they would save more than the waiting faxes pay for it; it takes pages only from faxes worth less per page, never from urgent faxes or faxes with a send-by time, and falls as the plan's renewal nears; Faxbot's own cautious start for an unlimited plan (HumbleFax's 200 pages) keeps no reserve, since the plan never promised it. The allocation only changes which route a fax takes: it never makes a fax wait, never changes a rule, and a fax a cost cap or its rules keep on the plan takes it as before. A fax sent another way says why in Sent details, with the amounts kept when it was sent ("Sent by SignalWire for about $0.12 so your last 100 Phaxio pages this month go to the waiting fax they save more on, saving about $0.076 in all (estimate)."). Savings & optimization → Prices & plans → Who gets your plans' last pages, faxbot savings plans allocation and GET /routing/plans/allocation show what each plan has left, which waiting faxes get it, which go another way and for how much, and what is kept. A plan with no limit and no budget you set gets no allocation; committed monthly spend is not shared out. Proven with every assignment of small synthetic queues against the per-fax policy, a replay of five synthetic months that never reads later faxes, and the real planner and predictor on SQLite and PostgreSQL; quotes (faxbot savings fax --to, /routing/quote) still price each plan against its whole room, and nothing has run against a real eFax or HumbleFax month yet.
Savings & optimization → Opportunities → Other carriers and faxbot savings opportunities carriers: what your last 30 days of sending and receiving would have cost at each carrier's published prices, priced the same way for every carrier and for the services you use now (with every plan fee you pay, also for a plan that carried no faxes), with the cheapest and the difference. Carriers that publish no price are named and left out, a carrier missing a price for some of your faxes or numbers is never called the cheapest, and switching carriers means porting your numbers and a new account. Advice only; checked with synthetic faxes.
Finding partners (Recipients → Partners → Find partners, faxbot recipients partners discover|introduce|may-introduce|publish). A Faxbot whose SSL Fax engine answers a call names its own address in the call (its CSA), and one that places a call does the same (its TSA). When a call's record shows such an address, from the built-in engine's frames or the SSL Fax engine's session log, Faxbot keeps only the host and the number, never the passcode the address carries, and later makes one HTTPS request to https://host/.well-known/faxbot-direct, which is never a fax call. A validly signed partner card for the number that was called becomes a suggestion on Partners, in Savings & optimization → Opportunities and in the Recipients list: "This recipient runs Faxbot. Enroll as a direct partner to send to them without a phone call." Faxbot asks each host at most once a day and makes at most 20 lookups an hour; it keeps every answer, a failure too, until it expires, and contacts a host on a private network only when partners on private networks are allowed. There, a Faxbot's own certificate is accepted, and its fingerprint is shown and kept with the partner, so a later change is noticed. Every Faxbot answers that address with its own card while direct delivery is on (Answer Faxbot lookups, on by default). A verified partner can introduce two of its partners to each other when both records say May be introduced, which is off by default; each receives only a signed hint about the other. An installation can publish its card's number in a DNS directory it controls, as a signed TXT record at _faxbot.<reversed digits>.<directory>, only when it receives faxes on that number. Faxbot gives the record to add and never writes DNS itself. Senders look numbers up only in directories they list as trusted, and check the signature, the number and the expiry before anything is shown. Each found recipient still has to pass the challenge fax: enrolling one makes a partner that is not yet verified. Migration 0045 adds the tables. Tested with synthetic installations, a stand-in DNS and a local TLS server on SQLite and PostgreSQL; not yet run against a live partner.
Email and folder connectors, both directions, each document handled once (Delivery setup → Email and folders, faxbot delivery connectors list|add|update|test|pause|resume|remove|items). A connector brings documents in from an email mailbox (IMAP over TLS only) or a folder inside the Faxbot container, such as a mounted scanner share, through the same import path as POST /imports; documents land in the connector's mailbox, or by the fax number in a sidecar JSON file with the import manifest's fields. Or it sends: email to fax (the number in the subject, as fax+13035550100@…, or in RightFax's gateway addressing, /fax=NUMBER/name=NAME/, in an address or display name at your own mail domain, PDF or TIFF attachments joined into one fax) and folder to fax (a PDF beside {"to": "+1…"}). A message is identified by its Message-ID (or the whole message), a received attachment by its position in it, a folder file by its SHA-256 (and, when sending, its number), so a re-read mailbox, a message Faxbot crashed before moving, or a renamed or recopied file is counted as seen again and never filed or faxed twice; a changed file is a new document. Faxbot moves a message to a processed folder, or a file to done/ or failed/ with a reason file, only after recording what became of it, and reads a file only once it has stopped changing. Email to fax sends only for addresses mapped to Faxbot people who may send faxes, and only when the administrator's own mail server recorded an aligned DKIM, SPF or DMARC pass (Google Workspace's mx.google.com; Microsoft 365, whose header names no server; or the name you enter). A confirmed sender hears the result by email once (sent, not sent, or uncertain with what to do); an unconfirmed message is listed and gets no reply. Each sending connector gets its own key that may only send faxes; pausing or removing the connector revokes it, and the fax and its record commit together, so a key replaced on resume never sends twice. Sign-in by password or app password, a Microsoft 365 app (IMAP.AccessAsApp), a Google service account with domain-wide delegation, or a refresh token (XOAUTH2); the services' rules were read on 7 October 2026. Migration 0041 adds the tables. Tested against a TLS IMAP stand-in and temporary folders on SQLite and PostgreSQL; no real mailbox or scanner share has been used yet.
Fax-friendly shading: shaded areas keep their place on the page in a pattern the fax line sends quickly, every letter, line and mark stays exactly as it was, and each attempt sends the most faithful pages at its lowest expected bill. scripts/fax_friendly_benchmark.py and a later probe of the same synthetic pages (MH, MR and MMR at fine resolution) showed that making everything 25% gray or lighter white takes a shaded table from 61 to 12 seconds at 14,400 bit/s with error correction, but erases the 15% and 25% gray text samples completely. So the default (pages/screens.py) leaves a 4-pixel band around every change of gray, every pure black or white pixel, the PDF's own text and annotation objects (Ghostscript draws them on their own) and the gaps between marks on a line exactly as Faxbot draws them today, and draws only the uniform inside of shaded areas at least 25 pixels wide and 8 rows tall with horizontal stripes. The shaded table goes from 61 to 27 seconds and a form with tinted fields from 51 to 13; the pale text stays pixel for pixel; a noisy scan, a photograph, a gradient and black text do not change. Without the width and height rules the stripes save about a second more on the table, but put lines inside a shaded checkbox. Feng, Fuchs and Bouman's clustered-dot screen ("Image Rendering for Digital Fax", 2003) and a coarser clustered dot were measured on the same pages and code larger than stripes. A fidelity check (pages/fidelity.py) compares each changed page with today's, one kind of content at a time: small type, faint handwriting, decimal points, check marks, barcodes and stamps exactly as they were, highlights and shading still toned, small shaded areas untouched and no light part faded to paper. A screened page that would lose anything goes as it is. Each attempt's layout chooser prices the pages as they are, screened and (only with the opt-in) whitened, in every layout and with its measured coding, keeps the lowest expected bill and, within 0.05 of a billing step of it, the most faithful pages. A faster page wins at the same bill only for the administrator's Always, a send-by time within the hour, or faxes waiting for the phone line, so a page that stays in the same billed minute goes as it is. The setting "Fax-friendly shading on documents you send" (fax_friendly_documents, Delivery setup → Providers & accounts → Delivery routes, faxbot admin settings set fax_friendly_documents=where_it_saves|always|never) keeps its stored values with these meanings, and the earlier on and off still read as Always and Never. "Also make light areas white" (fax_friendly_whiten, off by default) is a separate opt-in that warns it may erase pale text and light marks; removing specks goes only with it. Each recipient keeps its own choice under a number's Details in Recipients and with faxbot recipients set --shading on|off|default; a recipient's Never always wins. Sent's details follow the newest attempt, for example "Shaded areas on 2 of the 4 pages were kept with a fax-friendly pattern: an estimated 35 seconds less on the line at full fax speed.", or say that light areas were made white; migration 0058 records which, and attempts recorded before it read as made white. Faxes sent together in one call get the screen, never whitening, because a shared call is not priced fax by fax. The changed pages are made once per fax and method and kept with its attempt files, and the retention cleanup removes them. Pages Faxbot draws itself and encoded pages are never changed. With the setting at Never, Savings & optimization → Opportunities and faxbot savings opportunities measure your last 10 faxes and say how much time the pattern would have saved on calls billed by time. Migration 0042 records each changed attempt and each recipient's choice. Tested with synthetic pages through Ghostscript on SQLite and PostgreSQL, and with the shared predictor on synthetic prices; no screened page has gone over a real call or through a cloud provider yet.
Guided setup packs (Administration → Setup → Suggested Packs, faxbot admin setup plan|list|show|apply). Faxbot compiles what it already knows (your accounts and rules, the last 30 days of sent and received faxes, the cost, partner, toll-free, relay, send-once, reply-number, junk and busy-hour advice its other pages give) into five packs: costs, partners, receiving, reliability and compliance basics. Each suggestion has its sources and one explanation. A suggestion is a sending rule, a setting, a step only you can take, or a note that Faxbot already does it. Each rule shows its saving over your last 30 days of faxes, estimated by the shared predictor (an unknown price stays unknown, and a rule with no estimated saving is not chosen for you). You state your business name and the country your organization and each mailbox work in; nothing is filled in from the installation country. The 47 CFR 68.318(d) header line is suggested only for mailboxes stated to work in the United States, as a suggestion and not legal advice; other countries are listed as having no reviewed rules yet, and no retention period is ever picked for you. The console’s plan history and faxbot admin setup list let you reopen saved previews. A preview sends nothing and changes no setting or rule. It keeps the plan (migration 0053) with what's missing (each item says whose choice it is, what it affects and whether it holds the plan back) and each mailbox's settings with where each comes from. Applying the chosen suggestions checks your permissions and that neither your settings nor the touched rules changed since the preview, then saves the settings through the normal settings write and publishes each scope's rules through their own draft, check and publish, recording what each part did. A partner enrolment, a relay or send-once offer and a toll-free approval need the other side, so they stay steps with a link to their page and are never applied. Tested with synthetic installations (fresh, cost-heavy, partner-rich, two mailboxes in different countries) on SQLite and PostgreSQL, with the real rules publish, settings write and predictor; templates for regulated workflows are not built yet.
Direct messages and FHIR as delivery routes, with no fax call (Delivery setup → Providers & accounts → Direct messages and FHIR, a number's Details in Recipients, faxbot delivery providers digital, faxbot recipients digital, database revision 0052). A recipient can carry a Direct address and a FHIR server address, either entered by you or suggested from the NPI registry when the NPI you give lists the recipient's fax number. Faxbot uses an address only after you confirm it, and every change is kept and audited. The route planner then offers it beside your fax accounts and prices it by the account's plan through the shared predictor (a missing price is unknown, never free; Inpriva's published $199 a year for three Direct addresses ships as a starting plan, read 8 October 2026). Sending rules can name one address (dsm:<id>, fhir:<id>), name them all as digital (for example try_in_order: [digital, phaxio]), or forbid them with never: [digital]; a rule naming an address that is no longer confirmed is flagged and skipped.
faxbot send and POST /fax take the patient's medical record number (with the system it belongs to), family and given name and birth date, used only for FHIR routes. Faxbot keeps them in one file beside the fax's document and nowhere else: no log line, record or sentence repeats them. Each FHIR client says how its server takes a patient: added when the fax gives one, looked up by medical record number, or confirmed by the server's patient matching from the number, name and birth date. A fax without what that server needs skips the route, says why in one sentence and goes by fax; a patient the server cannot find or confirm sends nothing, and the fax goes by fax in the same attempt. Proven against a fake FHIR server only. What a missing fact costs you (Savings & optimization → Facts to establish, faxbot savings facts). For the last 90 days, grouped by recipient, Faxbot prices what the faxes would have cost by the best route it may use (the accounts its automatic choice may use, plus a verified partner, a confirmed Direct address or an approved toll-free number), and what they would have cost with exactly one more fact established, both with the shared predictor at today's prices. The facts come from a fixed list, each with the step that establishes it and the time it takes you: a partner Faxbot found but you have not enrolled; a Direct address or FHIR endpoint nobody confirmed; no record of what the recipient's fax machine accepts, on a trunk billed by time (priced as an upper bound, with the share of numbers Faxbot has seen that accept the most compact coding); a toll-free number on file without the recipient's approval; documents a recipient already acknowledged, resent because no one recorded that they accept a one-page list instead; a route or receiving price nobody entered and no carrier publishes (given as a count of faxes and the price below which that route would have cost less, never as a saving); and a flat plan held at Faxbot's cautious normal-use budget because its real allowance is unknown. Money a step costs, such as the enrollment fax, is subtracted; your time is stated, not priced. A missing approval is a boundary: the route it would open never counts as allowed, whatever it would cost, and the advice says who must confirm what. Each fact is priced on its own, and a recipient's figure is its largest single fact. These are what past faxes would have cost, never savings; once a fact is established and used, Savings & optimization → Savings results counts what it really saved. Advice only: Faxbot never enrolls, approves, enters a price or changes a route. Tested with synthetic installations and history rows on SQLite and PostgreSQL, with the real predictor and number placement; not yet run on a live installation's history.
A read-only setup portfolio planner in Savings & optimization → Facts to establish and faxbot savings portfolio --file scenario.json (POST /routing/portfolio/plan, settings-read permission). You state whose costs and benefits count, one currency and time period, a spending limit, up to ten setup items, shared setup costs and expected/cautious running-cost reductions for connections between pairs of items. Negative benefits represent higher running costs. Faxbot checks every affordable group, counts shared setup once, excludes installed costs and already-active benefits, and returns the expected plan and the plan with the best lower result across both scenarios. Unknown amounts needed for a new plan stay incomplete; a plan with no positive net benefit adds nothing. Inputs are not saved; nothing is enrolled or applied. Checked with synthetic cases, independent exhaustive comparisons, authenticated API/CLI checks and console tests; these are modeled plans, not measured savings.
Needs attention on Overview and in faxbot overview: held faxes, sent faxes with an uncertain result, failed sends, received faxes waiting for an owner or overdue, email delivery failures, overdue expected faxes and expected faxes with a match to confirm, plus carrier charges with no matching fax and the network check for fax over the internet. Items are grouped by the action they need, and each opens its exact list, whose filter stays in the page address so a link, a reload and Back show the same list: Sent by status and by the last hours (?status=failed&since=24h, the same faxes the count counts; faxbot faxes sent list --hours 24 and GET /admin/fax-jobs?since_hours=24 do the same) and the faxes your rules hold (?show=held), Received by ?show=, and Expected by ?show=overdue or ?show=proposed. The command names the matching faxbot command for each. A provider or fax engine that is not ready and an uncertain result are marked serious. Each source keeps its own state: one this account may not read or one that failed is named without a count, and "Nothing needs attention" appears only when every source answered. Tested with one shared set of synthetic answers for the console and the command.
A value-first Overview, with faxbot overview printing the same blocks. What Faxbot is doing lists the capabilities that acted on your faxes in the last 30 days, each opening its Capabilities page, and the results in their own units: money (the Savings estimate), pages not sent, call time saved, calls avoided and data not sent again. Each unit lists its parts and is never added into one total, because two parts can act on the same fax. Next improvements lists capabilities ready to turn on, cheaper routes and missing facts, each marked "You can do this now", "Needs a fact", "Needs a recipient's agreement" or "Experimental" and opening its capability or opportunity. Everyday faxes has Send a fax and the Received, Sent and Expected counts, with the status and delivery cards; an installation that only receives says so instead of looking broken. Needs attention follows, and moves to the top while a serious problem lasts. The map of every way Faxbot saves money stays at the bottom. Each block has its own loading, empty, refused, failed and stale state and its own time; a status poll changes only the status time. A new installation sees which connection would make which capabilities work right away. Nothing invents a saving: a quiet installation says it has no results yet. Without permission to read settings, the value blocks say they are not available and are never asked for. Tested with shared synthetic answers for a healthy, new, quiet, receive-only, incident, failed-source and restricted installation, plus stale times; not yet clicked through in a browser.
A live outbound board at the top of Overview and, in short, on Sent, with faxbot status (--watch shows it again every 5 seconds) and GET /outbound/now giving the same sections in the same order. It shows what is sending now (by which route and fax engine, since when), how many faxes wait and why (a free line, another fax calling the same number or one with an unknown result, the recipient's fax hours or busy times, going in one call with other faxes, a later hour, another try, being prepared, or next to go), what needs a decision with the actions you may take there, how today went with failures grouped by how they ended, how full each phone line and limited account is (calls coming in counted), when Faxbot has switched new calls on your phone line to audio fax and how it switches back, and the progress of each sender with 5 or more faxes today. Each person sees only the faxes Sent lists for them. One read every 2 seconds serves every viewer and counts in the database rather than loading every fax, and each person's visibility is read once and kept for up to 30 seconds or until access changes, so polling adds no database write lock beyond signing in; a section that cannot be read is named and the rest still shows. faxbot status <fax id> still shows one sent fax. Tested with synthetic deliveries through the real claim, schedule and hold code on SQLite; not yet watched on a busy installation.
Where Faxbot may dial, a guard against toll fraud that also caps cost (Delivery setup → Providers & accounts → Where Faxbot may dial, faxbot delivery providers destinations list|allow|block|reset, GET/PUT /routing/dialing, migration 0068). Every fax is checked once, when it is accepted, against the number its calls will dial. Numbers in your own country (geographic, toll-free and mobile) are allowed. Another country is allowed when this installation had already delivered a fax there over a call before it started checking (recorded once, with the date of the first one), when an active routing rule names it, or when a saved recipient is there. Premium-rate, special-service (such as UK 070 personal numbers) and satellite or international network numbers (+870, +881, +882, +883) are never dialed unless you allow that exact kind of number. A fax to anything else waits in Sent with one sentence and the usual Approve and Refuse; approving one fax never dials a premium-rate, special-service or satellite number while that kind is still blocked, and a partner's relayed fax that would wait is refused instead. Each kind of number or country can also have a price ceiling a minute (none by default): a fax whose cheapest allowed route costs more, or has no known price a minute, waits for approval. Routes that bill by the page or by a plan count as within the ceiling, and the check runs at acceptance only. Every change is a new, kept row with who made it. Tested with synthetic numbers through the real acceptance and approval paths on SQLite and PostgreSQL; not yet run against a real carrier's premium-rate or satellite ranges.
A header notice instead of a cover sheet (Delivery setup → Sending identity → Header notice, faxbot delivery identity notice show|set|clear [--mailbox], GET/PUT /header-notice, migration 0073). The organization, and each mailbox, may set one line of notice text, such as a confidentiality notice. Faxbot prints it at the top of every page of faxes sent from Send a fax, faxbot send and POST /fax, under the header line the fax engine prints; each page's content is scaled down a little so nothing is covered. The sender may mark the first page as a cover sheet whose notice goes in that line instead (The first page is a cover sheet on Send a fax, faxbot send --cover-in-header, the cover_in_header field). That page is then not sent, every price, quote, cost cap and approval counts the pages that are sent, Sent details say so, and the sender's whole document is kept beside the fax. A recipient marked as needing a cover sheet (a number's Details in Recipients, faxbot recipients set --needs-cover) always gets it. Faxbot never removes a page by itself, and refuses the fax rather than send it without the notice. Faxes that come in by email or from a folder, forms, case packets and partner relays are sent as they are. A fax sent from a mailbox now shows that mailbox's own reply number in its header line, station ID and caller ID on both engines. Tested with synthetic documents on SQLite and PostgreSQL, including the fax image both engines send; not yet run on a real call.
The station check and the 50-second cap on waiting for a fax answer (asterisk patch 0007, migration 0074). Before any page, the built-in engine compares the station a number answers as (the fax number its machine shows) with the number dialled and the stations it showed on earlier successful calls (kept 180 days) or that a person confirmed (365 days). A blank or short station is no signal, and a national number is matched against the international one. By default the fax goes on and Sent details name the station; a recipient (a number's Details in Recipients, faxbot recipients set --station-check refuse) or a mailbox (Delivery setup → Sending identity, faxbot delivery identity station-check refuse --mailbox) can choose to hang up before any page instead. That is a definite failure no other route takes, and a Work item asks you to confirm the number with the recipient. The SSL Fax engine has no such hook, so on its calls the check runs after the call and Sent details say so. On a trunk billed by the minute in steps of 60 seconds or more, a call on which no fax answers ends 50 seconds after answer instead of after spandsp's 60, so a person who stays on the line costs one minute, not two (T.30 expects identification within T1, 35 ± 5 seconds). Proven in loopback on two Faxbot Asterisks over T.38: a receiver that answers as another station is refused before any page, or sent to with a warning, a matching station is quiet, and a silent answer ends 50 seconds after answer. Not yet run against a real carrier or fax machine.
A switch for the 50-second answer cap on each trunk (migration 0075). It is on by default; Faxbot's built-in fax engine uses it only where the trunk's calls are billed by the minute in steps of 60 seconds or more (the SSL Fax engine keeps its own wait), and the sentence beside the switch says whether it is in use and why (Delivery setup → Carrier trunk → Fax settings, faxbot delivery providers trunk answer-cap [on|off] [--account KEY]; an extra trunk has its own answer_cap setting). When the cap ends a call, Sent details say so, with the billed step the call fitted in, from the trunk's billing step kept when the result arrived (on 60-second steps, one minute instead of two). The station check's mailbox choices can now be read where they are set (faxbot delivery identity station-check with no mode).
Public test lines in Diagnostics (research N10, migration 0075). On your request only, Faxbot sends its own one-page test page to one of seven lines whose operators invite test faxes, each listed with its source and the day it was read: Faxbeep in the US, the UK and Australia, GotFreeFax and Tokonet (public pages), HP's fax test service (faxes a reply), and Interpage ReFax (faxes your pages back). The dialing guard is never bypassed: a line in a country Faxbot may not dial yet is not sent, and you can allow that country there, with your confirmation, through the guard's own change. Diagnostics says whether the number your calls show and the number at the top of your pages reach this Faxbot. A reply from the line's own number is labelled Test reply in Received; a fax from another number during the wait is offered for you to mark; silence is "no answer from the service", never a receive failure. Faxbeep's public page for your fax is looked up in its public read-only API when you ask. Test faxes never open a Work item for a person who answered or a station that differed (Administration → System health → Public test lines, faxbot admin diagnostics test-lines list|send|show|receipt|reply). Not yet sent to a real line from a production install (the live campaign owns real sends); the HP entry has no captured invitation wording.
Keys pressed after answer, for a fax machine behind a phone menu (a number's Details in Recipients, Phone menu before the fax machine, faxbot recipients set --after-answer 2w105, GET/PUT /routing/after-answer/{number}, migration 0076). After the number answers, and while the call is still an ordinary voice call, Faxbot presses the keys you saved (0 to 9, * and #, with w for a half-second pause and W for a one-second pause) as telephone events, and only then starts the fax: the built-in engine runs SendDTMF before SendFAX, and the SSL Fax engine's call is dialled with D(), which sends them after answer and before the call is joined to the engine. Only a trunk can press keys, so a cloud service or a partner's relay never takes such a fax; without a trunk it waits in Sent with one sentence. On these calls the station check expects only the stations the fax machine behind the menu showed or you confirmed, never the switchboard number, and the 50-second cap on waiting for a fax answer is off, because the time in the menu would use it up. Sent details say which keys each call pressed and that the seconds in the menu are billed. Proven in loopback on two Faxbot Asterisks: a stand-in menu that answers and waits for one key heard 2 and passed the call to the receiver, which took a two-page fax over T.38. Not yet run against a real phone menu or carrier.
Route problems, told apart from number problems (Administration → System health → Sending routes, faxbot admin diagnostics routes list|close|test|send|show-test|upstream, GET /routing/families, migration 0072). Faxbot groups its calls by route family: the account, fax over IP (T.38) or audio fax (or the fax service's own calls), the stage at which a call failed, and the trunk's settings generation. When failures in one family reach three different numbers after a common change, make up most of the route's calls since then, and at least two of those numbers went through before the change or by another route, Faxbot records a route problem, with the change point (a trunk settings change, or the first failure when something outside Faxbot changed). While the problem lasts, and afterwards for its whole window, those failures are not lessons about the numbers: Faxbot neither remembers them per number nor lowers a number's speed because of them, and lessons it had already written are set aside when the problem ends (two numbers going through on the route again, a settings change, a quiet week, or you closing it). The 2-by-2 test sends one test fax by each of two of your accounts to each of two of your own numbers, each only when you send it, pinned to its account, and says whether a route, a number or something both share is at fault. You can also record which upstream carrier a provider publishes that it uses, with the page and date, so Faxbot can say when two routes share a path; unknown stays unknown, and nothing is inferred from SIP headers. Route choice ranks an account with an open problem on every transport it would use after every reliable one; a trunk's T.38 problem alone leaves its audio fax in use. The schedule leaves those failures out of a number's busy hours and call timings. Tested with replayed synthetic call histories through the real learning code and the real acceptance path on SQLite and PostgreSQL; not yet run against a real trunk or a second carrier.
An analog line through a gateway as a flat-rate local route (Delivery setup → Carrier trunk → Analog line through a gateway, then Local calls on this line; faxbot delivery providers trunk use grandstream-ht813, faxbot delivery providers trunk analog-line import|show, GET /routing/analog-lines/{account}, PUT /routing/analog-lines/{account}/local-calls). Presets for the Grandstream HT813 and GXW4104/GXW4108, the Patton SmartNode SN4112/SN4114 FXO and the AudioCodes MediaPack MP-114/MP-118 FXO list, in order, what you set in each gateway, from each vendor's documentation with its address and read date: peer-to-peer with Faxbot by address (no registration), one-stage dialing, every call on the line forwarded to Faxbot, and T.38 between the gateway and Faxbot on the local network. The gateway is reached on the local network like a phone system, as a first or an extra trunk, and carries one call at a time unless you set Calls at once to the number of lines. The line's local calling area comes from a file you save (the Local Calling Guide's Local prefixes page as HTML or XML, a carrier's CSV, or one prefix a line) and becomes $0 prices on the line's rate card beside the per-minute price you enter for other numbers, so the usual price ranking sends local numbers out on the line and the rest the cheapest known way; without that price a call on the line stays unpriced, never $0. Importing the area also makes the line one of your delivery routes, added after the routes you already have as an audited settings change, and says so with a one-step undo (Turn off, faxbot delivery providers trunk analog-line routing off). Faxbot never queries the Local Calling Guide itself, because its operator asks automated users to cache results and publishes no terms. *70 before the number cancels call waiting on each call where the exchange offers it, and a "ten digits for local numbers" format serves exchanges that refuse a 1 before a local number. Not yet run against a real gateway, line or carrier bill.
Faxbot as the fax annex behind a Microsoft Teams Direct Routing SBC (Delivery setup → Carrier trunk → Your phone system → Microsoft Teams SBC, faxbot delivery providers trunk teams-annex --vendor audiocodes|ribbon|oracle|anynode [--address] [--numbers]). Presets for AudioCodes Mediant, Ribbon SBC Edge, Oracle Enterprise SBC and TE-SYSTEMS anynode list, from each vendor's own documents with their addresses and read dates, how the SBC sends the fax numbers to Faxbot as an IP peer before its Teams route and how Faxbot's faxes go out through it to the carrier, so the fax leg never reaches Microsoft (Teams has no fax endpoint and no T.38). A five-step checklist splits the fax numbers out before the Teams port order. Where a vendor's guide does not cover a detail (Ribbon's entry order, anynode's T.38 setting), the step says so. Not yet run against a real SBC or tenant.
Copiers that fax over the network, and copiers that send by email (Delivery setup → Carrier trunk → Copiers that fax over the network, faxbot delivery providers trunk copiers [COPIER], GET /admin/sip/copiers; Delivery setup → Email and folders → Copiers that send by direct SMTP, faxbot delivery connectors add --copier '[email protected] 192.168.1.40'). Ricoh IM IP-Fax, Konica Minolta bizhub IP fax (SIP) and Xerox WorkCentre Fax over IP are listed with what each maker documents for SIP with T.38; Canon, Sharp and Kyocera are listed as not found rather than assumed. An email connector admits a listed copier's mail without DKIM or SPF only when your own mail server's topmost Received header shows it connecting from that copier's private address. A copier can also register to Faxbot as its own extension (below). Not yet run against a real copier.
Copiers as extensions of Faxbot (migration 0085), store and forward (Delivery setup → carrier trunk → Copiers that fax through Faxbot, faxbot delivery providers trunk copier-extensions add NAME EXTENSION --mailbox ID --number +1...). A copier with an IP fax option registers to Faxbot's Asterisk with a user name and a password Faxbot shows once and keeps only as pjsip's MD5 digest; its endpoint takes registrations and calls only from private addresses. Its fax is received by Faxbot's own engine and queued as an outbound fax from the copier's mailbox to the number it dialled, through the same sending rules, dialing guard, holds and Sent as any fax, under the copier's own sending key; it is never bridged to the trunk, the copier's call completes when Faxbot has the pages, and a fax Faxbot can't queue is filed in Received with why. Faxes received for a number you give the copier go on to its extension (or stay in Received when you choose), and one the copier doesn't answer stays in Received with that sentence after two tries. Proven in loopback (10 October 2026, make native-proof-style run of tests/test_copier_loopback.py on the built Asterisk image): a second Asterisk registered as the copier with the issued credentials, sent two pages to an outside number, Faxbot's engine handed them over with the dialled number and the real API queued them to that number from the copier's mailbox; a fax Faxbot sent on to the extension arrived at the copier with both pages. Contract tests cover the rest on SQLite and PostgreSQL. Not yet run against a real copier.
Fax servers that send through Faxbot, such as OpenText RightFax with a Brooktrout SR140 whose Primary Gateway is Faxbot (migration 0086), store and forward (Delivery setup → Carrier trunk → Fax servers that send through Faxbot, faxbot delivery providers trunk fax-servers add|list|change|remove|faxes, GET/POST /admin/sip/fax-servers, PUT /admin/sip/fax-servers/{id}, GET /admin/sip/fax-servers/calls). Faxbot answers a fax server's SIP call with T.38 or audio, takes the whole fax and sends it on to the number the server dialled as its own fax, so route choice, coding, packing and direct delivery to partners all apply; a call to one of Faxbot's own numbers stays a received fax. Only a server you enrolled can send: it never registers, it is recognised by its one address on your private network and proves itself with SIP digest authentication on every call (Faxbot shows the password once and keeps only pjsip's MD5 digest), and it has its own SIP port, published only on your network's address by docker-compose.fax-server.yml, never on the carrier's connection. Before answering, Faxbot refuses, with a SIP code the fax server shows as a failure, an emergency or short number, a country you did not allow for that server, a number its dialing guard does not allow, a fax its sending rules would hold, and a call over the server's limits per hour or per day; it removes an outside-line prefix you set. One SIP Call-ID is one fax, and a call that ended before every page arrived sends nothing. The fax server shows a fax as sent once Faxbot has it, so Faxbot keeps the real outcome: one record per call, the fax in Sent under the server's own sender, and one notice to the server's contact email or webhook when a fax fails, may not have arrived, or could not be sent; an uncertain fax is never sent again and an uncertain notice is never repeated. Tested with synthetic contract tests through the real sending rules and dialing guard. A stand-in for the SR140 (tools/sr140-emulator, Faxbot's own Asterisk placing an authenticated SIP/T.38 fax call) is ready for the live test; not yet run against Asterisk, that stand-in or a real RightFax server.
Who called: a caller-verification stamp on received faxes (Faxes → Received → Who called, Delivery setup → Carrier trunk → Registered senders for received faxes, faxbot delivery providers trunk caller-check show|set|fax, GET /caller-check/faxes/{inbound_id}, GET/PUT /caller-check/registered). On a trunk whose carrier passes its STIR/SHAKEN result, Asterisk keeps the call's Identity header and the verstat on P-Asserted-Identity or From, and each fax the built-in engine receives keeps, in its import report, one of three stamps: verified and registered, verified but unregistered, or unverified, with the reason. The network's word is the carrier's verstat (TN-Validation-Passed) or a SHAKEN attestation A whose signature Faxbot checks against the certificate authorities you trust for forwarded calls; registered senders for received faxes are an audited setting, separate from the sending side's registered-sender pins. The stamp reports what the network asserted about the call, never that the document is genuine. Faxes the SSL Fax engine receives are not stamped yet. Not yet run against a real carrier's STIR/SHAKEN result.
Receiving readiness, number by number (Administration → System health → Receiving readiness, faxbot admin diagnostics receiving check|owner, GET /receiving/readiness, POST /receiving/owners, migration 0072). Receiving is judged only from receiving evidence, so a working internet connection or sending route never marks it healthy. For a trunk, Faxbot reads whether the trunk is signed in to the carrier (or that it needs no sign-in) and when the last call to the number arrived; Faxbot keeps no record of the carrier's OPTIONS checks, so they are not read. For Sinch, Phaxio and eFax, which post received faxes to Faxbot, it asks its own receiving address, through the public address and any tunnel in front of it, for a one-time code only this server issued, so another server answering never counts. Every number also shows when its last fax arrived. Each number can have one named receiver (one of your receiving accounts, or a receiver outside Faxbot such as the fax machine at reception): naming a second one is refused unless you move the number on purpose, two changes made at the same moment cannot both win, and a fax that still arrives elsewhere is kept and named. Tested with synthetic numbers through the real server on SQLite and PostgreSQL; not yet run against a real carrier, tunnel or backup line.
Power-aware sending (Administration → System health → Power, faxbot admin diagnostics power show|set|off, GET/PUT /power, migration 0072). Off until you set a UPS, then on by itself: Faxbot reads it through Network UPS Tools (NUT's network protocol on port 3493, as upsc does) and changes nothing while it is on mains. On battery, a call on this server's own trunk may start only when the fax's 90th-percentile call time from the predictor, plus the minutes to spare you set, fits in the battery's remaining runtime; a fax service only needs Faxbot to hand the fax over, because the service places the call on its own power. When a call does not fit, Faxbot prefers an approved route in the other power domain, or keeps the fax waiting, unsent, in Sent with one sentence, urgent faxes included; an unreadable UPS or an unknown call time never holds a fax. Faxbot checks this when it binds a fax's account: a trunk call that could outlast the battery goes by the next approved account in the other power domain, and if none can take it, the fax is held in Sent with that sentence. It then waits for you to check it again in Sent; it is not yet released by itself when the power returns. Tested with a fake NUT server; not yet run against a real UPS.
NTT Hikari Denwa in Japan, built from what NTT publishes (Delivery setup → Carrier trunk → NTT Hikari Denwa, SIP_TRUNK_PRESET=ntt-hikari). The trunk signs in over IPv4 by UDP or TCP to the SIP server NTT's network hands out by DHCP, sends G.711 mu-law and dials national 0AB-J numbers. NTT's interface lists the Japanese T.38 standard and allows fax over IP between Data Connect devices, but its detailed interface is not published, so Faxbot offers T.38 exactly as ITU-T T.38 Annex D describes it and says to confirm the settings with NTT first. The rate card prices an ordinary call at NTT East's ¥8.8 per 3 minutes to fixed lines, and Data Connect is priced by the bandwidth held (¥1.1, ¥1.65 or ¥2.2 per 30 seconds up to 64 kbit/s, 512 kbit/s or 1 Mbit/s, and ¥16.5 or ¥110 per 3 minutes for several sessions at once, tax included, read 10 October 2026 from NTT East's price page and NTT West's Data Connect manual), counting every started unit. The trunk page states NTT's documented limits: Data Connect only between Data Connect devices on FLET'S Hikari Next, charged while the bandwidth is held, FAX notification email not working for Data Connect faxes (and ending in March 2028), and residential Hikari Denwa carrying fax as voice. Not yet run against NTT.
faxbot delivery rules, faxbot delivery providers accounts, faxbot faxes sent route|approve|refuse|check-again, faxbot faxes sent list --held, faxbot delivery numbers explain, faxbot send --mailbox --workflow --label and faxbot savings fax --to.The rules engine, the accounts and delivery have landed; none of it has run against a real system yet.
Live fax-friendly shading: one fax with a shaded table over Telnyx and one through Sinch, comparing billed seconds and the received page for the pages as they are, screened and whitened (opt-in). For providers that fetch the document themselves (SignalWire bills per minute), check that the screened PDF Faxbot serves at the fetch address goes out unchanged, and look at a received screened page at normal reading distance.
Live confirmation of SIP Call-ID matching in both directions and of the hourly check for calls Faxbot has no record of. Still to run live: the SignalWire and Flowroute call-record readers, Sinch and Phaxio received-fax charges, and the listing of each provider's faxes.
Live eFax sign-off with a real eFax Corporate API account.
Live HumbleFax receiving: on 10 October 2026 a one-page fax sent from the acceptance install to +13034265097 arrived in the partner Faxbot's Received through HumbleFax polling about a minute later, and its PDF downloaded through HumbleFax's real API; seventeen earlier test faxes from the trunk to that number are also in its Received.
Live combined call over a real trunk for sending together, and live automatic audio switching after a failed T.38 call.
Live per-number fax memory: a real number whose fax over IP calls fail and whose next fax then goes through as audio fax. For received calls, a real carrier caller whose fax over IP calls to Faxbot fail and then succeed when Faxbot answers with audio fax; only that evidence would justify answering such callers with audio fax, which stays off until then.
Live sign-off of the Avaya IP Office, Avaya Aura, BT One Voice, Gamma and Telstra SIP Connect presets on real systems.
Live SSL Fax calls over a real trunk, sent and received, with a fax machine that offers SSL Fax.
Live route choice by cost per delivered fax, once a number has delivered faxes on two metered routes.
Live Telnyx Fax API: create the Fax Application from the console, assign it an outbound voice profile in Telnyx (leaving the fax number on the trunk, unless Telnyx refuses to send from it otherwise), send one fax to a working fax machine and one to a busy number, check the status reads and the signed results notices, and compare its cost per delivered fax with the trunk (by the minute) and HumbleFax (flat plan) on the same documents.
Live Sinch: a fax sent through Sinch, a fax received on the Sinch number, the charge Sinch reports for the sent fax, and route choice with Sinch beside the trunk and HumbleFax.
Live check of delivery inside Faxbot: faxbot send to the trunk's own number arrives in Received in seconds, with no call record.
Live sending rules: a rule-driven fallback on a real busy number, a hold approved in the console, a quote against a real HumbleFax plan, SignalWire as a live second provider, and mailbox and workflow scopes in a real organization; Documo's and eFax's failure codes read from their own API references.
Live second trunk: a second SIP connection at Telnyx (or another carrier) sending and receiving beside the first, each fax recorded on its own trunk, and a send-only number shown after the carrier verifies it.
Live receiving on several accounts: a fax to the trunk, the HumbleFax number and a second account in one session, each showing its account, and a number rule placing one of them; a fax sent with a subaddress to the installation's own number to see whether Telnyx carries the SUB.
Live check that a second fax to a busy single-line number waits for the first and then goes through, with no busy retry.
Live connectors: a real Microsoft 365 mailbox signed in as an app and a Google Workspace mailbox through a service account, with replies through their outgoing servers; the Authentication-Results each one really writes for mail from inside the organization (Microsoft 365 may record no DKIM or SPF pass for internal mail, which Faxbot would refuse); and a real scanner writing to a mounted share.
Check the predictor against carrier charges on live calls.
Local relay through a partner (Recipients → Partners → Relay, faxbot recipients partners relay): an enrolled partner, often your own office in another country, sends your faxes as local calls there, and several partners' faxes to one number can share a call through it. A sending rule that names a partner's relay (relay:<partner>) uses it at its place in the rule's order, or ranks it by cost with your own accounts when the rule asks for the cheapest. Built and tested with three synthetic installations on SQLite and PostgreSQL.
relay:<partner> like an account, and "never relay" is a limit.relay:<partner>) or forbid relays; a fax being relayed for a partner is never relayed again.direct.relay.sender_identity_for). Not yet run between live installations or against a carrier. Each sent fax whose outcome Faxbot could not confirm becomes owned work, with the ways to find out ranked by cost (migration 0047). A fax that waits for confirmation, or whose call failed part way, gets one item. It goes to the person who sent it, else the backup person of the mailbox it was sent from, else the person you choose under Delivery setup → Mailboxes (faxbot faxes sent uncertain-settings), with a time to settle it (24 hours unless you change it); when that time passes it moves once to the person you chose. Faxbot runs the two free checks by itself. The first is an enrolled partner's signed answer: the direct path's own records, or one signed question about a call your own fax line placed. The second is the call's length against how long the fax needs, which reads as "probably not delivered" or "fits a delivered fax" and never as proof; Telnyx's call records and SignalWire's fax records give the length, while Phaxio and Sinch report none (their API references, read 7 October 2026). A one-page receipt query (tick a box and fax it back) and a phone script come next; the receipt query, like sending the fax again, goes only when a person selects it, and only once. When the fax is delivered after all, by a partner completing the broken call, a late result from the fax service or a confirmed receipt, the item closes by itself and says so ("Closed: the fax was completed directly by Lakeside"). Otherwise only a person settles it: delivered, not delivered (optionally sending the same document again as a new fax, linked both ways) or can't tell. Faxbot keeps who decided, why and what the checks showed at that moment. Delivered or not delivered also ends the fax itself as sent or failed, so its number is no longer held for an unknown result and the next fax to it goes at once; nothing is sent again unless you choose to. Can't tell ends the fax too, as failed with the sentence "Settled as can't tell: it may have arrived, so check before sending again." Its status in the API stays failed, but Sent and faxbot faxes sent list show it as "Can't tell" with that sentence, never as delivered or as a bare "Failed"; it is left out of the failed faxes today and the last 24 hours' failures and counted on its own (cant_tell, recent_cant_tell); and a partner that relayed it or a fax server's contact is told only that it may have arrived; a result that comes for it later is kept in its history but no longer changes it, and a provider fax ID can no longer be attached to it. A fax you settled before this worked that way (can't tell until 13 October 2026) is ended the same way once, by itself, under the name of the person who decided and at the time they decided. Sent's details, Faxes → Received (Sent faxes to settle) and faxbot faxes sent uncertain, probe, settle and assign show and do the same. A partner's notice fax and the first pages of a repaired call no longer stand beside the document as their own Work item or email: a fax of one or two pages that arrives while a document waits for its notice is held back until it has been checked (at most 15 minutes), and once it is paired or the call repaired, its item closes into the document's with the reason. In Faxes → Received and faxbot faxes received show, a repaired call's first pages say where the whole fax is ("Pages 1–6 of this fax were completed directly by Lakeside; the whole fax (10 pages) is in Received.", and completed_in in the API); they stay as they arrived, with their own record, and an email already sent for them cannot be recalled. The receipt query and a fax sent again go through the sending rules like any other fax, so a rule can hold them. Tested with synthetic faxes, a stand-in partner and the direct path's notice and repair tables on SQLite and PostgreSQL; the partner question has not yet run against a real partner.
Send only the pages a broken call did not confirm, to any recipient (migration 0050). When a fax fails part way through its call, Sent's details, the fax's uncertain item (beside "send it again") and faxbot faxes sent continue offer Send pages 8–20: a new fax of only the pages the receiving machine did not confirm. Faxbot prints one line at the top of its first page naming the fax it continues ("Continuation of our fax of 7 October 2026 at 9:41 AM MDT, 20 pages: pages 8–20. Pages 1–7 arrived on the first call."), in a band above the page's own content, which it scales down a little, so nothing on the page is covered. Only a person sends it, and the screen says that the first of those pages may arrive twice. It is priced against the whole fax on the account the sending rules would choose ("About $0.91, against $1.40 for the whole fax."), goes through the sending rules like any fax (so its route may differ and a rule can hold it), and is linked both ways with the original in Sent; from the uncertain item it also settles the fax as not delivered. Its fax ID comes from the broken call, so a second click, or a click in the other place, sends nothing more. Faxbot offers it only when the call's own record proves which pages arrived: the built-in engine's page count with error correction, or without it on a call that never had to train again; the SSL Fax engine's count with error correction, or without it only the pages the receiving machine answered "received fine" before the first damaged one (read from the call's session log); and the counts of pages sent that Sinch, Documo and HumbleFax report. Phaxio and SignalWire report no such count (their API references, read 8 October 2026), so their faxes get only "send again", as does a fax whose pages were packed onto longer pages, one sent in a shared call, and one whose outcome is uncertain. A call that broke after pages went is now always marked partly sent, so it is never sent again whole by another route on its own: the built-in engine's call with pages confirmed, a Documo failure with pages completed, and a HumbleFax "partial success" or attempt that sent pages, and a FreeSWITCH call whose fax_document_transferred_pages is above zero join the SSL Fax engine and Sinch, each waiting for you as an uncertain fax. Tested with synthetic faxes and call records, and the new tables on SQLite and PostgreSQL; no live call has been broken on purpose yet, and Documo's page count comes from the search-result text of its help pages, not a real account.
A person who answers is never called again by itself. When sound comes back on a fax call, no fax signal ever does and the other end hangs up first, a person or a voice line answered: the fax fails with "A person answered, not a fax machine; Faxbot did not call again.", takes no other route (inline or through the fallback scheduler), and becomes owned work: "A person answered at this number; check the fax number with the recipient", with a phone script for the right number, the NPI registry when the recipient is a healthcare provider, and no receipt query page. It is sent again only when a person settles it and asks. This covers the built-in engine, the SSL Fax engine (No carrier detected after sound came back), calls that carry several faxes, and HumbleFax when its reason names a voice answer. A line that stays open with no fax signal until the timer runs out may be the route, so another route may still try it. A call the far end answers and hangs up within 2 seconds (under 3 seconds of real time, as Asterisk counts whole seconds) is not a person either: a person hangs up only after hearing the calling tone, and no fax machine could have answered that fast, so it is a service turning the call away. The live pilot on 2026-10-10 found HP's toll-free test line doing exactly that, and Faxbot had written it as a person answering. Such a call now fails with "The number answered and hung up at once; its fax service may be busy.", before any fax data, so another route or a later try may take it and it opens no Work item; this covers the built-in engine, the SSL Fax engine and shared calls, while FreeSWITCH and HumbleFax report no answer time and are unchanged. Sinch, Phaxio, SignalWire and Documo publish no reason that says a person answered (their own error lists, read 2026-10-08), so their failures are unchanged. Proven with synthetic calls on SQLite and PostgreSQL; not yet run with a real person answering.
Live certainty checks: a receipt query faxed to your own number and ticked, a Telnyx call record compared with the predicted length, and an enrolled partner asked about an uncertain call.
Live continuation: break a long fax on purpose over Telnyx on each fax engine and send only its remaining pages, and check Sinch's pagesSentSuccessfully and Documo's pagesComplete on a real failed fax.
Live partner relay: the acceptance install sends a fax through the partner install once that has its own Telnyx number, with the signed receipt, the header line and both sides' costs checked.
Live peer fax between two installations: a fax image accepted, filed in Received with an owner and emailed once, with the same SHA-256 at both ends.
Live check of the reply number: a fax from the Telnyx trunk to your own HumbleFax number shows the reply number in its header line and as the station ID on both engines.
Live check of junk screening: block your HumbleFax number, fax from it to the Telnyx trunk, and see the call declined with no billed seconds in Telnyx's call record.
Live checks of patch 0004: the far end's DIS recorded on a real Telnyx call, T.38 asked at once for a number that never asks, and Internet Aware Fax to the partner Faxbot over its own Telnyx number (whether Telnyx keeps T.38 end to end between two of its numbers is unknown until that call).
Live exchange of a registered form between two installations, including a form fetched by the receiver and a mismatch that a person resolves by fax.
Route choice by each plan's budget (the rules' "cheapest marginal" method), and a live check: one fax each way through HumbleFax and Telnyx with the plan counters compared.
Live plan allocation: a real eFax or HumbleFax month near its allowance with two faxes waiting at once, the plan's own count compared with Faxbot's afterwards, and quotes that price a plan after the pages held for waiting faxes.
faxbot recipients fax-machinefaxbot delivery providers trunk negotiation Notice fax for enrolled partners whose intake needs a fax event (Recipients → Partners → Send a notice fax with each document, faxbot recipients partners notice-fax <partner> on; off by default). The original goes by the encrypted direct route after a signed link, and the partner holds it out of Received. Then one page goes by telephone, never directly, filed under the same owner as the original fax. The page carries a random 20-digit code as a Code 128 barcode and as digits, with no part of the document and nothing that retrieves it. The SSL Fax engine also requests the code as the fax subaddress (SUB), which HylaFAX sends only when the far end takes one; the built-in engine cannot send SUB yet. The receiving Faxbot pairs the page by its subaddress, then by its barcode, or you pair it by hand under Recipients → Partners → Notice faxes (faxbot recipients partners notices|notice-faxes|pair). It files the original once and tells the sender, signed. The notice fax, the original and both signed statements are kept. Received shows "Notice for …: the document came by direct delivery" on the notice page and says the original came directly, never that it was faxed. A Faxbot that cannot pair notices gets the fax by fax. Migration 0046. Tested with two synthetic installations, fax pages at fine and standard resolution with line damage, on SQLite and PostgreSQL. A live notice fax over Telnyx, and whether the carrier keeps SUB, are not checked yet.
The built-in engine sends a subaddress (Asterisk patch 0005): a notice fax's notice ID, or the subaddress a routing rule sets for a department or mailbox behind one fax number (Delivery setup → Routing rules, faxbot delivery rules add|update --subaddress). Each call records the subaddress as asked for, and Their fax machine says whether it was carried: spandsp sends it only when the far end's fax machine says it takes one. Proven by replay (sent when the receiver takes subaddresses, withheld when it does not) and between two Asterisk containers over T.38 and over audio, where the receiving engine read it. Whether Telnyx carries the subaddress end to end has not been tried live.
Peer fax calls for enrolled partners whose intake is a fax server: a fax call straight between the two Faxbots' fax engines, never on the telephone network and with no carrier, only inside an encrypted WireGuard tunnel that you set up yourself in the fax engine's network (a WireGuard container sharing the Asterisk container's network). Recipients → Partners and faxbot recipients partners tunnel-calls|tunnel-check set the partner's address inside the tunnel and whether you take its calls; the partner is told with a signed statement. Each such partner gets its own endpoint in the fax engine (on its own port, 5070, with Internet Aware Fax), loaded on the trunk page's Apply. Before each call the fax engine itself checks that the route to the partner leaves through WireGuard and that the partner's Faxbot answers inside the tunnel; otherwise the fax goes by your carrier as before. The call record and the received fax name the partner. Proven between two Asterisk containers with a real WireGuard tunnel: two pages over T.38 with Internet Aware Fax, about 100 KB through the tunnel, and with the tunnel removed the same check refused the call. Not yet run between two real installations; only the built-in engine places these calls.
Resend only the missing pages to an enrolled partner after a broken call, with the document assembled whole on the receiving side. When a fax to an enrolled partner that takes fax images fails part way ("partly sent"), Faxbot asks the partner, signed, which pages of that call it holds intact. It names the call by its time, the calling number and the page count. On a call without error correction, a page the engine marked with damaged lines counts as missing, and so does every page after it. Only the remaining pages then go directly as a fax image, and the partner files one received fax made of the call's pages and those pages, once. Nothing goes again when the partner holds every page. When the partner cannot confirm, the fax waits for you, as before. Once the partner holds the whole fax, the sent fax shows delivered, completed directly by the partner, with the repair as its own attempt: the broken call's attempt stays exactly as it was, a late result for it changes nothing, and the pages that went directly count as a direct delivery, never as a call. The repair is also shown beside it (Sent details, Recipients → Partners → Broken calls completed directly, faxbot recipients partners repairs, and the delivery history in faxbot faxes sent history). Tested with two synthetic installations; not yet run on a live broken call.
Resend only the missing pieces of a document to an enrolled partner after a broken transfer, with the document assembled and committed once on the receiving side. A document over 4 MiB goes in 1 MiB pieces after a signed preflight, in which the receiver can refuse early with its reason (sender, recipient, type, size, page count, freshness, room on disk) before any document byte is sent. Each piece is kept once, and only when its SHA-256 is the signed one. After a dropped connection, the receiver lists the missing pieces by sequence and SHA-256 and only those go again. The commit checks every hash and records the document once, with the same signed receipt as a single delivery. Unfinished transfers are resumed when the partner answers again, and stopped and fenced after 23 hours. Recipients → Partners → Documents sent in pieces, faxbot recipients partners transfers. Tested with two synthetic installations.
Partners on your own network with their own certificate: once partner discovery (migration 0045, merging separately) has pinned a partner's certificate, Faxbot accepts exactly that certificate for its address and verifies every other address normally, never without verification. A changed certificate is refused before anything is sent, and the partner shows "Its certificate is not the one it had when you enrolled it". Tested against a local TLS server.
Send once to an enrolled partner whose intake files faxes for several of its numbers, only where that partner agrees. The receiving organization offers it, signed, naming the exact numbers its intake files for; the sender's administrator accepts it, because faxes to those numbers then stop going by telephone; either side ends it at once (Recipients → Partners → Send once, faxbot recipients partners send-once list|offer|accept|end). Similar numbers or a shared name never count. Each fax to a covered number still goes as its own direct delivery with its own signed receipt and Sent row. When the first of several faxes from one sender, with the same document to different covered numbers, goes out, the others of that send already waiting (accepted within ten minutes of it) are named with it: it carries the document and a signed list of those recipients, they send only a reference to that copy, and each one's Sent row says "Sent once to {partner}'s intake, which delivers to {n} recipients." A fax of the same document accepted after the first one went is not on that list; it still goes as a reference to the copy the partner holds, and says "Sent to {partner}'s intake, which files it for this number." Faxbot never holds a fax back to wait for others, and never groups two faxes to the same number. The intake files each recipient's copy, by its own receiving rules, only when that recipient's own delivery arrives, so a fax that went by telephone instead is never filed twice. Each copy is its own received fax and Work item, and a number no rule places waits in Received with the reason. Its receipt lists where each recipient is filed. Migration 0049. Tested with two synthetic installations; no real partner intake has used it.
Send an enrolled partner only the bytes it lacks, for original documents and fax images. Before an original goes to a partner that accepted the exact same document (SHA-256) from you before, Faxbot asks, signed, whether it still holds it, and then sends only a reference that the partner files from its kept copy. For a newer version of a case document (same case, source and purpose in the case ledger), it sends only the changes from the version the partner holds, as a binary delta. The partner files the result only when its SHA-256 matches the signed manifest. A partner answers only about documents that partner delivered to it. On any miss the whole document goes at once. These save bytes, never money, because the call was already avoided: Savings & optimization → Savings results → Bytes saved by reuse and patches and faxbot savings results show them apart from money. A fax image differs on every send only in the header line Faxbot prints above each page (the date, time and page number), so Faxbot writes each page's body apart from that header band and names the body by its digest; the partner's signed receipt for a fax image says which body it now holds. When a partner signed for the same body to the same number and says, signed, that it still holds it, only the new header lines and the image's structure go, and the partner puts its kept body back and files the image only when its SHA-256 matches the signed manifest. A missing copy, an image that does not match, an answer more than 10 minutes old or another recipient sends the whole image at once, and Sent says "only the new header lines went" when they were all that went. Keeping each page's body apart makes every fax image about 3% larger on a dense page and up to 11% on a light one. Tested with two synthetic installations on SQLite and PostgreSQL; not yet run between two live installations.
Reuse templates and unchanged pages between enrolled partners by content fingerprint (whole documents, changes between versions and a fax image's whole unchanged body are built; single pages and templates are not).
Save call time with a fax image body the recipient already holds, on a phone route that must be used: the opt-in encoded pages would carry a signed reference to those pages and only the new header lines. Not built, because the encoded pages' payload carries only a PDF or text and does not say which partner sent it.
Encoded pages (experimental): a whole document can travel as a few fax pages and be recovered byte for byte. It is off by default and requires the recipient's agreement (a number's Details in Recipients, Encoded pages, faxbot recipients encoded). With comparable prices, the route predictor selects encoded pages only for a lower estimated bill. On a plan or an unpriced route, it can select fewer pages while rejecting a known increase in transmission time; that is not a claim of monetary savings. The same chooser compares ordinary, packed and encoded pages for each attempt. On Faxbot's own engines, it now measures every encoded candidate in the usable fax codings before rejecting or ranking it; an MMR-only estimate can no longer hide a candidate that costs less in MH. Each engine is then asked for that coding: on a loopback call (10 October 2026) the SSL Fax engine sent a payload page in JBIG, as measured, and the built-in engine, which has no JBIG, in MR, the smallest of the others, where it had previously taken MMR by itself. Where a provider draws the pages, every coding is still measured on them and the estimate uses the measured size of the coding the call is expected to use, not a fixed ratio to MMR, which overpriced payload pages. The chooser that decides between ordinary, packed and encoded pages for a provider now measures each candidate the same way when encoded pages are among them. When the fax goes to one of your own trunk numbers, a fax service's call is priced at the speed earlier faxes into that number reached (from the sending account's own number when you set one), and the trunk's bill for receiving the call, from its saved or published receiving price, is added to each candidate, because you pay both ends; the encoded pages' explanation says what the receiving call adds, or, for any other number or a partner (who publishes no receiving price), that what the receiving end pays is unknown. A fax service's estimate for any other number now says that the receiving machine's speed is unknown. The live pilot of 10 October 2026 found the gap: HumbleFax sent 7 encoded pages to the installation's own Telnyx number, predicted at 586 seconds, and the call took 1,352 seconds at 9,600 bit/s, which the receiving trunk billed as 23 minutes ($0.0736). Replayed through the real predictor at that call's own size (worked out from its transfer time, since HumbleFax drew the pages) and the speed learned from it, the prediction comes within 1.2% of the call; this checks the arithmetic and the speed lookup, not how well Faxbot's measurement of its own pages matches pages a provider draws. Tested with synthetic choices and the real receiving records on SQLite and PostgreSQL; not yet run on a new live call. Encoded pages are never packed, trimmed or lightened, and the original files remain unchanged.
Grid pages tolerate resolution changes; run-coded pages need an exact raster; picture pages carry the document in their dot pattern. These three layouts also work with the static decoder in tools/fax-decoder. A fourth layout, enumerative profile 1, maps payload bits into bounded-cost MH patterns. It is available explicitly through faxbot admin codec encode original.pdf --layout enumerative --output payload.tiff; use faxbot admin codec decode received.pdf --output original.pdf with a Faxbot version that supports this profile. It is not selected automatically and the static browser decoder does not support it. Its page carries the profile and recovery parameters. Unknown profiles, invalid bounds and contradictory payload rows are refused. A fifth layout, capacity (payload format 2), draws the payload as runs at the capacity of the complete T.4 code with an arithmetic coder over frozen frequency tables, in three profiles: time for the shortest call, pages for the fewest pages, and balanced. Measured on full fine pages of random payload, in MH at 14,400 bit/s: time carries a kilobyte in 0.663 seconds, 4% less than the best run-coded limit for time (63: 0.689) and 7% less than the default (15: 0.716); pages carries 357 kB a page, 14% more than the best run-coded limit for pages (7: 313 kB) and 55% more than the default (231 kB); in JBIG every profile is faster still. These are well below the research bound (17–19% and two fifths), which compared ideal sources with the default limit only and left out each line's offset, CRC and padding and each page's caption and ladder. Faxbot chooses it by itself only for a recipient whose decoder you recorded as reading it (a number's Details in Recipients, Encoded pages, Recipient's decoder, faxbot recipients encoded set NUMBER --decoder capacity, database revision 0071): the chooser then also prices the time and pages profiles and the route's bill decides; every other recipient keeps the format 1 layouts. faxbot admin codec encode --layout capacity --capacity-profile time|balanced|pages makes the pages explicitly. A Faxbot decoder from October 2026 or later and the browser decoder in tools/fax-decoder read them; a page of a newer format, layout or profile is refused in one sentence. A partner Faxbot now says in its signed capabilities which layouts its decoder reads (grid, run-coded, picture, enumerative profile 1 and each capacity profile), and the chooser sends a partner only those; a partner that has not said gets the format 1 layouts every version reads, plus capacity pages when you recorded that its decoder reads them. Releases before October 2026 refuse a statement that carries a key they do not know, so Faxbot sends the key only to a partner whose own statement carried it, and learns a partner's from the partner's signed answer to its own statement (database revision 0082; Recipients → Partners, faxbot recipients partners list PARTNER). Proven between two synthetic installations through the real signing on SQLite and PostgreSQL, and against a fake partner with the earlier strict parser; not yet run against a real partner. Decoding reads what real receivers publish: a public test line's PDF receipt (one CCITT image per page, one white row short), page pictures without a resolution, CCITT Group 3 one- and two-dimensional and Group 4, Flate and image-mask PDFs, pages stored in strips, pages turned upside down or inverted, a header line drawn over the top or added above, square pixels, and run-coded rows moved sideways or padded to letter width. A page drawn again at another size, which run-coded and enumerative pages cannot survive, or a small preview instead of the fax, is refused in one sentence that says what to decode instead. Proven with synthetic fixtures of each container and change for every layout; no encoded page has yet been decoded from a real third-party receipt.
All layouts retain the original SHA-256 check and Reed–Solomon correction; an agreed shared key encrypts the document with AES-256-GCM. A receiving Faxbot keeps the received image and either recovers the original or reports why it could not. After you add, change or clear a stored shared key, opening Received details or downloading the decoded original retries a failed recovery; an unchanged key does not repeatedly retry the same failed document. Verified originals stay local even when received fax images use object storage, and follow the received fax’s retention deadline. Expiration removes both copies and preserves the decode history, with the download unavailable. If checking an encoded original fails unexpectedly during email delivery, the email says so and still includes the fax as received. Sent and Received details, faxbot faxes sent show, faxbot faxes received show, and Savings & optimization → Savings results retain the attempt and decode evidence. Decoder compatibility, recipient agreement and the applicable document-handling requirements must be established before use; the feature does not establish compliance or freedom to operate.
On 9 October 2026, an explicitly encoded one-page enumerative fax sent through Telnyx to HumbleFax recovered the exact 55,422-byte synthetic 30-page PDF from the provider's received PDF, with no damaged payload rows. The call used JBIG with error correction at 9,600 bit/s and lasted 69 connected seconds (59 seconds of fax transfer). The existing run-coded representation of the identical document also recovered exactly: 72 connected seconds, 63 seconds of fax transfer, and 420,576 measured JBIG bits versus 397,944 for the enumerative page (5.38% fewer). Telnyx reported $0.01 for each call, so this pair showed no monetary saving. This is one measured carrier path and one comparison pair, not a universal interoperability or timing claim. Synthetic checks cover the supported raster resolutions, MH/MMR recoding, encrypted multipage recovery, damaged and duplicate rows, bounded malformed headers, and compatibility with earlier layouts. In an equal-envelope local comparison, the new mapping used 6.78% fewer canonical MH bits than the existing run mapping; the actual live call used JBIG. Call duration, billed units and money are measured separately. Separate LAN calls between ARM64 and x86-64 Asterisk 22.11.0 fax engines also recovered the same original in both directions using T.38 at 14,400 bit/s, with identical received rasters. Two further calls passed the complete Faxbot workflow in fresh installations on those hosts: API submission, durable outbound success, SIP/T.38 transmission, inbound acquisition, automatic decoding, and downloading the exact original through the receiving API. Both calls carried one page and recorded 52 connected seconds, with unchanged queued and received rasters and no codec repairs. These were isolated synthetic installations; existing provider accounts and services remained unchanged.
Prove T.38 Internet Aware Fax interoperability on compatible endpoints before offering it as a transport.
Evaluate SIP routing preferences against real account costs and delivery reliability. Savings & optimization → Opportunities → Fax marker compares calls marked as fax with calls not marked, from history, and says so until each side has 10 calls.
After this release ships, remove what it deprecates: MCP over SSE, the FreeSWITCH code, provider plugins (FEATURE_V3_PLUGINS and /plugins), the settings recovery copy and the SDKs' client.plugins (see the release notes).
FreeSWITCH as a second fax engine, rebuilt from scratch. The FreeSWITCH support in this release could not run in the shipped Docker image, so Setup and the console no longer offer it; its code stays for one release.