Back to Tax Preparation Workflow

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

Developer Handover Pack

Tax Preparation Workflow

[YourCompany.com] · Finance Department · Prepared by FullSpec · [Today's Date]

This pack gives the FullSpec build team everything needed to construct, connect, and validate the Tax Preparation Workflow automation. It covers the current-state process map with bottlenecks identified, full agent specifications with IO contracts, an end-to-end data flow trace, and the recommended build stack. The process owner's role is to confirm access credentials and resolve exception items flagged during testing. All build, integration, and deployment work is handled by FullSpec. Reach the FullSpec team at support@gofullspec.com for any pre-build queries.

01Process snapshot

Step
Name
Description
1
Open Preparation Checklist
Bookkeeper manually creates or copies a checklist in Google Drive listing every required document and report for the period. Time cost: 30 min/cycle.
2
Export Transactions from QuickBooks
Bookkeeper logs into QuickBooks, sets the date range, and exports profit and loss, balance sheet, and general ledger to spreadsheets. Time cost: 45 min/cycle.
3
Identify Missing or Uncategorised Transactions
BOTTLENECK. Bookkeeper scrolls through exported data and manually flags transactions missing categories, descriptions, or receipts, then compiles a follow-up list. Time cost: 60 min/cycle.
4
Chase Employees for Missing Receipts
BOTTLENECK. Bookkeeper emails each employee individually for flagged receipts and tracks follow-ups manually. Time cost: 40 min/cycle plus multiple follow-up rounds.
5
Collect and Sort Incoming Documents
As receipts, statements, and invoices arrive, the bookkeeper manually downloads, renames, and files each document into Google Drive. Time cost: 90 min/cycle.
6
Process Receipts Through Hubdoc
Collected receipts are uploaded to Hubdoc for OCR extraction. Bookkeeper checks each extracted record, corrects errors, and confirms the QuickBooks match. Time cost: 50 min/cycle.
7
Reconcile Bank and Credit Card Statements
BOTTLENECK. Bookkeeper downloads statements from each account and cross-references against QuickBooks entries, noting discrepancies manually. Time cost: 75 min/cycle.
8
Compile Tax Document Package
All verified reports, receipts, and statements are gathered into a single Google Drive folder or PDF. Bookkeeper manually checks completeness against the checklist. Time cost: 45 min/cycle.
9
Send Package to Accountant for Review
Bookkeeper emails the completed package to the external accountant with a summary of open items. Time cost: 20 min/cycle.
10
Obtain Sign-Off on Final Return
Finance Manager sends a DocuSign request to the director or business owner and tracks completion manually. Time cost: 25 min/cycle.
Time cost summary: Total manual time per cycle is 480 minutes (8 hours). At approximately 4 cycles per year this equals roughly 32 hours of bookkeeper time on manual preparation steps annually, before accounting for follow-up rounds and rework. The automation replaces steps 3, 4, 5, 6, 8, 9, and 10 in full, and partially replaces step 2 (QuickBooks export is automated). Step 7 (bank reconciliation) requires manual resolution only for discrepancies the automation surfaces. The bookkeeper's residual task is resolving exception items flagged by the Receipt Collection Coordinator, estimated at under 30 minutes per cycle. Bottleneck steps 3, 4, and 7 account for 175 minutes per cycle, nearly 37% of total preparation time.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Document Gap Detector

Compares the QuickBooks transaction export against the expected document checklist and identifies every missing receipt, uncategorised entry, or unmatched statement. Builds a structured request list broken down by employee or vendor. This agent fires at the start of each preparation window and produces the input list that drives all downstream agents. It must handle QuickBooks Online OAuth token refresh transparently and must not re-flag transactions already resolved in a prior partial run. Complexity: Moderate. Estimated build time: 10 hours.

Trigger
Scheduled trigger or manual start from the Finance Manager. Fires immediately after the QuickBooks report export completes at the start of each preparation window.
Tools
QuickBooks (OAuth 2.0, Reports API and Transactions API), Google Drive (Sheets API for checklist read/write)
Replaces steps
Step 3: Identify Missing or Uncategorised Transactions
Estimated build
10 hours, Moderate complexity
// Input
quickbooks.export.profit_loss   -> { period_start, period_end, line_items[] }
quickbooks.export.general_ledger -> { transactions[]: { txn_id, date, vendor, amount, category, receipt_attached } }
google_drive.checklist_sheet    -> { required_docs[]: { doc_type, employee_or_vendor, due_date } }

// Output
gap_list: {
  missing_receipts[]:    { txn_id, employee, amount, date, category }
  uncategorised_txns[]:  { txn_id, vendor, amount, date }
  unmatched_statements[]:{ account_id, period, expected_closing_balance }
  generated_at:          ISO8601 timestamp
  preparation_period:    { start, end }
}
  • QuickBooks Online (not Desktop or Enterprise) is assumed. If the client runs Desktop/Enterprise, a middleware connector such as a local sync agent must be confirmed before build starts. Confirm the active QuickBooks edition before writing any API calls.
  • OAuth 2.0 credentials (client_id, client_secret, refresh_token) must be provisioned by the QuickBooks account administrator and stored in the shared credential store before this agent can be built or tested.
  • The expected document checklist is stored as a Google Sheet with a fixed schema: columns doc_type, employee_or_vendor, period, and status. The sheet ID and tab name must be confirmed and locked before build. Any structural change post-build requires a mapping update.
  • Deduplication: the agent must check the gap_list output from the previous run (stored in the error-log table) and exclude any txn_id already marked resolved. This prevents repeat emails to employees for receipts already submitted.
  • Fallback behaviour: if the QuickBooks API returns a rate-limit error (429), the agent must back off with exponential retry (3 attempts, 30/60/120 second intervals) and post a Slack alert if all retries fail.
  • Confirm with the process owner: what percentage of transactions are from employees versus direct vendor invoices? This affects how the gap list is segmented for the next agent.
Receipt Collection Coordinator

Sends personalised receipt request emails to employees via Gmail, monitors replies and uploads, processes incoming documents through Hubdoc, and matches each receipt to its corresponding QuickBooks transaction. Any item that cannot be matched automatically is escalated to the bookkeeper via a dedicated Slack channel with full transaction context. This agent handles steps 4, 5, and 6 of the manual process and is the highest-volume agent in the workflow. Complexity: Complex. Estimated build time: 18 hours.

Trigger
Triggered by the gap_list output produced by the Document Gap Detector. Each entry in missing_receipts[] spawns an individual email task.
Tools
Gmail (Gmail API, OAuth 2.0, send and watch scopes), Hubdoc (REST API, document upload and extraction endpoints), QuickBooks (Transactions API, receipt attachment endpoint), Slack (Incoming Webhooks or Bot Token, post to #tax-exceptions channel)
Replaces steps
Step 4: Chase Employees for Missing Receipts; Step 5: Collect and Sort Incoming Documents; Step 6: Process Receipts Through Hubdoc
Estimated build
18 hours, Complex complexity
// Input
gap_list.missing_receipts[]: { txn_id, employee_email, amount, date, category, vendor }
gmail.inbound_reply:          { from_email, thread_id, attachments[]: { filename, mime_type, file_data } }
hubdoc.extraction_result:     { doc_id, vendor_name, date, total_amount, currency, confidence_score }

// Output
receipt_log: {
  matched[]:   { txn_id, hubdoc_doc_id, qb_attachment_id, confidence_score, matched_at }
  unmatched[]: { txn_id, employee_email, reason_code, escalated_at }
}

// On exception (unmatched item)
slack.post to #tax-exceptions: {
  txn_id, employee, amount, date, category,
  reason_code: 'LOW_CONFIDENCE' | 'NO_REPLY' | 'WRONG_AMOUNT' | 'DUPLICATE',
  action_required: 'Bookkeeper to resolve manually'
}
  • Gmail API requires the gmail.send and gmail.readonly OAuth scopes. A dedicated service account or delegated credentials for the bookkeeper's Gmail address must be confirmed before build. Do not use a personal OAuth token that may expire without a refresh mechanism.
  • Gmail watch (push notifications) should be configured on the bookkeeper's inbox with a Pub/Sub topic to capture inbound replies without polling. Confirm the Google Cloud project and Pub/Sub topic name before configuring the watch subscription.
  • Hubdoc API: documents are uploaded via POST /documents with multipart/form-data. The extraction result is retrieved via GET /documents/{doc_id} polling until status is 'processed'. Set a polling timeout of 120 seconds before marking as failed.
  • Matching logic: match on (amount within $0.10 tolerance) AND (date within 3 calendar days) AND (vendor name fuzzy match, Levenshtein distance threshold of 2). Any match scoring below the threshold is flagged as LOW_CONFIDENCE and sent to Slack.
  • Hubdoc OCR accuracy drops on low-resolution or handwritten receipts. The matching threshold must be calibrated with a real sample of the client's receipts during the sandbox test phase before going live.
  • Dedupe: if the same attachment filename and amount combination has already been matched to a txn_id in the current period, skip silently and log. Do not create duplicate QuickBooks attachments.
  • Follow-up emails: if no reply is received within 3 business days, send one automated follow-up. After a second 3-day window with no reply, escalate to the #tax-exceptions Slack channel and stop emailing. Confirm the follow-up cadence with the process owner before build.
  • Confirm with the process owner: who sends the Gmail emails, the bookkeeper's address or a shared finance@ alias? The OAuth credentials must match the sending address.
Package Builder and Dispatcher

Assembles the verified reports, matched receipts, and reconciled statements into a structured document package in Google Drive, then dispatches the DocuSign sign-off request to the appropriate approver. Posts a Slack notification to the Finance Manager confirming the package is ready for the accountant. This agent is triggered only after the bookkeeper has confirmed all manual exception items are resolved. Complexity: Moderate. Estimated build time: 10 hours.

Trigger
Triggered when the bookkeeper posts a resolution confirmation in the #tax-exceptions Slack channel (a specific slash command or button interaction), signalling all exception items are cleared.
Tools
Google Drive (Drive API v3, file create, copy, and folder operations), DocuSign (eSignature REST API, envelope create and send), Slack (Bot Token, post to #finance-ops channel)
Replaces steps
Step 8: Compile Tax Document Package; Step 9: Send Package to Accountant for Review; Step 10: Obtain Sign-Off on Final Return
Estimated build
10 hours, Moderate complexity
// Input
receipt_log.matched[]:           { txn_id, hubdoc_doc_id, qb_attachment_id }
quickbooks.reports[]:            { report_type, file_id, period }
google_drive.checklist_sheet:    { all items status = 'resolved' }
slack.trigger_event:             { user_id, action: 'confirm_exceptions_resolved', period }

// Output
google_drive.package_folder: {
  folder_id,
  folder_path: '/Tax Packages/{YYYY-QQ}/',
  contents[]: { file_name, file_id, category }
}
docusign.envelope: {
  envelope_id,
  signer_email,
  signer_name,
  status: 'sent',
  sent_at: ISO8601 timestamp
}

// On approval (DocuSign webhook callback)
docusign.envelope.status = 'completed' ->
  slack.post to #finance-ops: {
    message: 'Tax package signed off. Ready for accountant.',
    drive_folder_link, envelope_id, completed_at
  }
  • Google Drive folder schema must be agreed and locked before build. Recommended path: /Tax Packages/{YYYY}/{QQ}/ with subfolders /Reports, /Receipts, /Statements, /Signed. Confirm the root Drive folder ID with the process owner.
  • DocuSign envelope templates must be created and reviewed by the accountant before build. One template per entity or filing type is required. Confirm the templateId values for each entity. Do not generate ad-hoc envelopes without a template as this breaks audit trail consistency.
  • DocuSign webhook (Connect): configure a Connect listener to receive envelope status callbacks. The automation platform endpoint URL must be registered in the DocuSign account settings. Status transitions to monitor: sent, delivered, completed, declined.
  • If DocuSign returns a declined status, post an alert to #tax-exceptions and halt the workflow. Do not auto-resend. Bookkeeper must investigate.
  • The Slack trigger (bookkeeper confirmation) must be implemented as a Slack interactive message button or a slash command, not a free-text keyword match, to prevent accidental triggers.
  • Confirm the signer routing with the process owner: is it always a single director, or does it route conditionally by entity or filing type? Routing logic must be mapped before the DocuSign template is configured.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow, Tax Preparation Workflow
// ── TRIGGER ──────────────────────────────────────────────────────────────
// Scheduled cron OR manual trigger from Finance Manager
TRIGGER: preparation_window_open
  -> payload: { period_start: DATE, period_end: DATE, entity_id: STRING }

// ── STEP 1: QuickBooks report export ─────────────────────────────────────
// Automation platform calls QuickBooks Reports API
GET /v3/company/{realmId}/reports/ProfitAndLoss
  params: { start_date, end_date, accounting_method: 'Accrual' }
  -> profit_loss: { rows[]: { account, amount } }

GET /v3/company/{realmId}/reports/GeneralLedger
  params: { start_date, end_date }
  -> general_ledger: { transactions[]: { txn_id, date, vendor, amount, category, receipt_attached: BOOL } }

// ── HANDOFF 1: To Document Gap Detector ─────────────────────────────────
AGENT_IN (Document Gap Detector):
  general_ledger.transactions[]
  google_drive.checklist_sheet -> required_docs[]: { doc_type, employee_or_vendor, status }

AGENT_LOGIC:
  FOR EACH txn IN general_ledger.transactions:
    IF txn.receipt_attached == FALSE OR txn.category == NULL:
      append to gap_list.missing_receipts { txn_id, employee, amount, date, category }
  FOR EACH doc IN required_docs WHERE doc.status != 'received':
      append to gap_list.unmatched_statements { account_id, period }

AGENT_OUT (Document Gap Detector):
  gap_list: { missing_receipts[], uncategorised_txns[], unmatched_statements[], generated_at }
  -> written to: error_log_table { run_id, period, gap_list_json, created_at }

// ── HANDOFF 2: To Receipt Collection Coordinator ─────────────────────────
AGENT_IN (Receipt Collection Coordinator):
  gap_list.missing_receipts[]: { txn_id, employee_email, amount, date, category, vendor }

AGENT_LOGIC (per missing_receipt):
  gmail.send(
    to: employee_email,
    template: 'receipt_request_v1',
    vars: { employee_name, txn_date, amount, vendor, upload_link }
  )
  -> thread_id stored against txn_id in run state

  ON inbound reply (gmail.watch Pub/Sub event):
    attachment -> POST /hubdoc/documents (multipart/form-data)
    POLL GET /hubdoc/documents/{doc_id} until status = 'processed'
    hubdoc_result: { vendor_name, date, total_amount, confidence_score }

  MATCH hubdoc_result TO general_ledger.txn:
    IF amount_delta <= 0.10 AND date_delta <= 3 days AND vendor_fuzzy <= 2:
      -> POST /v3/company/{realmId}/attachments { txn_id, doc_id }  // attach to QB
      -> receipt_log.matched[]: { txn_id, hubdoc_doc_id, qb_attachment_id, confidence_score }
    ELSE:
      -> receipt_log.unmatched[]: { txn_id, reason_code }
      -> slack.post #tax-exceptions { txn_id, employee, amount, reason_code }

  IF no reply after 3 business days:
    gmail.send follow_up (once)
    IF no reply after further 3 days:
      slack.post #tax-exceptions { action: 'ESCALATE', txn_id, employee_email }

AGENT_OUT (Receipt Collection Coordinator):
  receipt_log: { matched[], unmatched[] }
  -> written to: error_log_table { run_id, receipt_log_json, updated_at }

// ── MANUAL STEP: Bookkeeper resolves exceptions ───────────────────────────
// Bookkeeper reviews #tax-exceptions, resolves items manually (<30 min/cycle)
// When done, triggers Package Builder via Slack button or /resolve-exceptions slash command
SLACK_EVENT: { user_id, action: 'confirm_exceptions_resolved', period }

// ── HANDOFF 3: To Package Builder and Dispatcher ─────────────────────────
AGENT_IN (Package Builder and Dispatcher):
  receipt_log.matched[]
  quickbooks.reports[]: { report_type, file_id, period }
  google_drive.checklist_sheet (all statuses confirmed = 'resolved')

AGENT_LOGIC:
  CREATE Drive folder: /Tax Packages/{YYYY}/{QQ}/
  COPY reports      -> /Tax Packages/{YYYY}/{QQ}/Reports/
  COPY receipts     -> /Tax Packages/{YYYY}/{QQ}/Receipts/
  COPY statements   -> /Tax Packages/{YYYY}/{QQ}/Statements/
  UPDATE checklist_sheet: all rows status = 'packaged'

  POST /docusign/envelopes {
    templateId: entity_template_id,
    signers[]: [{ email: director_email, name: director_name, role: 'Director' }],
    emailSubject: 'Tax Return Sign-Off Required - {period}'
  }
  -> envelope_id stored in run state

ON DocuSign Connect webhook { envelope_id, status: 'completed' }:
  slack.post #finance-ops {
    message: 'Package signed. Ready for accountant.',
    drive_folder_link, envelope_id, completed_at
  }

ON DocuSign Connect webhook { envelope_id, status: 'declined' }:
  slack.post #tax-exceptions { alert: 'Sign-off declined. Investigate.' }
  -> HALT workflow

// ── END ──────────────────────────────────────────────────────────────────
// Final state: signed package in Drive, Slack confirmation sent,
// run record closed in error_log_table { run_id, status: 'complete', completed_at }
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation platform (the specific tool is confirmed at project kickoff). One workflow per agent is recommended: Workflow A (Document Gap Detector), Workflow B (Receipt Collection Coordinator), Workflow C (Package Builder and Dispatcher). A shared credential store holds all OAuth tokens and API keys centrally, with no hardcoded secrets in any workflow definition. Workflows communicate by writing and reading from a shared run-state data store (see error logging below).
Webhook configuration
Three inbound webhook endpoints are required. (1) Gmail Pub/Sub push subscription endpoint: receives new-message events from the Gmail watch subscription registered on the bookkeeper's inbox. Must be HTTPS with a verified domain. (2) DocuSign Connect endpoint: receives envelope status events (sent, completed, declined). Register the URL in the DocuSign account Connect settings under the relevant account. (3) Slack interactive endpoint: receives button-click and slash-command payloads from the #tax-exceptions channel for the bookkeeper exception-confirmation trigger. All endpoints must return HTTP 200 within 3 seconds or the sender will retry.
Templating approach
Gmail receipt request and follow-up emails use a template stored as a plain-text file with variable placeholders: {{employee_name}}, {{txn_date}}, {{amount}}, {{vendor}}, {{upload_link}}, {{deadline_date}}. Templates are version-controlled and referenced by name (receipt_request_v1, receipt_followup_v1) in the workflow. DocuSign envelope templates are maintained inside the DocuSign account by the process owner and referenced by templateId in the workflow. No envelope content is generated dynamically; the template controls all field positions and signing order.
Error logging
All run events, agent outputs, exception flags, and final statuses are written to a Supabase table named tax_prep_runs with columns: run_id (UUID), period_start, period_end, agent_name, event_type, payload_json, status, created_at. A separate table tax_prep_exceptions stores each unmatched or escalated item with columns: exception_id, run_id, txn_id, reason_code, escalated_at, resolved_at, resolved_by. On any critical failure (QuickBooks API down after retries, Hubdoc extraction timeout, DocuSign envelope declined), an alert is posted to #tax-exceptions in Slack via the bot token and the error record is written with status 'FAILED' before the workflow halts.
Testing approach
All agents are built and tested in a sandbox environment first. QuickBooks provides a sandbox company accessible via the developer portal; use this for all API call testing. Hubdoc testing uses a dedicated test account with a prepared set of sample receipts including at least one low-quality image, one duplicate, and one handwritten receipt to calibrate the matching threshold. Gmail tests use a sandbox Google Workspace account. DocuSign sandbox (demo.docusign.net) is used for all envelope testing before credentials are switched to production. No live QuickBooks data, live Gmail inboxes, or live DocuSign accounts are used during build. A parallel run alongside the manual process is conducted for one full preparation cycle before the automation is set to sole operation.
Credential list (to be confirmed before build)
QuickBooks Online: client_id, client_secret, refresh_token, realmId. Google (Drive + Gmail + Pub/Sub): OAuth 2.0 client_id, client_secret, refresh_token, Pub/Sub topic name, Drive root folder ID, checklist sheet ID. Hubdoc: API key, account ID. Slack: bot token (xoxb-), #tax-exceptions channel ID, #finance-ops channel ID, interactive endpoint verified request signing secret. DocuSign: integration key (client_id), account_id, user_id, RSA private key (JWT auth), per-entity templateId values, Connect listener URL.
Estimated total build time
Document Gap Detector: 10 hours. Receipt Collection Coordinator: 18 hours. Package Builder and Dispatcher: 10 hours. End-to-end integration testing and parallel run validation: 8 hours. Total: 38 hours across a 4 to 5 week delivery window (aligned to the Standard build timeline).
Pre-build blockers to resolve before any development starts: (1) Confirm QuickBooks edition (Online required; Desktop/Enterprise needs a middleware connector). (2) Confirm the Gmail sending address and provision OAuth credentials for that address. (3) Lock the Google Drive folder schema and checklist sheet structure. (4) Confirm DocuSign templateId values for each entity. (5) Confirm the Slack channel names and bot token scope (channels:join, chat:write, commands). None of these are build decisions; they are access and configuration decisions that the process owner must sign off on. Contact support@gofullspec.com to run through the credential checklist before the build week begins.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Tax Preparation Workflow.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View