Employee Expense Workflow with Make.com and Slack
Route Google Forms receipt uploads through Cryvis extraction, Slack approval, and Google Sheets — write ledger rows only when managers approve.
Unreviewed OCR should not hit the books. This scenario collects employee receipts via Google Forms, extracts structured fields with Cryvis, asks a manager in Slack, and appends to Google Sheets only on approval. Rejections stop before finance.
Make overview: Make.com hub. Simpler no-approval logging: automate expense tracking. Sheets column design: receipt to Google Sheets.
Workflow
[Google Forms: Watch Responses]
employee | project | file upload
|
v
[Google Drive: Download a File]
|
v
[Filter: pdf|jpeg|png|webp]
|
v
[HTTP: Make a Request]
POST https://api.cryvis.com/v1/documents/receipt
|
v
[Slack: Create a Message / Approval]
merchant, date, total, photo link
|
+-- approved -------+
| v
| [Google Sheets: Add a Row]
| Status = Approved
|
+-- rejected -------+
v
[Sheets: Rejected tab]
or Slack DM to employeeModules
| Step | Module | Notes |
|---|---|---|
| 1 | Google Forms — Watch Responses | Trigger |
| 2 | Google Drive — Download a File | Form upload |
| 3 | Filter | MIME allowlist |
| 4 | HTTP — Make a Request | Cryvis Receipt |
| 5 | Slack — Send Message / Approval | Block kit or Approve/Reject buttons if your Slack module supports them |
| 6 | Router | Approved vs Rejected |
| 7a | Google Sheets — Add a Row | Approved ledger |
| 7b | Google Sheets — Add a Row | Rejected audit (optional) |
| 8 | Error Handler | Cryvis/Slack failures |
If your Slack app cannot do interactive approvals, approximate with reactions: a second scenario watches for :white_check_mark: on the bot message and continues. Prefer true Approve/Reject actions when available.
Form design
Keep the form short:
- Employee email (collect automatically if Workspace)
- Cost center / project code (required dropdown)
- Business purpose (short text)
- Receipt file (required upload)
- Optional: amount estimate (helps managers spot OCR mismatch)
Do not ask users to type merchant and total if Cryvis will extract them — duplicate entry creates conflicts. Show extracted values in Slack for confirmation instead.
Cryvis HTTP configuration
| Setting | Value |
|---|---|
| URL | https://api.cryvis.com/v1/documents/receipt |
| Method | POST |
| Auth | Authorization: Bearer <API_KEY> |
| Body | Multipart file = Drive binary |
One form response → one file → single-file envelope (success + data). Credits: 1 per page/image.
Docs: extractReceipt. Product: Receipt API.
Slack message content
Post a compact summary managers can decide in under 10 seconds:
Expense approval needed
Employee: {{form.email}}
Project: {{form.project}}
Purpose: {{form.purpose}}
Merchant: {{data.merchant.name}}
Date: {{data.transaction_date}}
Total: {{data.total_amount}} {{data.currency}}
Tax: {{data.tax_total}}
Receipt #: {{data.receipt_number}}
File: {{drive.webViewLink}}If data.total_amount disagrees with an optional form estimate by more than 5%, bold a warning line in Slack so approvers look twice.
Response mapping
Into Slack (pre-approval)
| Slack field | Source |
|---|---|
| Merchant | data.merchant.name |
| Date | data.transaction_date |
| Total | data.total_amount |
| Currency | data.currency |
| Tax | data.tax_total |
| Payment | data.payment.method |
| Type | data.receipt_type |
Into Sheets (approved only)
| Column | Source |
|---|---|
| Approved At | Approval timestamp |
| Approver | Slack user who approved |
| Employee | Form email |
| Project | Form project |
| Purpose | Form purpose |
| Merchant | data.merchant.name |
| Date | data.transaction_date |
| Total | data.total_amount |
| Tax | data.tax_total |
| Currency | data.currency |
| Receipt Number | data.receipt_number |
| Status | Approved |
| File URL | Drive link |
Rejected path: write to Rejected with reason (Slack reject comment) and never to Approved. Finance pivots only the Approved tab.
Destination specifics: Slack + Sheets
Routing approvers
Use a Router or Data Store lookup: project → Slack user/channel.
ENG-* → #eng-expenses
SALES-* → @sales-ops
default → #finance-approvalsDo not post every expense to a public company channel if receipts include personal purchases awaiting reimbursement — prefer private channels or DMs to managers.
Sheets hygiene
- Approved tab is append-only from Make.
- Humans may add
Paid in payrolllater; do not overwrite. - Protect header row; restrict edit on formula columns.
For duplicate detection after approval (same receipt submitted twice by an employee), combine receipt_number + transaction_date + employee email — pattern detailed in receipt to Google Sheets.
Holding state
Approvals are asynchronous. Options:
- Make Slack approval module that pauses the scenario until action (simplest).
- Split scenarios: Scenario A posts Slack + stores Cryvis JSON in Data Store keyed by
response_id. Scenario B webhook/slash receives approval and reads Data Store before Sheets write.
Option 2 survives longer manager delays and scenario edits mid-flight.
Filters and edge cases
- MIME filter before Cryvis.
- Soft-fail if
total_amountempty → Slack with “OCR incomplete — approve only if you open the file”. - Policy Filter: auto-reject or auto-escalate if
total_amount > 500(or your threshold) to finance lead. - Weekend travel: multiple Forms in one night — ensure Slack messages include Form timestamp to order them.
- Resubmits: employees fix a rejected receipt by submitting a new Form response (new row), not by editing the old one.
Invoice-style vendor PDFs uploaded by mistake should be routed to an invoice scenario (extract invoice data) or rejected with guidance.
Errors
| Failure | Handling |
|---|---|
| Cryvis auth error | Stop; alert #finance-ops; do not Slack-spam managers |
| Cryvis soft fail | Slack “extraction failed” with Drive link for manual review |
| Slack API error | Incomplete execution; do not mark Approved |
| Approval timeout | Data Store TTL + remind manager after 48h |
| Sheets write fail after approve | Critical alert — money was approved but not recorded |
Never write Approved rows before the Slack decision bundle resolves.
Test plan
- Submit Form with a clear JPEG; confirm Cryvis fields in the Slack preview.
- Approve → exactly one Approved Sheets row.
- Submit again; Reject → Rejected tab only.
- Submit unsupported file type → Filter stops before Slack.
- Submit high-dollar receipt → escalation route fires.
- Kill API key temporarily → Error Handler notifies ops, no orphan Approved rows.
Production checklist
- Slack bot installed to the right workspaces; least-privilege scopes.
- Manager mapping table owned by finance, not hardcoded in one scenario.
- Cryvis key rotation; credit budget for headcount × monthly receipts (1 credit / page / image).
- GDPR/PII: receipt images in Drive with restricted ACL; Sheets without card PAN (Cryvis
payment.last4only if policy allows). - Document the employee help text: “Upload one receipt per submission.”
Related guides
- Extract receipt data from images
- Convert receipts to JSON
- Extract receipt data (Drive → Sheets)
- Make.com hub
CTA
Extraction without control is just faster mess. Use the Cryvis Receipt API for structured merchant and totals, then gate ledger writes on Slack approval. Implementation reference: extractReceipt.