HollyHR Developer Docs
  • HollyHR
  • Sign in
  • Manage API keys
  • Start Here
  • Core API
  • AI and MCP
  • API Reference
  • Integrations
  • Recipes
  • Resources
Recipe indexGitHub Actions recipesMCP smoke testSafe MCP leave bookingPeople syncExpense and spend toolsTest SDK from sourceSlack who's awayGoogle Sheets exportReceive webhooks in NodeCreate person + webhookWebhook + payroll referencesPayroll readiness export
Recipes

Expense and spend tools

Use this recipe when a finance or operations workflow needs clean people, employment, department, cost-centre, legal-entity, and leaver context from HollyHR while a specialist tool owns expenses, cards, receipt capture, reimbursements, VAT, and accounting reconciliation.

HollyHR is not a native expense-management product and this is not a first-party connector. It is the launch-safe integration pattern for teams using tools such as Xero Expenses, FreeAgent, Dext, Pleo, Soldo, Expensify, or Zoho Expense.

What HollyHR should own

DataHollyHR sourceUse in a spend tool
Person identityGET /people, GET /people/{personId}Create or match employee/user records.
Work emailpeople:readPrimary matching key when the spend tool also keys users by work email.
Employment statusstatus, start_date, end_dateDecide who can receive access or a card.
Job title and managerPeople detail and employment contextApproval-routing context where the spend tool supports it.
DepartmentsGET /org-units?type=department and People projectionsReporting and approval grouping.
Cost centresGET /org-units?type=cost_centreAccounting dimensions, budget ownership, and spend reporting.
Legal entitiesGET /org-units?type=legal_entityEntity-aware accounting setup; not payroll registration data.
Provider idsOrg-unit provider identity fields and GET /provider-mappingsReconcile HollyHR resources with downstream ids without overloading staff_id.

What the spend tool should own

  • expense claims, mileage, receipt capture, OCR, and evidence retention;
  • card issuance, spend limits, merchant rules, subscriptions, and transaction feeds;
  • reimbursement workflow and payment status;
  • VAT, MTD, ledger posting, account codes, and bank reconciliation;
  • expense-policy approval semantics and exception handling;
  • spend analytics and finance-close reporting.

Do not store card numbers, bank details, receipt images, reimbursable amounts, merchant data, or accounting-ledger payloads in HollyHR custom fields.

Recommended scopes

Create the smallest API key that fits the sync:

Code
people:read org_units:read provider_mappings:read webhooks:manage

Add people:write or org_units:write only if your integration creates safe setup data in HollyHR. Do not add people:personal:read, payroll_exports:read, payroll-financial grants, custom sensitive fields, or document scopes for a spend-tool user lifecycle sync.

provider_mappings:read also requires the matching resource read scope. For example, reading org-unit mappings requires provider_mappings:read and org_units:read.

Readiness check

Call GET /integration-readiness before building or activating a spend sync. The endpoint gives one aggregate answer for whether HollyHR is ready to act as the HR source of truth for tools such as Xero Expenses, FreeAgent, Dext, Pleo, and Soldo.

The response includes provider cards with native_connector: false, because v1 is a readiness/playbook/API handoff, not a first-party connector. Treat these statuses as operational setup guidance:

  • not_configured: fix blockers first, especially archived members without an employment end date;
  • needs_attention: the handoff can be useful, but cost-centres, departments, or webhook health need review;
  • ready: HollyHR has the people, org-structure, and webhook posture expected for that provider pattern.

For Pleo and Soldo-style card tools, person.ended webhook coverage matters: that is the event a downstream system needs to deactivate a leaver. Keep a scheduled reconciliation job as a backstop even when webhooks are healthy.

Initial sync

  1. Fetch people with GET /people?limit=100.
  2. Store HollyHR person_id as the stable source id.
  3. Store work email as the human-readable matching key.
  4. Fetch departments, cost centres, and legal entities with GET /org-units.
  5. Fetch GET /people/{personId}/org-links when the downstream tool supports multiple memberships or needs cost-centre/legal-entity context.
  6. Store downstream ids in the downstream tool, or use HollyHR provider-mapping reads where mappings already exist. Do not repurpose staff_id as a connector id.

Use cursor pagination and updated_since for repeat syncs.

Change handling

Subscribe to these events where the current event source covers your workflow:

Code
person.created person.updated person.ended person.reactivated org_unit.created org_unit.updated org_unit.archived org_unit.reactivated

Webhook deliveries are notifications, not the integration's database. Verify the signature, deduplicate by HollyHR-Webhook-Id, then fetch current state through REST before updating the spend tool.

Current source coverage is mixed:

  • public API writes emit the matching public webhook events for implemented people, employment, org-unit, time-off, working-pattern, and time-off configuration writes;
  • in-app mutations emit source: "app" events for person creation/person profile updates and time-off create/update/cancel flows wired through the domain-event spine;
  • some UI-origin paths, including access-removal/offboarding without a recorded employment end date, still need incremental updated_since polling or a follow-up product slice before they can be treated as real-time card-disable automation.

For Pleo or Soldo-style company-card tools, run a daily reconciliation job even if you also subscribe to webhooks. A leaver should lose spend access based on a recorded end date or inactive status, not solely on a single webhook delivery.

Provider patterns

Tool typeExamplesPractical HollyHR role
Accounting-native expensesXero Expenses, FreeAgentProvide employee, department, cost-centre, and legal-entity context; the accounting product owns claims and posting.
Receipt/accountant captureDextProvide who-submitted and cost-centre context for accountant workflows; Dext owns receipt capture and extraction.
Card-first spend controlPleo, SoldoProvide joiner/mover/leaver and cost-centre context; the spend platform owns cards, limits, receipts, and transactions.
Dedicated T&EExpensify, Zoho ExpenseProvide HR identity/org context; the T&E platform owns travel, claim workflow, policy, and reimbursement.

Boundaries

  • This recipe does not mean HollyHR has a native connector to any named spend product.
  • HollyHR does not expose an expenses API, card API, receipt API, reimbursement API, or accounting-ledger API.
  • Home address, date of birth, government identifiers, compensation, bank details, document bytes, and payroll export grants are not needed for this pattern.
  • Legal-entity org units are structural context only. They are not payroll or Companies House registration records.
  • Native connector work should be demand-gated by a named buyer, bureau, accountant, or provider partner.

Demand gate for a native connector

Open a connector/product slice only when a named opportunity can answer:

  1. Which spend tool is the buyer actually using?
  2. Which data must move that cannot be handled by API, webhooks, updated_since, or a no-code tool?
  3. Who owns support when a card is not disabled, a cost centre is wrong, or a claim posts to the wrong ledger account?
  4. Which sensitive fields cross the boundary, and which scopes/audit/DSAR rules cover them?
  5. Is this a one-customer convenience or a repeatable channel bet?

Until those answers are strong, keep expenses in the specialist system and use HollyHR as the clean HR source of truth.

Last modified on August 21, 2026
People syncTest SDK from source
On this page
  • What HollyHR should own
  • What the spend tool should own
  • Recommended scopes
  • Readiness check
  • Initial sync
  • Change handling
  • Provider patterns
  • Boundaries
  • Demand gate for a native connector