Skip to main content

API 1.0.2

Released September 13, 2026

This release adds a first-party integration with Taxi. Enterprise organizations that connect Taxi under Settings → Taxi get client uploads and signed documents pushed into the matching Taxi customer automatically, without granting anyone read access to Zapa.

There are no breaking changes. Existing integrations, webhooks, and Zapier Zaps are unaffected.

Highlights​

Taxi file push​

For organizations with the Taxi integration connected, setting a portal's externalSystemIds.taxi to a 6-digit Taxi customer id links the portal. Zapa verifies the id against Taxi, then delivers:

  • every uploaded file (file.uploaded) and every fully signed PDF (file.signed) — the bytes are uploaded by Zapa to a short-lived upload URL issued by Taxi, with a SHA-256 checksum that Taxi's storage enforces;
  • task.created, task.completed, and portal.workflow_changed as metadata;
  • a portal.unlinked notice when the id is cleared.

Delivery is at-least-once, idempotent on (file_id, event) so Taxi can deduplicate: transient failures retry with exponential backoff for 24 hours, after which the file is marked failed in the portal with a Resend action. Every push is written to the portal's audit history and triggers guest download notifications, like a member download.

Linking through the REST API works the same as in the web app:

curl -X PATCH https://api.zapaportal.com/api/v1/portals/PORTAL_ID \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "externalSystemIds": { "taxi": "000123" } }'

The id must match ^[0-9]{6}$; anything else is rejected with 400. A taxi id already assigned to another portal in the organization returns 409 Conflict, as for any external system id.

Saving the id — from this endpoint or the web app — triggers link verification with Taxi. If the link is later found stale (for example the organization connected its Taxi credential after linking portals), Zapa re-verifies automatically the next time it matters: when a file event arrives for the portal, or when the portal page is opened.

External system names are case-insensitive​

externalSystemIds keys are now matched ignoring case across the API: taxi, Taxi and TAXI name the same system. Consequences:

  • PATCH with { "taxi": "…" } replaces an existing Taxi entry rather than adding a second key, and { "taxi": null } removes it. The spelling from the request is kept.
  • A request whose body contains two keys that differ only by case returns 400.
  • GET /api/v1/portals?externalSystem=Taxi&externalId=… matches portals stored under taxi, and the 409 Conflict uniqueness check compares names case-insensitively.
  • Organizations cannot register two external system labels that differ only by case.

GET /api/v1/portals and GET /api/v1/portals/{portalId} now include a read-only taxi_link object when the portal has (or had) a taxi external system id:

"taxi_link": {
"status": "linked",
"tenant_id": "firm-abc",
"customer_id": "000123",
"display_name": "Acme Holdings LLC",
"verified_at": "2026-09-13T20:41:07.000Z"
}

status is one of verifying, linked, not_found, credential_rejected, error, or unlinked; when it is not linked, error carries the reason. The field cannot be set through the API — PATCH requests that include it are ignored for that key. Poll it after setting the id if you need to confirm the link before relying on pushes.

Web app​

  • Settings → Taxi (administrators): connect, replace, or disable the Taxi credential. The pair is verified against Taxi before it is stored; only the last four characters of the key are shown afterwards.
  • Portal → Settings → External System IDs: the taxi field validates the 6-digit format, shows the verified customer name, verifies automatically on save and on page load when the link is stale, and offers Re-verify.
  • File list: members with Manage Permissions see Sent to Taxi / Sending to Taxi / Taxi failed on each file of a linked portal, with Resend on failures.

See the Taxi Integration admin guide for setup and troubleshooting.

Notes for integrators​

  • Webhook receivers already get external_system_ids on every payload (since 1.0.1), so a Taxi-linked portal's events carry "external_system_ids": { "taxi": "000123" }. Nothing about webhook payloads or signatures changed in this release.
  • The Taxi push runs alongside your webhooks, not instead of them; both fire for the same event.
  • The Zapier integration is unchanged (still 1.0.1).

Resources​