ml-connector
DeltekExpensify

Deltek and Expensify integration

Deltek Vantagepoint runs project accounting, billing, and the general ledger for professional services firms. Expensify captures employee expenses, scans receipts, and runs the approval workflow. Connecting the two means approved expense reports stop being re-keyed into Deltek by hand. Each report flows from Expensify into Deltek as an employee expense report with its category mapped to a GL account and its tag mapped to a project. ml-connector handles the very different request styles on each side and moves the data on a schedule you control.

How Deltek works

Deltek Vantagepoint exposes employees, firms, projects, AP invoices, AR invoices, journal entries, employee expense reports, and GL accounts through a REST JSON API on a company-specific deltekfirst.com URL, so there is no shared hostname. It authenticates with an OAuth2 password grant that returns a bearer token valid for about an hour plus a refresh token, and the Allow Password Grant Type setting must be enabled for server-to-server access. Vantagepoint has workflow-driven outbound webhooks for record save events, but no HMAC signature and no pub/sub event bus, so finance data is read by polling. There is no native idempotency header, so duplicates must be prevented by checking for an existing record before posting.

How Expensify works

Expensify's Integration Server API sends every request as an HTTP POST to a single endpoint, with the operation chosen by a type field inside the JSON body. Authentication is a long-lived partnerUserID and partnerUserSecret pair passed inline on every call, not OAuth, so there are no tokens to refresh. It exposes expense reports, individual expenses, employees, and policies, and GL codes live as a categoryGLCodeMap on each policy while tags act as accounting dimensions. Expensify does not push events and has no webhooks, so a connector must poll using approvedAfter and the markedAsExported filter. Amounts are returned in cents, and there is no sandbox, so all calls run against production.

What moves between them

The main flow runs from Expensify into Deltek. ml-connector polls Expensify for expense reports in an APPROVED or REIMBURSED state and posts each one into Deltek as an employee expense report, with line categories mapped to Deltek GL accounts and tags mapped to Deltek projects. Employee and approver records flow the other way, from Deltek into Expensify policies, so the approval chain and policy membership reflect the firm's current staff. Reference data such as expense categories, GL accounts, and projects is aligned so every imported line references a code that already exists in Deltek. Expensify holds no vendor, invoice, or payment objects, so ml-connector treats it strictly as the source of employee expense activity.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the Deltek side it accepts the full company-specific instance URL per customer, runs the OAuth2 password grant, and refreshes the bearer token when a call returns 401. On the Expensify side it builds the single POST with the partner credentials embedded in the requestJobDescription body. Because Expensify never pushes, the connector polls on your schedule, passing approvedAfter set to the last processed timestamp and filtering markedAsExported so a report is never imported twice, then calls the markAsExported action on each report it ingests. Expensify amounts arrive in cents and are converted to Deltek's decimal amounts before posting. Categories map to Deltek GL accounts and tags map to projects, so a missing mapping is flagged rather than guessed. Expensify rate limits of five requests per ten seconds and twenty per minute return HTTP 429, so the connector backs off with jitter, and because Deltek offers no idempotency key it checks for an existing expense report before posting. Every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A 200-person architecture and engineering firm runs Deltek Vantagepoint for project accounting and billing, and uses Expensify for travel and field expenses across several project teams. Before the integration, accounting exported approved reports from Expensify each week and re-entered them into Deltek line by line, choosing a GL account and project code for every expense by hand, which delayed project cost reporting and introduced coding errors. With Deltek and Expensify connected, approved reports post into Deltek automatically, each line coded to the right GL account and project from the Expensify category and tag. Project managers see expense costs against their jobs within a day, and the weekly re-keying step is gone.

What you can do

  • Post approved and reimbursed Expensify expense reports into Deltek as employee expense reports automatically.
  • Map each Expensify category to a Deltek GL account and each tag to a Deltek project so lines are coded correctly.
  • Push employee and approver records from Deltek into Expensify policies to keep approval chains aligned.
  • Bridge the Expensify partner secret to the Deltek OAuth2 password grant, with both credential sets stored encrypted.
  • Poll Expensify on your schedule with markedAsExported deduplication, backoff on rate limits, and a full audit trail on every record.

Questions

Which direction does data move between Deltek and Expensify?
The main flow is Expensify into Deltek. Approved and reimbursed expense reports move from Expensify into Deltek as employee expense reports, while employee and approver records move from Deltek into Expensify policies. Categories, GL accounts, and projects are aligned so every imported line references a code that already exists in Deltek.
How does the integration handle Expensify having no webhooks?
Expensify does not push events, so ml-connector polls on a schedule you set. It passes approvedAfter set to the last processed timestamp and uses the markedAsExported filter to skip reports it has already imported, then marks each report as exported once it lands in Deltek. This keeps a report from being posted to Deltek twice.
How are Expensify categories and amounts translated for Deltek?
Expensify stores GL codes as a categoryGLCodeMap on each policy and uses tags as accounting dimensions, so ml-connector maps each category to a Deltek GL account and each tag to a Deltek project. Expensify amounts arrive in cents, so they are converted to Deltek's decimal amounts before posting. A category or tag with no matching Deltek code is flagged rather than guessed.

Related integrations

Connect Deltek and Expensify

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started