Skip to main content

Workflows

Overview

Workflows let you automate actions in response to events inside Financely. They are built as directed graphs: a trigger fires, then a sequence of steps executes. Go to Workflows in the sidebar to create and manage workflows.

Concepts

TermMeaning
TriggerThe event that starts the workflow (e.g. invoice.paid)
StepAn action to execute (e.g. HTTP Request, Send Email)
EdgeA connection between steps that defines execution order
RunA single execution of the workflow, with its own status and logs
VersionEvery time you update the steps or edges, a new version is created

All available triggers

Invoice events

TriggerFires when
invoice.createdA new invoice is created
invoice.paidAn invoice’s status changes to Paid
invoice.sentAn invoice’s status changes to Sent
invoice.overdueAn invoice passes its due date without being paid (checked daily)

Lead events

TriggerFires when
lead.qualifiedA lead’s status changes to Contacted
lead.convertedA lead’s status changes to Converted

Contact events

TriggerFires when
contact.createdA new contact is created
contact.updatedAn existing contact record is updated

Proposal events

TriggerFires when
proposal.createdA new proposal is created
proposal.sentA proposal is sent to a client
proposal.approvedA proposal’s status changes to Accepted
proposal.rejectedA proposal’s status changes to Rejected
proposal.converted_to_invoiceA proposal is converted to an invoice

Product events

TriggerFires when
product.createdA new product is added to the catalog
product.low_stockA product’s stock quantity drops to or below its low stock threshold

User events

TriggerFires when
user.joinedA user accepts an invitation and joins the organization

Schedule

TriggerFormat
schedule.cronA cron expression string — e.g. 0 9 * * * = daily at 9 AM UTC

Manual trigger

TriggerHow to use
manual.triggerHTTP POST to the trigger endpoint (see below)

External webhooks

Trigger a workflow from an external system using the webhookHandler endpoint with a custom eventType. This lets you fire Financely workflows from any external tool that can make an HTTP request.

HTTP Request step

The most common step type. Sends an HTTP request to any URL. Configuration fields:
FieldDetails
MethodGET, POST, PUT, PATCH, DELETE
URLThe endpoint to call. Supports template variables.
HeadersKey-value pairs. Supports template variables.
BodyJSON body for POST/PUT/PATCH. Supports template variables.
AuthenticationNone, Bearer token, or Basic auth

Template variables

Use {variable} syntax in URL, headers, and body to inject dynamic data from the triggering event.

Invoice variables

{invoice.number}       → Invoice number (e.g. INV-2025-001)
{invoice.total}        → Total amount
{invoice.currency}     → Currency code
{invoice.status}       → Current status
{invoice.dueDate}      → Due date (ISO string)
{invoice.id}           → Firestore document ID

Customer/contact variables

{customer.name}        → Buyer name
{customer.email}       → Buyer email address
{customer.company}     → Buyer company

Proposal variables

{proposal.title}       → Proposal title
{proposal.status}      → Current status
{proposal.id}          → Firestore document ID

Lead variables

{lead.id}              → Lead document ID
{lead.status}          → Current status

Secrets

{secret.api_key}       → Retrieves a secret named "api_key" from your org's secret store
Secrets are stored encrypted and are never exposed in the workflow UI after being set.

Example: notify on invoice payment

A workflow that POSTs to a Slack webhook when an invoice is paid: Trigger: invoice.paid Step 1 — HTTP Request:
  • Method: POST
  • URL: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
  • Body:
{
  "text": "Invoice {invoice.number} has been paid by {customer.name}. Amount: {invoice.total} {invoice.currency}"
}

Example: cron — daily overdue check

Trigger: schedule.cron0 8 * * * (every day at 8 AM UTC) Step 1 — HTTP Request: POST to your CRM or notification endpoint with a daily summary payload.

Manual trigger endpoint

To trigger a workflow externally via HTTP:
POST https://us-central1-{PROJECT_ID}.cloudfunctions.net/triggerWorkflow
Content-Type: application/json

{
  "workflowId": "workflow_abc123",
  "tenantId": "org_xyz789",
  "payload": {
    "customKey": "customValue"
  }
}
Response:
{
  "success": true,
  "eventId": "event_def456"
}
Optional headers:
  • x-correlation-id — for tracing across systems
  • x-idempotency-key — prevents duplicate executions for the same key

External webhook trigger

Trigger a workflow from an external system with a custom event type:
POST https://us-central1-{PROJECT_ID}.cloudfunctions.net/webhookHandler
Content-Type: application/json

{
  "tenantId": "org_xyz789",
  "eventType": "payment.received",
  "payload": {
    "amount": 500,
    "currency": "EUR"
  }
}
Create a workflow with a trigger matching payment.received to handle this.

Workflow run history

Every workflow execution creates a Run record. View run history from the workflow detail page:
  • Status: pending, running, completed, failed
  • Started / completed at timestamps
  • Step results: per-step status, request/response data, error messages
Use this to debug failed runs — expand any step to see the exact HTTP request sent and the response received.

Troubleshooting

Confirm the trigger event type matches exactly (case-sensitive). For Firestore-based triggers (invoice.paid, lead.converted, etc.), the trigger fires when the document field changes — make sure the status change is actually happening in the app.
Open the run history and expand the failed step. The response body and status code are logged. Common issues: wrong URL, missing auth header, body format mismatch, or the target server is rejecting requests.
Variable names are case-sensitive. Use the exact names listed in this document. If a variable is empty (e.g. customer has no company), the placeholder is replaced with an empty string.
Cron expressions use UTC. Adjust accordingly for your local timezone. Crons are checked every minute — a workflow set to 0 9 * * * fires once per day at exactly 09:00 UTC.