C
Cotizera Docs

Automations API

Automations API

Automations execute automatic actions when events occur on your quotes. You can send emails, change statuses, fire webhooks, and more — all based on configurable conditions.

All endpoints require PRO plan and config:manage permission (Owner only).


List Automations

GET /api/automations

Lists all automations for the tenant, including execution counts.

Response 200 OK:

[
  {
    "id": "clxyz...",
    "name": "Notify on acceptance",
    "trigger": "QUOTE_ACCEPTED",
    "isActive": true,
    "conditions": [
      { "field": "total", "operator": "gt", "value": 5000 }
    ],
    "actions": [
      { "type": "send_email", "to": "owner", "subject": "Quote accepted", "body": "..." }
    ],
    "delayMinutes": 0,
    "createdAt": "2026-04-01T10:00:00.000Z",
    "_count": { "logs": 12 }
  }
]

Create Automation

POST /api/automations

Permission: config:manage | Plan: PRO

Request body:

{
  "name": "Email on large quote sent",
  "trigger": "QUOTE_SENT",
  "conditions": [
    { "field": "total", "operator": "gt", "value": 10000 },
    { "field": "client.companyName", "operator": "is_not_empty" }
  ],
  "actions": [
    {
      "type": "send_email",
      "to": "client",
      "subject": "Your quote is ready",
      "body": "Thank you for your interest. Your quote is attached."
    }
  ],
  "delayMinutes": 5
}
Field Type Required Description
name string Yes Name (1-100 characters)
trigger string Yes Event that triggers the automation (see table below)
conditions array No Conditions that must be met (AND logic)
actions array Yes At least one action to execute
delayMinutes number No Minutes to delay before executing (default: 0)

Response 201 Created: Returns the created automation.


Triggers (Events)

Trigger Description
QUOTE_CREATED A new quote was created
QUOTE_SENT A quote was sent to the client
QUOTE_VIEWED The client viewed the quote in the portal
QUOTE_ACCEPTED The client accepted the quote
QUOTE_REJECTED The client rejected the quote
QUOTE_WON The quote was marked as won
QUOTE_LOST The quote was marked as lost
QUOTE_EXPIRING The quote is about to expire (within 24 hours)

Conditions

Conditions filter when the automation executes. All conditions must be met (AND logic).

{ "field": "total", "operator": "gt", "value": 5000 }
Field Type Required Description
field string Yes Field to evaluate (see available fields)
operator string Yes Comparison operator
value string/number Depends Value to compare (not required for is_empty/is_not_empty)

Operators

Operator Description Compatible types
eq Equals all
neq Not equals all
gt Greater than number
lt Less than number
gte Greater than or equal number
lte Less than or equal number
contains Contains text text
starts_with Starts with text
is_empty Is empty (no value) text
is_not_empty Is not empty text

Available fields

Quote

Field Type Operators
status select eq, neq
currency select eq, neq
total number eq, neq, gt, lt, gte, lte
subtotal number eq, neq, gt, lt, gte, lte
tax number eq, neq, gt, lt, gte, lte
shippingCost number eq, neq, gt, lt, gte, lte
viewCount number eq, neq, gt, lt, gte, lte
quoteNumber number eq, neq, gt, lt, gte, lte
notes text eq, neq, contains, starts_with, is_empty, is_not_empty

Client

Field Type Operators
client.contactName text eq, neq, contains, starts_with
client.companyName text eq, neq, contains, starts_with, is_empty, is_not_empty
client.email text eq, neq, contains, starts_with
client.phone text eq, neq, contains, is_empty, is_not_empty

Product

Fields prefixed with items.* evaluate whether any product in the quote matches the condition.

Field Type Operators
items.productName text eq, neq, contains, starts_with
items.model text eq, neq, contains, is_empty, is_not_empty
items.unitPrice number eq, neq, gt, lt, gte, lte
items.quantity number eq, neq, gt, lt, gte, lte
items.discountPct number eq, neq, gt, lt, gte, lte
💡

items.* fields use "any matches" logic — the condition is met if at least one product in the quote matches.


Actions

Each automation must have at least one action. They execute in order.

send_email

Sends an email.

{
  "type": "send_email",
  "to": "client",
  "subject": "Your quote is ready",
  "body": "We've prepared a personalized quote for you."
}
Field Type Required Description
to string Yes "client", "owner", or "custom"
customEmail string Conditional Destination email (required if to is "custom")
subject string Yes Email subject
body string Yes Email body

send_notification

Creates an in-app notification for the owner.

{
  "type": "send_notification",
  "title": "Quote accepted",
  "body": "The client has accepted quote COT-0042"
}

change_status

Changes the quote status.

{
  "type": "change_status",
  "newStatus": "SENT"
}

Valid values: GENERATED, SENT, WON, LOST, ACCEPTED, REJECTED

add_label

Adds a label to the quote.

{
  "type": "add_label",
  "labelId": "clxyz..."
}

create_reminder

Creates a follow-up reminder.

{
  "type": "create_reminder",
  "delayMinutes": 1440,
  "message": "Follow up on this quote"
}

fire_webhook

Sends a POST to an external URL with the quote data. Ideal for connecting with Zapier, Slack, or any external service.

{
  "type": "fire_webhook",
  "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
  "headers": {
    "Authorization": "Bearer my-secret-token"
  },
  "includeItems": true
}
Field Type Required Description
url string Yes Webhook URL (must be valid)
headers object No Additional HTTP headers (e.g., Authorization)
includeItems boolean No Include products in the payload (default: true)

The payload sent has this structure:

{
  "event": "QUOTE_SENT",
  "timestamp": "2026-04-09T14:30:00.000Z",
  "data": {
    "quote": {
      "id": "clxyz...",
      "quoteNumber": 42,
      "status": "SENT",
      "total": 15000,
      "subtotal": 13000,
      "currency": "MXN",
      "notes": "...",
      "client": {
        "id": "...",
        "contactName": "María López",
        "companyName": "Acme Corp",
        "email": "maria@acme.com"
      },
      "items": [
        {
          "productName": "Premium service",
          "model": "SRV-001",
          "unitPrice": 13000,
          "quantity": 1,
          "discountPct": 0
        }
      ]
    }
  }
}
ℹ️

The webhook has a 5-second timeout. If the server doesn't respond in time, the action is logged as failed.


Get an Automation

GET /api/automations/:id

Permission: config:manage | Plan: PRO

Gets an automation with its last 10 executions.

Response 200 OK: Returns the automation with the logs array.


Update Automation

PATCH /api/automations/:id

Permission: config:manage | Plan: PRO

Updates an automation. All fields are optional. Includes isActive to enable or disable.

{
  "isActive": false
}

Response 200 OK: Returns the updated automation.


Delete Automation

DELETE /api/automations/:id

Permission: config:manage

Permanently deletes an automation and all its execution history.

Response 200 OK:

{
  "ok": true
}
⚠️

This operation cannot be undone. All execution logs are also deleted.


Execution History

GET /api/automations/:id/logs

Permission: config:manage | Plan: PRO

Lists executions for an automation with pagination.

Query parameters:

Parameter Type Default Description
page number 1 Page number
limit number 20 Results per page (max 100)

Response 200 OK:

{
  "logs": [
    {
      "id": "clxyz...",
      "automationId": "...",
      "quoteId": "...",
      "tenantId": "...",
      "status": "COMPLETED",
      "triggeredAt": "2026-04-09T14:30:00.000Z",
      "completedAt": "2026-04-09T14:30:01.000Z",
      "error": null
    }
  ],
  "total": 47,
  "page": 1,
  "totalPages": 3
}

Possible statuses: TRIGGERED, COMPLETED, FAILED.

© 2026 Cotizera. All rights reserved.