Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.dualentry.com/llms.txt

Use this file to discover all available pages before exploring further.

Zapier Integration: Setup, Authentication, and Actions

DualEntry ships a Zapier Platform application that calls the Public API v2 using an organization API key. Once installed, Zaps - Zapier’s automation workflows - create, update, poll, and search records across DualEntry and thousands of other apps. The connector is a Node.js package under core/integrations/connectors/zapier/; every action, trigger, and search is generated from a single lib/schemas.js manifest, so changes to that manifest re-shape the published Zapier surface.

Prerequisites

Confirm the following before building Zaps:
  • A Zapier account and permission to install or use the DualEntry integration. Distribution is private invite or a Zapier App Directory listing, depending on how your organization releases the app.
  • A DualEntry organization-scoped Public API key with the authentication scopes your Zaps need. Create the key under Organization Management → your organization → API Keys.
  • Agreement on which environment Zaps should call. The integration defaults BASE_URL to https://api.dualentry.com when unset; private deployments override BASE_URL on the Zapier app configuration.
  • For polling triggers, tolerance for latency. Triggers send GET calls on Zapier’s schedule rather than pushing real-time webhooks from DualEntry. See Rate limiting for the limits Zapier polling has to respect.

Install the DualEntry app and authenticate

The DualEntry Zapier app uses custom authentication: every request adds the X-Api-Key header with your Public API key, and Zapier validates the key against the API health endpoint before completing the connection.
  1. Install the DualEntry Zapier app the way your organization provides it - directory install or invite link from whoever maintains the Zapier project.
  2. When Zapier prompts for authentication, paste your Public API key.
  3. Zapier runs the connection test against GET {BASE_URL}/public/v2/health/. A 200 response completes the connection.
If the test fails, confirm the key is valid in DualEntry, the base URL matches your environment, and outbound HTTPS from Zapier to your DualEntry host is allowed. The auth handler lives in lib/auth.js; the X-Api-Key injection happens in the connector’s beforeRequest hook in index.js.

How Zaps call DualEntry

Each Zapier action, trigger, and search corresponds to a specific call pattern on DualEntry’s Public API. Knowing the pattern up front makes errors much easier to diagnose later.
MechanismBehavior
API prefixAll calls target {BASE_URL}/public/v2/ (DUALENTRY_VERSION is v2 in lib/constants.js).
CreatesPOST to /public/v2/<slug>/ (for example invoices, bills) with a JSON body built from the Zap’s input fields.
UpdatesGET the existing record, strip read-only fields (amounts, approval metadata, resolved names), merge Zap input overrides, then PUT the full payload. The merge is implemented in lib/factories.js’s stripReadOnlyFields.
Triggers (polling)Repeated GET list calls; Zapier deduplicates using the platform’s normal polling rules. See Pagination for how list endpoints page.
SearchesGET with a narrow query (the factory uses limit=1-style lookup to return a single match).
Errors401 triggers Zapier’s reauth flow; 403 is forbidden; 404 is not found; 422 surfaces the API’s validation detail when present. See Errors for the canonical model.
Draft creates for transactional records (such as invoices and bills) support a record_status field with dynamic fields. When the user selects Draft, several fields become optional - Zapier rebuilds the form so you aren’t forced to supply values the product doesn’t require for drafts. The list of optional fields is configured per resource in draftOptionalFields in schemas.js.

Use dynamic dropdowns for IDs

Six hidden dropdown triggers fetch up to 1,000 rows each (paginated) to power dynamic field references such as customerList.id.name. Use these in Zap steps instead of hard-coding numeric IDs whenever possible so Zaps survive data changes - when a customer is renamed in DualEntry, the dropdown reflects it on the next refresh, but a hard-coded ID becomes a stale reference the next time the Zap runs.
Trigger keyPublic API slugCompany-scoped
companyListcompaniesNo
customerListcustomersYes
vendorListvendorsNo
accountListaccountsYes
itemListitemsNo
classificationListclassificationsYes
Company-scoped dropdowns require the user to choose a company in the Zap step before the dropdown loads - they only show records that belong to the selected company.

Published actions

The connector currently publishes 39 actions across 19 resources. Each resource’s published object in lib/schemas.js toggles create, update, trigger, and search independently, so the published surface can change between releases.
Resource (examples)CreateUpdatePolling triggerSearch
Invoice, Bill, Customer, Vendor, Sales Order, Customer PaymentYesYesYesYes
Journal Entry, Direct ExpenseYes--Yes
Item, Purchase Order, Vendor Payment, Cash Sale, Customer Credit, Vendor Credit, Bank Transfer, Customer Deposit, Customer Refund, Vendor Refund, Classification- (or partial)--Yes (where indicated)
Capabilities that exist in schemas.js with published: false are not visible in Zapier and require flipping the flag and redeploying the app (npm run deploy-zapier in the connector package). For the canonical action matrix, see the connector’s README.md.

Operate safely in production

A few production hygiene rules cover most of the gotchas Zapier publishing rules and DualEntry’s API model enforce.
  1. Build and validate Zaps against a non-production DualEntry organization first. Map every required field, run end-to-end tests, then point at production.
  2. Avoid consecutive search steps, and never end a Zap with only a search - Zapier’s publishing rules reject those patterns.
  3. Map 422 errors back to missing required fields or invalid enums. The middleware formats the API’s detail arrays into a single message when possible.
  4. For updates, remember the GET-merge-PUT pattern - omitted fields keep their existing API values, and supplied fields override after the merge. Supply complete arrays when changing line items, since PUT replaces the array wholesale rather than patching individual lines.

Troubleshoot common failures

SymptomCauseResolution
Connection test failsWrong API key, wrong BASE_URL, or the health route is blocked.Regenerate the Public API key; set BASE_URL for private stacks; verify GET /public/v2/health/ returns 200 from a browser or curl with the same key.
401 / “Invalid API key”Key revoked or typo.Create a new key under Organization Management and update the Zapier connection.
403 on an actionThe key lacks permission for that record type or company.Use a key whose scopes match the Zap’s operations, or adjust DualEntry role permissions.
422 validation errorsRequired fields missing, bad enums, or draft vs. posted rules.Use draft mode where applicable; populate dynamic dropdowns; read the error text for loc and msg fragments from the API response.
Update overwrote line itemsPUT replaced arrays after the merge.Supply complete line arrays when changing lines, or use create-only Zaps for additive workflows.
Dropdown emptyNo rows in DualEntry, or the company filter excludes them.Create master data first; pick the correct company for company-scoped lists (customerList, accountList, classificationList).

FAQ

The FAQ covers questions that come up most often during Zap design and connector maintenance. Maintainer-specific answers note the relevant package files.

Does the Zapier app use OAuth or the same session as the DualEntry UI?

No. It uses a static API key on every call (X-Api-Key). OAuth for end users is a separate Public API surface (/public/v2/oauth/... in the Django app) and is not what this Zapier package implements.

Where is the source of truth for field labels and required flags?

lib/schemas.js in the Zapier connector package. Operators rarely edit it; engineering or solutions engineering changes it and runs npm test and npm run validate (or npm run verify-zapier before merge).

How do we add a new record type to Zapier?

Following the maintainer workflow: extend scripts/zapier-config.json, run node scripts/generate-zapier-schemas.js, merge the generated block into lib/schemas.js, hand-tune fields and published flags, then test and zapier push per README.md.

Result

After connecting with a valid Public API key, Zaps call /public/v2/ endpoints to create, update, poll, and search the published DualEntry resources, with dropdown-backed IDs and structured validation errors. To compare other integrations, return to Integrations. For Zapier platform concepts, see the Zapier Platform documentation. For connector maintenance detail, read the package README.md in core/integrations/connectors/zapier/.
Last modified on May 28, 2026