> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.pinnacle.sh/v-2/api-reference/fax-hipaa-only/send/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.pinnacle.sh/_mcp/server. # Send Fax POST https://api.pinnacle.sh/fax Content-Type: application/json Send one PDF, TIFF, JPEG, PNG, DOC, DOCX, RTF, or TXT document from a configured fax number. **HIPAA only:** this endpoint exists only in Pinnacle's HIPAA cell. Complete HIPAA onboarding and use the connection details provided by Pinnacle. It is not available at `https://api.pinnacle.sh`. **Availability:** `from` must be an enabled fax number owned by your team. Fax sending is unavailable for development-mode teams and sandbox numbers. Each request accepts exactly one document; cover pages and per-request webhook URLs are not supported. **Source URL:** `mediaUrl` must be a publicly reachable HTTPS URL on port 443. Signed query parameters are supported. URLs with credentials, redirects, private or local network addresses, and non-200 responses are rejected. Downloads must complete within 30 seconds. **Document limits:** the document must contain 1–3,500 pages and be no larger than 50 MB. Documents over 350 pages are split automatically and remain one fax in the API. File extensions and response headers do not override file validation. **Document safety:** encrypted files, macros, ActiveX controls, embedded objects, symbolic links, unsafe archive paths, and malformed documents are rejected. **Quality:** `HIGH` is the default and recommended choice for most documents. Use `NORMAL` when speed matters more than detail, `VERY_HIGH` for small text and fine lines, `ULTRA_LIGHT` for image-heavy documents, or `ULTRA_DARK` for text-heavy documents. **Asynchronous processing:** the request returns 202 after preparation is queued. Downloading, validation, conversion, splitting, and archival happen afterward. A 202 response does not mean the document is valid or delivered. Watch `FAX.STATUS` webhooks or retrieve the fax for the final result. The initial status is `PREPARING`, `reservedCost` is zero, and `hasMedia` is false. **Multipart delivery:** the original `id` identifies the complete fax across list, detail, cancellation, billing, media, and webhooks. Parts are sent in order. If a part fails, later parts are not sent. The fax becomes `FAILED`, and `partialContent` is true if any earlier pages were transmitted. **Pricing:** sent and received faxes cost $0.025 per transmitted page. Quality does not change the rate. Pinnacle reserves the estimated cost after preparation, charges only for transmitted pages, and returns unused reserved credits. If your balance is too low, the fax becomes `FAILED` with `failureReason: INSUFFICIENT_CREDITS`. **Delivery uncertainty:** Pinnacle does not automatically retry a fax after transmission may have started, which prevents duplicate delivery and charges. If transmission cannot be confirmed, status becomes `SUBMISSION_UNKNOWN` while Pinnacle reconciles the fax. **Idempotency:** `Idempotency-Key` is optional. Without it, each request creates a new fax, including retries. For retry-safe sending, generate a UUID for each intended fax and retain it until the outcome is known. After a client timeout, retry with the same key and identical body. The key is scoped to your team and covers `from`, `to`, `mediaUrl`, and `quality`. Reusing it with an identical body returns the existing fax; changing any of those fields returns 409. Reference: https://docs.pinnacle.sh/api-reference/fax-hipaa-only/send ## Authentication - `PINNACLE-API-KEY` header (required) — API Key authentication via header ## Request ### Headers - `Idempotency-Key` (string, optional) — Optional unique key for one logical send. Without it, every request creates a new fax. Use 1–128 ASCII letters, numbers, periods, underscores, or hyphens. Reuse it only with the identical `from`, `to`, `mediaUrl`, and effective `quality`; any change returns 409. ### Body (application/json) This endpoint expects a SendFaxRequest. - `from` (string, required) — Fax-enabled, non-sandbox number owned by your HIPAA team, in E.164 format (`+` followed by 10–15 digits; the first digit cannot be zero). The number must remain enabled and configured through preparation. Fax sending is unavailable to development-mode teams. - `to` (string, required) — Recipient fax number in E.164 format (`+` followed by 10–15 digits; the first digit cannot be zero). - `mediaUrl` (string, required) — Public HTTPS URL on port 443 for one PDF, TIFF, JPEG, PNG, DOC, DOCX, RTF, or TXT document. The URL must contain 9–8,192 characters, including signed query parameters. Usernames, passwords, redirects, private or local addresses, IPv6-only hosts, and non-200 responses are rejected. The origin must complete the download within 30 seconds and return no more than 16 KiB of response headers. If present, `Content-Length` must be a non-negative decimal integer no greater than 50,000,000, and `Content-Type` must be one of the accepted types listed in the endpoint description. The source and processed document must each be no larger than 50,000,000 bytes. The document must contain 1–3,500 pages. A permitted URL extension or `Content-Type` is not sufficient: file signatures and structure must identify a supported format. JPEG/PNG images are limited to 250,000,000 pixels and TIFF images to 2,000,000,000 pixels. DOCX archives must be non-encrypted and free of macros, ActiveX controls, embedded objects, symbolic links, and unsafe paths; ZIP64 and multi-disk containers are not accepted. See the endpoint description for the complete DOCX archive and document-processing limits. - `quality` (enum, optional) — Rendering profile applied to the fax. Defaults to `HIGH`. Higher-detail profiles can take longer to process but do not change the $0.025 per-page price or any document limit. - Allowed values: `NORMAL`, `HIGH`, `VERY_HIGH`, `ULTRA_LIGHT`, `ULTRA_DARK` ## Response ### 202 Fax preparation durably queued for asynchronous processing. - `id` (string, required) - `direction` (enum, required) — `OUTBOUND` for faxes sent by your team or `INBOUND` for faxes received by your team. - Allowed values: `INBOUND`, `OUTBOUND` - `from` (string, required) — Sender number in E.164 format. - `to` (string, required) — Recipient number in E.164 format. - `status` (enum, required) — Current state of the fax: - `PREPARING`: Pinnacle is downloading, validating, converting, splitting, or archiving the document. - `SUBMITTING`: The fax is waiting for transmission to start. - `SUBMISSION_UNKNOWN`: Transmission may have started, but Pinnacle cannot confirm it. The fax is not retried automatically. - `QUEUED`: The outbound fax is queued for transmission. - `PROCESSING`: The outbound document is being processed. - `SENDING`: The outbound fax is being transmitted. - `RECEIVING`: An inbound fax is in progress. - `DELIVERED`: Every outbound part was delivered. - `RECEIVED`: The inbound fax was received and archived. - `FAILED`: Preparation, submission, or delivery failed. `partialContent` indicates whether any pages were transmitted. - `CANCELLED`: The outbound fax was cancelled before transmission started. - Allowed values: `PREPARING`, `SUBMITTING`, `SUBMISSION_UNKNOWN`, `QUEUED`, `PROCESSING`, `SENDING`, `RECEIVING`, `DELIVERED`, `RECEIVED`, `FAILED`, `CANCELLED` - `pages` (integer, required) — Transmitted page count across the fax. This can be zero before transmission and can include only transmitted pages after a partial failure. Outbound documents can contain at most 3,500 pages. - `durationSeconds` (double, required) — Total transmission duration in seconds. - `partialContent` (boolean, required) — Whether only part of the document was delivered, including when an earlier part succeeded before a later part failed. - `failureReason` (enum, required) — Stable failure category, or null when no failure is recorded: - `MEDIA_PREPARATION_FAILED`: The source was unavailable, invalid, unsupported, over a limit, or could not be rendered. - `MEDIA_PREPARATION_INTERRUPTED`: Preparation could not be completed after retries. - `INSUFFICIENT_CREDITS`: The team's available credits could not cover the prepared page count. - `SUBMISSION_UNCONFIRMED`: Transmission may have started, so Pinnacle will not retry automatically. - `SUBMISSION_REJECTED`: Transmission could not start. - `DELIVERY_FAILED`: Delivery failed or a transmitted part did not match the expected page count. - Allowed values: `MEDIA_PREPARATION_FAILED`, `MEDIA_PREPARATION_INTERRUPTED`, `INSUFFICIENT_CREDITS`, `SUBMISSION_UNCONFIRMED`, `SUBMISSION_REJECTED`, `DELIVERY_FAILED` - `cost` (double, required) — Settled fax cost in USD, calculated at $0.025 per final transmitted page. Quality does not change the rate. - `reservedCost` (double, required) — Credit reserved after document preparation for an unsettled outbound fax, in USD. This equals $0.025 multiplied by the prepared page count, regardless of quality, and is zero while status is `PREPARING`. - `billingStatus` (enum, required) — `PENDING` while a reservation or uncertain submission remains open; `SETTLED` after final charging, refund, or cancellation. - Allowed values: `PENDING`, `SETTLED` - `hasMedia` (boolean, required) — Whether Pinnacle has archived the fax document. - `createdAt` (string, required) - `updatedAt` (string, required) ## Errors ### 400 Bad Request Error The request was unacceptable, often due to providing an invalid update. Errors may originate from invalid payload or from Pinnacle's additional validation checks. For example, providing an URL that cannot be accessed, updating a campaign that is currently being reviewed, updating data that you cannot access, sending a malformed message, and so on. For `Pinnacle Validation Error` inspect the `error` payload to determine the source of the failure. These errors are likely due to additional validation and business logic checks. For `Request Validation Error` inspect the `description` and `errors` payload to determine the source of failure. These errors are likely due to invalid payload inside the request. - `SendFaxRequestBadRequestError` ### 401 Unauthorized Error The request lacks valid authentication credentials or the provided credentials are invalid. Ensure you're including a valid API key in the request headers and that your account has the necessary permissions to access this endpoint. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ### 403 Forbidden Error Your subscription does not include access to this feature. This occurs when attempting to use functionality that requires a higher subscription tier. Please upgrade your subscription to access this feature. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ### 404 Not Found Error The requested resource could not be found. This may occur if the identifier is incorrect, the resource has been deleted, or you don't have permission to access it. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ### 409 Conflict Error The request conflicts with an existing resource. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ### 500 Internal Server Error An unexpected error occurred on Pinnacle's servers while processing your request. If this error persists, please contact support with the request details. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ### 503 Service Unavailable Error Fax support is disabled or temporarily unavailable in this deployment. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ## Types ### ZodError - `description` (string, required) — Human-readable summary of validation failures. - `errors` (ZodErrorErrors, required) — Structured dictionary of issues containing two main sections: - `errors`: Array of global validation errors not tied to specific fields - `properties`: Object mapping field names to their specific validation errors, where each field contains an `errors` array ### Error Standard error response returned when a request cannot be processed successfully. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ### ZodErrorErrors Structured dictionary of issues containing two main sections: - `errors`: Array of global validation errors not tied to specific fields - `properties`: Object mapping field names to their specific validation errors, where each field contains an `errors` array ## Examples **Request** ```json { "from": "string", "to": "string", "mediaUrl": "string" } ``` **Response** ```json { "id": "string", "direction": "INBOUND", "from": "string", "to": "string", "status": "PREPARING", "pages": 1, "durationSeconds": 1.1, "partialContent": true, "failureReason": "MEDIA_PREPARATION_FAILED", "cost": 1.1, "reservedCost": 1.1, "billingStatus": "PENDING", "hasMedia": true, "createdAt": "2024-01-15T09:30:00Z", "updatedAt": "2024-01-15T09:30:00Z" } ``` **SDK Code** ```python import requests url = "https://api.pinnacle.sh/fax" payload = { "from": "string", "to": "string", "mediaUrl": "string" } headers = { "PINNACLE-API-KEY": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.pinnacle.sh/fax'; const options = { method: 'POST', headers: {'PINNACLE-API-KEY': '', 'Content-Type': 'application/json'}, body: '{"from":"string","to":"string","mediaUrl":"string"}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.pinnacle.sh/fax" payload := strings.NewReader("{\n \"from\": \"string\",\n \"to\": \"string\",\n \"mediaUrl\": \"string\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("PINNACLE-API-KEY", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.pinnacle.sh/fax") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["PINNACLE-API-KEY"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"from\": \"string\",\n \"to\": \"string\",\n \"mediaUrl\": \"string\"\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.pinnacle.sh/fax") .header("PINNACLE-API-KEY", "") .header("Content-Type", "application/json") .body("{\n \"from\": \"string\",\n \"to\": \"string\",\n \"mediaUrl\": \"string\"\n}") .asString(); ``` ```php request('POST', 'https://api.pinnacle.sh/fax', [ 'body' => '{ "from": "string", "to": "string", "mediaUrl": "string" }', 'headers' => [ 'Content-Type' => 'application/json', 'PINNACLE-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.pinnacle.sh/fax"); var request = new RestRequest(Method.POST); request.AddHeader("PINNACLE-API-KEY", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"from\": \"string\",\n \"to\": \"string\",\n \"mediaUrl\": \"string\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "PINNACLE-API-KEY": "", "Content-Type": "application/json" ] let parameters = [ "from": "string", "to": "string", "mediaUrl": "string" ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.pinnacle.sh/fax")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` > One API for RCS, iMessage, MMS, and SMS. Build, test, and scale every channel — send your first message in minutes, not weeks.