Skip to main content

Outcome

When you finish this guide, your integration sends to https://api.mintfax.com/v1 with a Bearer key, reads snake_case fields, signs an Idempotency-Key on every send, verifies Standard Webhooks signatures on every webhook, and has cleared a full fax round-trip in the sandbox. Code samples are curl and Node. Marketing positioning is at /compare/sinch-alternative; this page is the dev-execution path.

Prerequisites

  • A mintfax environment with a sandbox API key (mfx_test_...). Live keys (mfx_live_...) come later, after the sandbox round-trip.
  • A webhook endpoint configured in the mintfax dashboard. The signing secret is shown once; store it as MINTFAX_WEBHOOK_SECRET.
  • Your existing Sinch v3 (or Phaxio v2.1) integration in source control. The cutover diff is small, but you want a clean revert.
  • Node 18+ for the Node samples, or any HTTP client that speaks multipart/form-data for the curl samples.
  • Read Verify webhook signatures, Idempotency, Errors, Event types, and Sandbox before cutover. The migration leans on each one.

Step 1: Swap the base URL and authentication

Sinch v3 uses HTTP Basic with a project-scoped key and secret, and the project ID lives in the URL path. mintfax uses a Bearer token, infers the environment from the key prefix (mfx_test_ for sandbox, mfx_live_ for live), and has no project ID in the URL.
Verify A GET https://api.mintfax.com/v1/account with your sandbox key returns 200 and your account ID. A 401 means the header is missing or malformed; see unauthenticated and api_key_invalid.

Step 2: Rename fields from camelCase to snake_case

Phaxio v2.1 used snake_case. Sinch v3 broke that convention. mintfax restores it. Most send-path fields map directly; a few drop or rename. The mintfax Fax resource also adds fields Sinch v3 does not have: csid, page_size (letter/legal/a4/b4), resolution (standard/fine), optimize_for (text/photo), and idempotency_key. All are optional and fall back to your environment fax settings. Verify Submit one fax, then GET /v1/faxes/{id}. Confirm every field your old code reads is present under its snake_case name.

Step 3: Add an idempotency key

Sinch v3 has no documented idempotency feature. A retried POST /faxes against Sinch can double-bill silently. mintfax accepts an Idempotency-Key header on POST /v1/faxes and POST /v1/faxes/{id}/resend; duplicate keys return the original response without re-processing, and keys expire after 24 hours. Generate a UUID v4 per submission. Reuse the same key on retry.
Verify Submit the same request twice with the same Idempotency-Key. Both responses carry the same id. Read the Idempotency guide for full semantics.

Step 4: Translate status and retry behavior

Sinch v3 status names are uppercase; mintfax statuses are lowercase, and add one extra value (submitted) to distinguish “in queue” from “handed to the carrier.” Retry caps differ. Sinch v3 caps at 5 retries (maxRetries 0-5); mintfax caps at 10 (retries 0-10), with a default of 3. Configure it per fax or as an environment default at PUT /v1/environment/fax-settings. Retry timing is controlled by mintfax, so there is no per-request retryDelaySeconds to map. If you previously cancelled queued faxes, note that neither product exposes a cancel endpoint. A queued fax in mintfax runs to a terminal state (delivered or failed) before it can be deleted via DELETE /v1/faxes/{id}. A delete attempt against an in-flight fax returns fax_not_terminal. Verify Submit a fax to +15005550004 (the transient-failure magic number) and watch the lifecycle: fax.queued, fax.sending (attempt 1), fax.sending (attempt 2 after the transient failure), then fax.delivered. fax.sending fires once per delivery attempt, so the repeat is how you observe mid-flight retries. See Sandbox.

Step 5: Replace the v3 webhook scheme with Standard Webhooks

This is the highest-value step in the migration. Sinch v3 dropped the Phaxio v2.1 X-Phaxio-Signature (HMAC-SHA1) header. The v2-to-v3 guide states verbatim: “Webhook signatures: Removed due to low usage, at the moment V3 does not support.” What replaced it is HTTP Basic credentials inside the callback URL. That mechanism leaks the credential to any reverse proxy in the path and to Sinch’s own request logs, and it does not authenticate the payload. mintfax follows the Standard Webhooks specification and sends three headers on every delivery: The signature is HMAC-SHA256(secret, "{webhook-id}.{webhook-timestamp}.{body}"), base64-encoded, emitted as v1,<base64>. Use the Standard Webhooks reference library for your language - it handles constant-time comparison, the 5-minute timestamp tolerance, and parsing multi-secret rotation tokens.
Verify Send a fax to +15005550001 (success) and confirm your handler returns 200. Tamper with one byte of the body in a replayed request and confirm 401. Read the full verify webhook signatures page for the multi-language reference and rotation guidance before you ship.

Step 6: Adjust webhook event handling

Sinch v3 fires one FAX_COMPLETED event whose fax.status is either COMPLETED or FAILURE. mintfax fires distinct event types, plus events Sinch does not have: fax.queued, fax.sending, fax.delivered, fax.failed, balance.low, and balance.topup. Two consequences for your handler. First, code that branched on fax.status inside one event now branches on event.type at the top of the payload; a switch over event.type is clearer. Second, if your Sinch v3 integration consumes INCOMING_FAX, mintfax has no equivalent today. Treat that as a known gap, and do not migrate inbound flows yet. The mintfax envelope is the same across all event types: id (evt_-prefixed, also delivered as the webhook-id header; use it for deduplication), type (the event name), created (Unix timestamp in seconds), and data.object (event-specific payload). The full catalog is at Event types. Verify Confirm your handler routes fax.delivered and fax.failed correctly. Replay protection plus id deduplication means you can replay any captured event safely while testing.

Step 7: Translate error codes

Sinch v3 returns an integer errorCode plus a type field on failure (one of DOCUMENT_CONVERSION_ERROR, CALL_ERROR, FAX_ERROR, FATAL_ERROR, GENERAL_ERROR), and uses HTTP statuses for top-level rejections. mintfax returns a stable string error field in a consistent envelope with message, action, and docs. The per-failure-reason error catalog for the fax record itself (the error_code field on fax.failed) is intentionally compact in v1; treat unfamiliar values as opaque-but-logged. Top-level API errors (the envelope above) are stable, documented at Errors, and machine-matchable on the error field. Verify Submit to +15005550005 (the permanent-failure magic number) and confirm your fax.failed handler logs data.error_code and routes to your alerting path.

Step 8: Adapt sandbox tests

Sinch v3 ships a single magic number for sandbox testing. mintfax ships per-failure-mode magic numbers so you can exercise each branch deterministically. Existing test fixtures built around Sinch’s single number expand here: one fixture per failure mode, deterministic, no carrier dependency. The full list and behavior are on Sandbox. Verify Run your full integration suite against the sandbox using these numbers before any traffic moves to live keys.

Verify

End-to-end check before you flip live traffic:
  1. Send a fax to +15005550001 with a sandbox key and an Idempotency-Key. The response carries status: "queued" and a fax_-prefixed id.
  2. Your webhook endpoint receives fax.queued, then fax.sending, then fax.delivered. Each request passes Standard Webhooks verification via the reference library.
  3. Repeat the same POST /v1/faxes with the same idempotency key. The response is identical; no second fax is created.
  4. Send to +15005550005 and confirm a fax.failed event with a populated error_code.
  5. Replace mfx_test_ with mfx_live_ in your config, send one real fax to a known-good destination, and watch the same event sequence land.

What to do next

  • Verify webhook signatures - Standard Webhooks library snippets in five languages, plus key rotation guidance.
  • Idempotency - retry semantics, key lifetime, and what happens on replay.
  • Errors - the stable error catalog with HTTP statuses, causes, and next actions.
  • Event types - every event type, payload shape, and delivery behavior.
  • Sandbox - magic numbers and simulated failure scenarios.
Last modified on July 14, 2026