openapi: 3.1.0
info:
version: v10.40.4
contact: {}
title: Vic.ai Accounts Invoice Approval Flows API
description: "## Introduction\n\nThe Vic.ai API provides a seamless connection between your Enterprise Resource\nPlanning (ERP) system and the Vic.ai product suite.\n\nThe API is designed to offer three main areas of functionality:\n\n- **Syncing master data:** This refers to the data in your ERP that Vic.ai\n interacts with. You are required to supply and update this data in Vic.ai, and\n you also have the option to verify the copy of the masterdata in Vic.ai.\n\n- **Syncing training data:** We need historical data to train your AI model. To\n that end, the API provides endpoints to sync historical invoices into Vic.ai\n and to confirm their presence.\n\n- **Subscribing to and receiving webhooks:** Webhooks enable users or automated\n tasks to interact with your ERP through various actions in the Vic.ai product\n suite, such as posting an invoice, payment or purchase order or requesting\n synchronization. You will receive a notification via a webhook when these\n actions occur.\n\n\nFor US-based integrations, please use the following base API URL:\n\n```\nhttps://api.us.vic.ai\n```\n\nFor integrations based in Norway, use the following base API URL:\n\n```\nhttps://api.no.vic.ai\n```\n\nAll paths mentioned in this documentation should use one of these URLs as the\nbase.\n\nExample:\n\n```bash\ncurl https://api.us.vic.ai/v0/healthCheck \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer YOUR_ACCESS_TOKEN\"\n```\n\n## Getting Started\n\nTo begin interacting with the Vic.ai API, you will need the following\ncredentials:\n\n* A Vic.ai client ID\n* A Vic.ai client secret.\n\nThese can be provided to you securely by a Vic.ai representative\n[upon request](https://www.vic.ai/book-a-demo).\n\n**Please note:** These credentials are essentially the keys to your ERP\nintegration. If they fall into the wrong hands, unauthorized parties could\nimpersonate you, gain access to sensitive data, and potentially perform\nmalicious actions. Therefore, it's crucial to keep these credentials safe at all\ntimes to protect your application's integrity and your clients' data.\n\n### Limitations\n\nThe Vic.ai API has the following limitations:\n\n**Rate Limiting:** The API is rate-limited to 500 requests per 10-second time\nframe. If you exceed this limit, you will receive a `429 Too Many Requests`\nresponse. The limit is per Oauth client ID. If you continue to receive `429`s,\nplease contact support with a request id from the response headers.\n"
servers:
- url: https://api.no.stage.vic.ai
description: staging server, NO
- url: https://api.us.vic.ai
description: production server, US
- url: https://api.no.vic.ai
description: production server, NO
security:
- BearerAuth: []
tags:
- name: Invoice Approval Flows
description: 'Invoice approval flows define the criteria and steps for processing invoices
through an approval workflow. These operations allow you to create, update,
and manage approval flows with selection rules and approval steps.
'
paths:
/v2/companies/{company_id}/invoice_approval_flows:
parameters:
- $ref: '#/components/parameters/CompanyId'
get:
description: 'Lists invoice approval flows for a company. Returns a paginated list of
approval flows with their selection rules and steps.
'
summary: List invoice approval flows
operationId: listInvoiceApprovalFlowsV2
tags:
- Invoice Approval Flows
x-badges:
- name: V2
position: after
color: blue
parameters:
- $ref: '#/components/parameters/PaginationV2'
responses:
'200':
$ref: '#/components/responses/ListInvoiceApprovalFlowsResponseV2'
4XX:
$ref: '#/components/responses/ErrorResponseV2'
post:
description: "## Creating a Flow with Selection Rules\n\nWhen you create an approval flow (see the main invoice approval flow endpoint documentation for the request/response contract), you can define the selection rules that determine which invoices will be routed through that flow and its steps. The sections below describe the structure and semantics for those selection rules so you can include them in the `InvoiceApprovalFlowInputV2` payload.\n\n**Request Body:** `InvoiceApprovalFlowInputV2`\n\n**Response:** `201 Created` with the created flow data\n\n## Invoice Approval Flow Structure\n\nAn approval flow consists of:\n1. **Flow properties** - Label, description, ordering, and behavior settings\n2. **Selection rules** - Criteria that determine which invoices match this flow\n3. **Steps** - Sequential approval steps with their own selection and approver rules\n\n### Complete Flow Example\n\n```json\n{\n \"label\": \"High Value Invoices\",\n \"description\": \"Approval flow for invoices over $10,000\",\n \"index\": 0,\n \"auto_initiate\": true,\n \"selection_rules\": [\n {\n \"type\": \"invoice_total_amount\",\n \"comparator\": \"gte\",\n \"values_type\": \"decimal\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"10000.00\",\n \"value_name\": \"10000.00\",\n \"index\": 0\n }\n ]\n }\n ],\n \"steps\": [\n {\n \"index\": 0,\n \"approvers_required\": \"any\",\n \"skip_if_no_approvers\": false,\n \"selection_rules\": [],\n \"approver_selection_rules\": [\n {\n \"type\": \"ROLE\",\n \"values\": [\n {\n \"value\": \"Finance Manager\",\n \"value_name\": \"Finance Manager\"\n }\n ]\n }\n ]\n }\n ]\n}\n```\n\n## Flow Properties\n\n### Required Fields\n\n- **`label`** (string, max 255 chars) - The label for the approval flow\n - Example: `\"High Value Invoices\"`\n\n- **`description`** (string, max 255 chars) - A description of the approval flow\n - Example: `\"Approval flow for invoices over $10,000\"`\n\n- **`index`** (integer, minimum 0) - The order index for this approval flow\n - Flows are evaluated in order from lowest to highest index\n - Example: `0`\n\n- **`auto_initiate`** (boolean) - Whether to automatically initiate this approval flow\n - Example: `true`\n\n- **`selection_rules`** (array) - Selection rules that define when this flow applies\n - See [Selection Rules](#selection-rules) section below\n\n### Optional Fields\n\n- **`steps`** (array) - The approval steps for this flow\n - See [Approval Steps](#approval-steps) section below\n\n---\n\n## Selection Rules\n\nSelection rules determine which invoices match a particular flow or step based on various invoice attributes.\n\nSelection rules use the `InvoiceApprovalFlowSelectionRuleInputV2` schema with the following structure:\n\n```json\n{\n \"type\": \"invoice_vendor_id\",\n \"comparator\": \"eq\",\n \"values_type\": \"list_of_values\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"12345\",\n \"value_name\": \"Acme Corp\",\n \"index\": 0\n }\n ]\n}\n```\n\n### Important Note on Display Names\n\n**Always populate `value_name`, `start_value_name`, and `end_value_name` fields.** These fields are used to display human-readable names in the user interface. While the `value` fields contain IDs or raw values for matching logic, the display name fields ensure users see meaningful text rather than cryptic IDs or numbers.\n\n### Selection Rule Types\n\nThe following selection rule types are available for matching invoices to flows and steps.\n\n#### 1. Invoice Vendor ID (`invoice_vendor_id`)\n\nMatches invoices from specific vendors.\n\n**Supported Comparators:** `eq`, `in`\n\n**Values Type:** `list_of_values`\n\n**Type ID:** Not used (set to `null`)\n\n**Values Structure:**\n- `value`: Vendor ID (as string)\n- `value_name`: Vendor name - **Always populate this for UI display**\n- `value_type`: Always `\"single\"`\n\n**Example - Single Vendor (eq):**\n```json\n{\n \"type\": \"invoice_vendor_id\",\n \"comparator\": \"eq\",\n \"values_type\": \"list_of_values\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"12345\",\n \"value_name\": \"Acme Corporation\",\n \"index\": 0\n }\n ]\n}\n```\n\n**Example - Multiple Vendors (in):**\n```json\n{\n \"type\": \"invoice_vendor_id\",\n \"comparator\": \"in\",\n \"values_type\": \"list_of_values\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"12345\",\n \"value_name\": \"Acme Corporation\",\n \"index\": 0\n },\n {\n \"value_type\": \"single\",\n \"value\": \"67890\",\n \"value_name\": \"Beta Industries\",\n \"index\": 1\n }\n ]\n}\n```\n\n---\n\n#### 2. Invoice Vendor Tags (`invoice_vendor_tags`)\n\nMatches invoices from vendors that have specific tags.\n\n**Supported Comparators:** `in`\n\n**Values Type:** `list_of_values`\n\n**Type ID:** Not used (set to `null`)\n\n**Values Structure:**\n- `value`: Tag ID (as string)\n- `value_name`: Tag value - **Always populate this for UI display**\n- `value_type`: Always `\"single\"`\n\n**Example:**\n```json\n{\n \"type\": \"invoice_vendor_tags\",\n \"comparator\": \"in\",\n \"values_type\": \"list_of_values\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"100\",\n \"value_name\": \"Preferred Vendor\",\n \"index\": 0\n },\n {\n \"value_type\": \"single\",\n \"value\": \"101\",\n \"value_name\": \"Critical Supplier\",\n \"index\": 1\n }\n ]\n}\n```\n\n---\n\n#### 3. Invoice Total Amount (`invoice_total_amount`)\n\nMatches invoices based on the total amount of expense line items.\n\n**Supported Comparators:** `gt`, `gte`, `lt`, `lte`, `eq`\n\n**Values Type:** `decimal`\n\n**Type ID:** Not used (set to `null`)\n\n**Values Structure:**\n- `value`: Decimal amount (as string)\n- `value_name`: Amount formatted for display - **Should match `value` for consistency**\n- `value_type`: Always `\"single\"`\n- Only one value should be provided\n\n**Example - Greater Than or Equal:**\n```json\n{\n \"type\": \"invoice_total_amount\",\n \"comparator\": \"gte\",\n \"values_type\": \"decimal\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"10000.00\",\n \"value_name\": \"10000.00\",\n \"index\": 0\n }\n ]\n}\n```\n\n**Example - Less Than:**\n```json\n{\n \"type\": \"invoice_total_amount\",\n \"comparator\": \"lt\",\n \"values_type\": \"decimal\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"5000.00\",\n \"value_name\": \"5000.00\",\n \"index\": 0\n }\n ]\n}\n```\n\n---\n\n#### 4. Invoice PO Numbers (`invoice_po_numbers`)\n\nMatches invoices with purchase order numbers within numeric range(s).\n\n**Supported Comparators:** `between`\n\n**Values Type:** `positive_integer`\n\n**Type ID:** Not used (set to `null`)\n\n**Values Structure:**\n- `value_type`: Always `\"range\"`\n- `start_value`: Starting PO number (as string)\n- `start_value_name`: Starting PO number formatted for display - **Always populate for UI**\n- `end_value`: Ending PO number (as string)\n- `end_value_name`: Ending PO number formatted for display - **Always populate for UI**\n- Multiple ranges can be specified\n\n**Example - Single Range:**\n```json\n{\n \"type\": \"invoice_po_numbers\",\n \"comparator\": \"between\",\n \"values_type\": \"positive_integer\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"range\",\n \"start_value\": \"1000\",\n \"start_value_name\": \"1000\",\n \"end_value\": \"2000\",\n \"end_value_name\": \"2000\",\n \"index\": 0\n }\n ]\n}\n```\n\n**Example - Multiple Ranges:**\n```json\n{\n \"type\": \"invoice_po_numbers\",\n \"comparator\": \"between\",\n \"values_type\": \"positive_integer\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"range\",\n \"start_value\": \"1000\",\n \"start_value_name\": \"1000\",\n \"end_value\": \"2000\",\n \"end_value_name\": \"2000\",\n \"index\": 0\n },\n {\n \"value_type\": \"range\",\n \"start_value\": \"5000\",\n \"start_value_name\": \"5000\",\n \"end_value\": \"6000\",\n \"end_value_name\": \"6000\",\n \"index\": 1\n }\n ]\n}\n```\n\n---\n\n#### 5. Invoice Item Cost Account Number (`invoice_item_cost_account_number`)\n\nMatches invoices where any expense line item has a cost account matching the criteria.\n\n**Supported Comparators:** `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `between`\n\n**Values Type:**\n- `list_of_values` for `eq`, `in`\n- `positive_integer` for `between`\n\n**Type ID:** Not used (set to `null`)\n\n**Values Structure for eq/in:**\n- `value`: Cost account number (as string)\n- `value_name`: Cost account display name - **Should include number and name** (e.g., \"1000 - Office Supplies\")\n- `value_type`: Always `\"single\"`\n\n**Example - Equals:**\n```json\n{\n \"type\": \"invoice_item_cost_account_number\",\n \"comparator\": \"eq\",\n \"values_type\": \"list_of_values\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"5000\",\n \"value_name\": \"5000 - Office Expenses\",\n \"index\": 0\n }\n ]\n}\n```\n\n**Example - In List:**\n```json\n{\n \"type\": \"invoice_item_cost_account_number\",\n \"comparator\": \"in\",\n \"values_type\": \"list_of_values\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"5000\",\n \"value_name\": \"5000 - Office Expenses\",\n \"index\": 0\n },\n {\n \"value_type\": \"single\",\n \"value\": \"6000\",\n \"value_name\": \"6000 - Travel Expenses\",\n \"index\": 1\n }\n ]\n}\n```\n\n**Example - Between Range:**\n```json\n{\n \"type\": \"invoice_item_cost_account_number\",\n \"comparator\": \"between\",\n \"values_type\": \"positive_integer\",\n \"type_id\": null,\n \"values\": [\n {\n \"value_type\": \"range\",\n \"start_value\": \"5000\",\n \"start_value_name\": \"5000\",\n \"end_value\": \"5999\",\n \"end_value_name\": \"5999\",\n \"index\": 0\n }\n ]\n}\n```\n\n---\n\n#### 6. Invoice Item Dimension Name (`invoice_item_dimension_name`)\n\nMatches invoices where any expense line item has a dimension of a specific type with matching values.\n\n**Supported Comparators:** `eq`, `in`\n\n**Values Type:** `list_of_values`\n\n**Type ID:** **REQUIRED** - Must contain the dimension type (from `dimension.type` field)\n- This is a lowercase string like `\"department\"`, `\"location\"`, `\"project\"`, etc.\n- The comparison is case-insensitive, so `dimension.type` can be `\"Department\"` or `\"DEPARTMENT\"` but `type_id` should be lowercase\n\n**Values Structure:**\n- `value`: **Dimension ID** (from `dimension.id`, as string)\n- `value_name`: **Dimension display name** (from `dimension.display_name`) - **Always populate for UI display**\n- `value_type`: Always `\"single\"`\n\n⚠️ **Important:**\n- The `value` field should contain the dimension **ID**, not the dimension name\n- The `value_name` field **must** contain the `display_name` for proper UI display\n- Never omit `value_name` - it's essential for users to understand what dimension they're selecting\n\n**Example - Equals Specific Department:**\n```json\n{\n \"type\": \"invoice_item_dimension_name\",\n \"comparator\": \"eq\",\n \"values_type\": \"list_of_values\",\n \"type_id\": \"department\",\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"789\",\n \"value_name\": \"Engineering\",\n \"index\": 0\n }\n ]\n}\n```\n\n**Example - In Multiple Locations:**\n```json\n{\n \"type\": \"invoice_item_dimension_name\",\n \"comparator\": \"in\",\n \"values_type\": \"list_of_values\",\n \"type_id\": \"location\",\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"456\",\n \"value_name\": \"New York Office\",\n \"index\": 0\n },\n {\n \"value_type\": \"single\",\n \"value\": \"457\",\n \"value_name\": \"San Francisco Office\",\n \"index\": 1\n }\n ]\n}\n```\n\n**Matching Logic:**\n- The dimension `type` field is compared case-insensitively to `type_id`\n- The dimension `id` OR `display_name` is checked against the rule values\n- For `:in` comparator, any match in the list passes\n- For `:eq` comparator, only one value should be provided\n\n---\n\n#### 7. Invoice Custom Field (`invoice_custom_field`)\n\nMatches invoices based on custom header field values.\n\n**Supported Comparators:** `eq`, `in`\n\n**Values Type:**\n- `string` for text fields with `:eq`\n- `list_of_values` for select fields with `:eq` or `:in`\n\n**Type ID:** **REQUIRED** - Must contain the field label (e.g., `\"custom:department\"`, `\"custom:project_code\"`)\n\n**Values Structure:**\n- `value`: Field value (as string)\n- `value_name`: Same as value (for display purposes)\n- `value_type`: Always `\"single\"`\n\n**Field Type Considerations:**\n- **Text fields:** Use `values_type: \"string\"` with `comparator: \"eq\"`\n- **Select fields:** Use `values_type: \"list_of_values\"` with `comparator: \"eq\"` or `\"in\"`\n\n**Example - Text Field (eq):**\n```json\n{\n \"type\": \"invoice_custom_field\",\n \"comparator\": \"eq\",\n \"values_type\": \"string\",\n \"type_id\": \"custom:repair_order\",\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"RO-12345\",\n \"value_name\": \"RO-12345\",\n \"index\": 0\n }\n ]\n}\n```\n\n**Example - Select Field (eq):**\n```json\n{\n \"type\": \"invoice_custom_field\",\n \"comparator\": \"eq\",\n \"values_type\": \"list_of_values\",\n \"type_id\": \"custom:department\",\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"Engineering\",\n \"value_name\": \"Engineering\",\n \"index\": 0\n }\n ]\n}\n```\n\n**Example - Select Field (in):**\n```json\n{\n \"type\": \"invoice_custom_field\",\n \"comparator\": \"in\",\n \"values_type\": \"list_of_values\",\n \"type_id\": \"custom:category\",\n \"values\": [\n {\n \"value_type\": \"single\",\n \"value\": \"Office Supplies\",\n \"value_name\": \"Office Supplies\",\n \"index\": 0\n },\n {\n \"value_type\": \"single\",\n \"value\": \"Office Equipment\",\n \"value_name\": \"Office Equipment\",\n \"index\": 1\n }\n ]\n}\n```\n\n**Matching Logic:**\n- Comparison is case-insensitive\n- For text fields, exact match after case normalization\n- For select fields, matches against predefined options\n\n---\n\n## Approval Steps\n\nApproval steps define the sequential approval process for a flow. Each step can have its own selection rules to determine when it applies, and approver selection rules to determine who should approve.\n\n### Step Structure\n\n```json\n{\n \"id\": 123,\n \"index\": 0,\n \"approvers_required\": \"any\",\n \"system_action\": null,\n \"skip_if_no_approvers\": false,\n \"selection_rules\": [],\n \"approver_selection_rules\": [\n {\n \"type\": \"ROLE\",\n \"values\": [\n {\n \"value\": \"Finance Manager\",\n \"value_name\": \"Finance Manager\"\n }\n ]\n }\n ],\n \"reminder_notifications\": [\n {\n \"delay_hours\": 24,\n \"recipient_role\": \"manager\"\n }\n ]\n}\n```\n\n### Step Fields\n\n#### Optional Fields\n\n- **`id`** (integer or null) - The ID of an existing step to update\n - If provided, the step will be updated in place\n - If omitted, a new step will be created\n - Example: `123`\n\n#### Required Fields\n\n- **`index`** (integer, minimum 0) - The order index for this step\n - Steps are evaluated in order from lowest to highest index\n - Example: `0`\n\n#### Optional Configuration Fields\n\n- **`approvers_required`** (string, default: `\"any\"`) - How many approvers are required\n - `\"any\"` - Any one approver can approve this step\n - `\"all\"` - All approvers must approve this step\n - `\"system\"` - System automatically takes action (use with `system_action`)\n - Example: `\"any\"`\n\n- **`system_action`** (string or null) - The system action to take (when `approvers_required` is `\"system\"`)\n - `\"approve\"` - Automatically approve\n - `\"reject\"` - Automatically reject\n - `null` - No system action\n - Example: `null`\n\n- **`skip_if_no_approvers`** (boolean, default: `false`) - Whether to skip this step if no approvers are found\n - Example: `false`\n\n- **`selection_rules`** (array) - Selection rules that define when this step applies\n - Uses the same format as flow selection rules (see [Selection Rules](#selection-rules) section)\n - Example: `[]` (empty array means step always applies)\n\n- **`approver_selection_rules`** (array) - Rules that define who should approve at this step\n - See [Approver Selection Rules](#approver-selection-rules) section below\n\n- **`reminder_notifications`** (array) - Reminder notifications to send if the step remains pending\n - See [Reminder Notifications](#reminder-notifications) section below\n\n---\n\n## Reminder Notifications\n\nReminder notifications are scheduled emails sent when an approval step remains pending for a specified duration. They help ensure invoices don't get stuck waiting for approval.\n\n### Reminder Notification Structure\n\n```json\n{\n \"delay_hours\": 24,\n \"recipient_role\": \"manager\",\n \"recipient_user_id\": null\n}\n```\n\n### Reminder Notification Fields\n\n- **`delay_hours`** (integer, required, minimum 0) - Hours after step activation before sending the reminder\n - Use `0` to send immediately when the step becomes pending\n - Example: `24` (send after 24 hours)\n\n- **`recipient_role`** (string, required) - The type of recipient for this reminder\n - `\"user\"` - A specific user (requires `recipient_user_id`)\n - `\"manager\"` - The manager(s) of the step's approver(s) - resolved at trigger time\n - `\"managers_manager\"` - The manager's manager of the step's approver(s) - resolved at trigger time\n - Example: `\"manager\"`\n\n- **`recipient_user_id`** (string or null, UUID format) - The UUID of the user who should receive the reminder\n - Required when `recipient_role` is `\"user\"`\n - Ignored when `recipient_role` is `\"manager\"` or `\"managers_manager\"`\n - This is the user's `id` as returned by the V2 Users API\n - Example: `\"550e8400-e29b-41d4-a716-446655440000\"`\n\n### Reminder Notification Examples\n\n#### Send to Manager After 24 Hours\n\n```json\n{\n \"delay_hours\": 24,\n \"recipient_role\": \"manager\"\n}\n```\n\n**Behavior:** 24 hours after the step becomes pending, an email will be sent to the manager(s) of the step's approver(s).\n\n#### Send to Specific User Immediately\n\n```json\n{\n \"delay_hours\": 0,\n \"recipient_role\": \"user\",\n \"recipient_user_id\": \"550e8400-e29b-41d4-a716-446655440000\"\n}\n```\n\n**Behavior:** Immediately when the step becomes pending, an email will be sent to the specified user.\n\n#### Escalation Chain with Multiple Reminders\n\n```json\n{\n \"reminder_notifications\": [\n {\n \"delay_hours\": 24,\n \"recipient_role\": \"manager\"\n },\n {\n \"delay_hours\": 48,\n \"recipient_role\": \"managers_manager\"\n }\n ]\n}\n```\n\n**Behavior:**\n1. After 24 hours, the manager(s) of the approver(s) receive a reminder\n2. After 48 hours, the manager's manager receives a reminder\n\n### How Reminder Notifications Work\n\n1. **Scheduling:** When an approval step becomes active (status: pending), reminder jobs are scheduled based on the configured notifications\n2. **Trigger Time Resolution:** For `\"manager\"` and `\"managers_manager\"` recipient roles, the actual recipients are resolved at the time the reminder is triggered, not when configured\n3. **Cancellation:** When a step is approved, rejected, or skipped, any pending reminder jobs are automatically cancelled\n4. **Multiple Reminders:** You can configure multiple reminders per step with different delays and recipients\n\n### Use Cases\n\n1. **Escalation:** Send to manager after 24 hours, then manager's manager after 48 hours\n2. **Immediate Notification:** Use `delay_hours: 0` to notify someone immediately when approval is needed\n3. **Daily Reminders:** Configure multiple reminders at 24, 48, and 72 hours for persistent follow-up\n\n---\n\n## Approver Selection Rules\n\nApprover selection rules determine who should approve at a particular step. They use the `InvoiceApprovalFlowApproverSelectionRuleInputV2` schema.\n\nApprover selection rules work in conjunction with the `approvers_required` field to determine how many approvers from the selected group must approve:\n- When `approvers_required` is `\"any\"`, any one approver matching the rules can approve\n- When `approvers_required` is `\"all\"`, all approvers matching the rules must approve\n- When `approvers_required` is `\"system\"`, the system automatically takes action (no approvers needed)\n\n### Approver Rule Structure\n\n```json\n{\n \"type\": \"ROLE\",\n \"values\": [\n {\n \"value\": \"Finance Manager\",\n \"value_name\": \"Finance Manager\"\n },\n {\n \"value\": \"Controller\",\n \"value_name\": \"Controller\"\n }\n ]\n}\n```\n\n### Approver Rule Fields\n\n- **`type`** (string, required, max 255 chars) - The type of approver selection rule\n - **`\"ROLE\"`** and **`\"GROUP\"`**: These are specific types for organizations using certain accounting integrations. These types are only available when your integration supports roles and groups from the accounting system.\n - **`\"USER\"`**: Selects specific individual users by their legacy ID\n - **User metadata types**: You can also use user metadata types (see `UserMetadataEntryV2`). These are custom metadata fields configured for users in your system, allowing you to select approvers based on custom attributes.\n - **Note:** Available types depend on your integration type. For more details on which types are available for your specific integration, please contact the implementation support team.\n - Example: `\"ROLE\"` (for accounting integrations), or a user metadata type like `\"department\"` (if configured)\n\n- **`values`** (array of objects, required) - The values to match for this approver type\n - Each value object has two required fields:\n - **`value`** (string, required, max 255 chars) - The actual value used for matching\n - **`value_name`** (string, required, max 255 chars) - The display name shown in the UI\n - For `\"ROLE\"` (accounting integration specific): \n - `value`: Role name from the accounting system (case-sensitive, must match exactly as configured)\n - `value_name`: Role display name (typically the same as `value`, but can be customized for UI)\n - For `\"GROUP\"` (accounting integration specific): \n - `value`: Group name from the accounting system (case-sensitive, must match exactly as configured)\n - `value_name`: Group display name (typically the same as `value`, but can be customized for UI)\n - For `\"USER\"`: \n - `value`: **Must be `User.legacy_id`** (the user's legacy ID, not email or username)\n - `value_name`: User display name (typically the user's name or email for UI display)\n - For **user metadata types** (see `UserMetadataEntryV2`):\n - `value`: The metadata value (format depends on the metadata type)\n - `value_name`: The display name for the metadata value (typically the same as `value`, but can be customized for UI)\n\n### How Approver Selection Works\n\n1. **Rule Evaluation:** The system evaluates all approver selection rules in the `approver_selection_rules` array\n2. **User Matching:** Users are matched based on their assigned roles, group memberships, or user identifiers\n3. **Approval Requirement:** The `approvers_required` field determines how many of the matched approvers must approve:\n - `\"any\"`: One approval from any matched approver is sufficient\n - `\"all\"`: All matched approvers must approve\n - `\"system\"`: No human approvers needed, system takes action automatically\n4. **No Approvers Found:** If `skip_if_no_approvers` is `true` and no approvers match the rules, the step is skipped. If `false`, the step will wait indefinitely for an approver.\n\n### Multiple Approver Rules\n\nWhen multiple approver selection rules are defined in the `approver_selection_rules` array, the system uses **OR logic** - users matching ANY of the rules will be eligible approvers.\n\n**Important Constraint:** The `\"USER\"` type **cannot be mixed** with other types (`\"ROLE\"`, `\"GROUP\"`, etc.) in the same step. If you use `\"USER\"`, it must be the only approver selection rule in that step. Other types (`\"ROLE\"`, `\"GROUP\"`, etc.) can be combined together.\n\n**Example with Multiple Rules:**\n```json\n{\n \"approvers_required\": \"any\",\n \"approver_selection_rules\": [\n {\n \"type\": \"ROLE\",\n \"values\": [\n {\n \"value\": \"Finance Manager\",\n \"value_name\": \"Finance Manager\"\n }\n ]\n },\n {\n \"type\": \"GROUP\",\n \"values\": [\n {\n \"value\": \"Accounting Team\",\n \"value_name\": \"Accounting Team\"\n }\n ]\n }\n ]\n}\n```\n\n**Behavior:** Any user who has the \"Finance Manager\" role OR is a member of the \"Accounting Team\" group can approve this step. Since `approvers_required` is `\"any\"`, only one approval is needed.\n\n### Approver Selection Rule Types\n\n#### 1. Role-Based Selection (`ROLE`)\n\nSelects approvers based on their assigned roles from the accounting system. **This type is only available for organizations using certain accounting integrations** that support roles.\n\n**Use Cases:**\n- Department managers for department-specific approvals\n- Finance roles for financial approvals\n- Executive roles for high-value invoice approvals\n\n**Example - Single Role:**\n```json\n{\n \"type\": \"ROLE\",\n \"values\": [\n {\n \"value\": \"Finance Manager\",\n \"value_name\": \"Finance Manager\"\n }\n ]\n}\n```\n\n**Example - Multiple Roles (OR logic within values):**\n```json\n{\n \"type\": \"ROLE\",\n \"values\": [\n {\n \"value\": \"Finance Manager\",\n \"value_name\": \"Finance Manager\"\n },\n {\n \"value\": \"Controller\",\n \"value_name\": \"Controller\"\n },\n {\n \"value\": \"CFO\",\n \"value_name\": \"CFO\"\n }\n ]\n}\n```\n\n**Behavior:** Users with any of these roles can approve. If `approvers_required` is `\"all\"`, users with all three roles would need to approve (unlikely), but typically you'd use `\"any\"` with multiple roles.\n\n**Complete Step Example:**\n```json\n{\n \"index\": 0,\n \"approvers_required\": \"any\",\n \"skip_if_no_approvers\": false,\n \"selection_rules\": [],\n \"approver_selection_rules\": [\n {\n \"type\": \"ROLE\",\n \"values\": [\n {\n \"value\": \"Finance Manager\",\n \"value_name\": \"Finance Manager\"\n }\n ]\n }\n ]\n}\n```\n\n#### 2. Group-Based Selection (`GROUP`)\n\nSelects approvers based on their group memberships from the accounting system. **This type is only available for organizations using certain accounting integrations** that support groups. Useful when you want to route approvals to specific teams or departments.\n\n**Use Cases:**\n- Team-based approvals (e.g., \"Accounting Team\", \"Procurement Team\")\n- Department-wide approvals\n- Cross-functional approval groups\n\n**Example - Single Group:**\n```json\n{\n \"type\": \"GROUP\",\n \"values\": [\n {\n \"value\": \"Accounting Team\",\n \"value_name\": \"Accounting Team\"\n }\n ]\n}\n```\n\n**Example - Multiple Groups:**\n```json\n{\n \"type\": \"GROUP\",\n \"values\": [\n {\n \"value\": \"Finance Department\",\n \"value_name\": \"Finance Department\"\n },\n {\n \"value\": \"Accounting Team\",\n \"value_name\": \"Accounting Team\"\n }\n ]\n}\n```\n\n**Behavior:** Any user who is a member of any of these groups can approve.\n\n**Complete Step Example:**\n```json\n{\n \"index\": 0,\n \"approvers_required\": \"all\",\n \"skip_if_no_approvers\": false,\n \"selection_rules\": [],\n \"approver_selection_rules\": [\n {\n
# --- truncated at 32 KB (117 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/vicai/refs/heads/main/openapi/vicai-invoice-approval-flows-api-openapi.yml