{
  "openapi": "3.1.0",
  "info": {
    "title": "Flowcall API",
    "version": "1.0.0",
    "description": "Machine-readable contract for Flowcall's documented public Ticket, WhatsApp Template, Resource Record, and Execute Action APIs. Create an access token in the Flowcall dashboard under Settings > Integrations and send it as a Bearer token.",
    "contact": {
      "name": "Flowcall",
      "url": "https://docs.flowcall.co/developers"
    }
  },
  "servers": [
    {
      "url": "https://api.flowcall.co",
      "description": "Flowcall production API"
    }
  ],
  "externalDocs": {
    "description": "Flowcall developer documentation",
    "url": "https://docs.flowcall.co/developers"
  },
  "tags": [
    {
      "name": "Tickets",
      "description": "Create, retrieve, and export support tickets."
    },
    {
      "name": "WhatsApp Templates",
      "description": "Retrieve configured WhatsApp templates and send approved template messages."
    },
    {
      "name": "Resource Records",
      "description": "Insert or upsert structured records in a Flowcall resource."
    },
    {
      "name": "Execute Actions",
      "description": "Run execute actions configured in the Data Library."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/apis/tickets/manual": {
      "post": {
        "tags": ["Tickets"],
        "summary": "Create a manual ticket",
        "description": "Creates a support ticket from an external system. The customer must include a phone number or email address. Request-scoped dataPointOverrides can replace read-only data point values for the selected task without modifying the underlying source. This endpoint allows 5 requests per minute, 200 per hour, and 1,000 per day per access token.",
        "operationId": "createManualTicket",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManualTicketRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ticket creation accepted or completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManualTicketResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          }
        }
      }
    },
    "/apis/task-runs/tickets/list": {
      "post": {
        "tags": ["Tickets"],
        "summary": "List tickets",
        "description": "Returns a paginated ticket list with optional date, status, assignment, task, team, search, source, sentiment, category, and parent-ticket filters. The endpoint allows 200 requests per hour per access token.",
        "operationId": "listTickets",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketListRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Paginated ticket list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/apis/task-runs/tickets/export": {
      "post": {
        "tags": ["Tickets"],
        "summary": "Start a ticket CSV export",
        "description": "Queues an asynchronous CSV export for all tickets matching the supplied filters. When both startDate and endDate are supplied, the date range cannot exceed 92 days. The endpoint allows 200 requests per hour per access token.",
        "operationId": "startTicketExport",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketExportRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The ticket export job was queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketExportStartResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/apis/task-runs/tickets/export/{jobId}": {
      "get": {
        "tags": ["Tickets"],
        "summary": "Get ticket export status",
        "description": "Returns export progress and, after successful completion, a signed CSV download URL. Generated files are retained for 24 hours and each signed URL is valid for 15 minutes.",
        "operationId": "getTicketExportStatus",
        "parameters": [
          {
            "name": "jobId",
            "in": "path",
            "required": true,
            "description": "Job ID returned when the export was started.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current export status. Successful jobs include a signed download URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketExportStatusResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "description": "The export job does not exist or was requested by another user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/apis/whatsapp/template-sync": {
      "post": {
        "tags": ["WhatsApp Templates"],
        "summary": "Retrieve configured WhatsApp templates",
        "description": "Retrieves the WhatsApp message templates configured for the account identified by the access token.",
        "operationId": "syncWhatsAppTemplates",
        "responses": {
          "200": {
            "description": "Configured WhatsApp templates.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateSyncResponse"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/apis/whatsapp/template-send": {
      "post": {
        "tags": ["WhatsApp Templates"],
        "summary": "Send an approved WhatsApp template",
        "description": "Validates and queues an approved WhatsApp template message. Message delivery occurs asynchronously.",
        "operationId": "sendWhatsAppTemplate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateSendRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request validation result.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/TemplateSendSuccess"
                    },
                    {
                      "$ref": "#/components/schemas/TemplateSendFailure"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/apis/resources/records/insert": {
      "post": {
        "tags": ["Resource Records"],
        "summary": "Insert a resource record",
        "description": "Adds a new record to the specified resource. Required resource fields must be supplied, and data keys must match fields configured on the resource.",
        "operationId": "insertResourceRecord",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResourceInsertRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resource record inserted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResourceInsertResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/apis/resources/records/upsert": {
      "post": {
        "tags": ["Resource Records"],
        "summary": "Upsert a resource record",
        "description": "Finds a resource record by an exact configured field value. One match is updated; no match creates a record; multiple matches return a validation error.",
        "operationId": "upsertResourceRecord",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResourceUpsertRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resource record inserted or updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResourceUpsertResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/apis/workflow-config-library/execute-action/run": {
      "post": {
        "tags": ["Execute Actions"],
        "summary": "Run an execute action",
        "description": "Runs one Data Library execute action with a single set of inputs. Identify the action by workflowConfigLibraryId or executeActionKey. Inputs are converted using the field types configured for the action, and fixed inputs override supplied values. Only access tokens and account admins can call it. Limited to 30 requests per hour per account.",
        "operationId": "runExecuteAction",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExecuteActionRunRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Execute action ran successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExecuteActionRunSuccess"
                }
              }
            }
          },
          "400": {
            "description": "No identifier was supplied, inputs is not an object, or an input is missing or invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExecuteActionRunFailure"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationError"
          },
          "403": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "422": {
            "description": "The action ran but failed, for example because the external API returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExecuteActionRunFailure"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitError"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "XRateLimitLimit": {
        "description": "Configured request limit for the exceeded window.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "XRateLimitRemaining": {
        "description": "Requests remaining in the exceeded window. This is 0 on a 429 response.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying a rate-limited request.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Access token created in the Flowcall dashboard under Settings > Integrations."
      }
    },
    "responses": {
      "ValidationError": {
        "description": "The request is invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "AuthenticationError": {
        "description": "No valid Bearer token or authenticated app session was supplied.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "UnauthorizedError": {
        "description": "The Bearer token is missing, invalid, or not authorized for the requested account.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFoundError": {
        "description": "The requested account-owned object was not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "RateLimitError": {
        "description": "The access token has exceeded the endpoint's rate limit.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/XRateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/XRateLimitRemaining"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ServerError": {
        "description": "The request failed because of an unexpected server-side error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "description": "Structured error response. Existing endpoints may use error or message as the primary summary; clients should read both.",
        "anyOf": [
          {
            "required": ["error"]
          },
          {
            "required": ["message"]
          }
        ],
        "properties": {
          "error": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object",
                "additionalProperties": true,
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            ]
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation of the failure."
          },
          "retryAfter": {
            "type": "integer",
            "minimum": 0,
            "description": "Seconds to wait before retrying, when applicable."
          }
        },
        "additionalProperties": true
      },
      "CustomerInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Customer full name."
          },
          "phone": {
            "type": "string",
            "description": "Customer phone number. Required when email is omitted."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Customer email address. Required when phone is omitted."
          },
          "shopifyCustomerId": {
            "type": "string",
            "description": "Shopify customer ID, when applicable."
          }
        },
        "anyOf": [
          {
            "required": ["phone"]
          },
          {
            "required": ["email"]
          }
        ],
        "additionalProperties": false
      },
      "ManualTicketRequest": {
        "type": "object",
        "required": ["customer", "query"],
        "properties": {
          "customer": {
            "$ref": "#/components/schemas/CustomerInput"
          },
          "orderName": {
            "type": "string",
            "description": "Order name or order number associated with the ticket."
          },
          "subject": {
            "type": "string",
            "description": "Short summary or title for the ticket."
          },
          "query": {
            "type": "string",
            "description": "Customer question or issue description."
          },
          "payload": {
            "type": "string",
            "description": "Additional context serialized as a JSON string."
          },
          "payloadFormat": {
            "type": "string",
            "description": "Identifier for the payload structure."
          },
          "source": {
            "type": "string",
            "description": "Built-in ticket source or a manual-source label."
          },
          "manualSourceLabel": {
            "type": "string",
            "description": "Configured label when source is manual."
          },
          "currentTaskId": {
            "type": "string",
            "description": "Workflow task ID used to route the ticket. Takes precedence over taskName."
          },
          "taskName": {
            "type": "string",
            "description": "Workflow task name used to route the ticket."
          },
          "objectiveValues": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Values for normal task objectives, keyed by objective parameter. A key cannot also appear in dataPointOverrides."
          },
          "dataPointOverrides": {
            "type": "object",
            "maxProperties": 50,
            "propertyNames": {
              "minLength": 1
            },
            "additionalProperties": {
              "type": "string",
              "minLength": 1
            },
            "description": "Request-scoped values that replace read-only data points directly referenced by the selected task. Keys are matched case-insensitively. Computed objectives, execute-action objectives, unreferenced data points, and Google Sheet writes cannot be overridden. Configured possibleValues are enforced."
          },
          "relatedTicketNumber": {
            "type": "string",
            "description": "Ticket number of a related or previous ticket."
          },
          "waitForTicket": {
            "type": "boolean",
            "default": true,
            "description": "Create and return the ticket. Send false to only find or create the customer; the response then has requestId instead of ticketId."
          },
          "forceCreateTicket": {
            "type": "boolean",
            "default": false,
            "description": "Always create a new ticket. When false, an open ticket for the same customer and task is reused."
          },
          "fastResponse": {
            "type": "boolean",
            "default": false,
            "description": "Skip AI processing of subject/query and return as soon as the ticket is created."
          },
          "skipExecuteAction": {
            "type": "boolean",
            "description": "Skip configured execution actions when true. Defaults to true when dataPointOverrides is present; set false explicitly to allow actions to run with overridden inputs."
          },
          "images": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            },
            "description": "Image URLs related to the ticket."
          }
        },
        "additionalProperties": false
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": ["string", "null"]
          },
          "phone": {
            "type": ["string", "null"]
          },
          "email": {
            "type": ["string", "null"],
            "format": "email"
          }
        },
        "additionalProperties": true
      },
      "ManualTicketResponse": {
        "type": "object",
        "required": ["success", "customer"],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "customer": {
            "$ref": "#/components/schemas/Customer"
          },
          "requestId": {
            "type": "string",
            "description": "Returned instead of ticketId when waitForTicket is false; no ticket is created."
          },
          "ticketId": {
            "type": "string",
            "description": "ID of the created or reused ticket."
          },
          "existingTicket": {
            "type": "boolean",
            "description": "True when an open ticket for the same customer and task was reused."
          }
        },
        "oneOf": [
          {
            "required": ["requestId"]
          },
          {
            "required": ["ticketId"]
          }
        ],
        "additionalProperties": true
      },
      "TicketFilters": {
        "type": "object",
        "properties": {
          "sortOrder": {
            "type": "string",
            "enum": ["asc", "desc"],
            "default": "desc"
          },
          "timestampKey": {
            "type": "string",
            "enum": ["createdAt", "updatedAt", "resolvedAt", "executedAt", "assignedAt"],
            "default": "createdAt"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time"
          },
          "ignoreDateRange": {
            "type": "boolean"
          },
          "statuses": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "excludeInProgress": {
            "type": "boolean"
          },
          "agentId": {
            "type": "string"
          },
          "involvedAgentId": {
            "type": "string"
          },
          "agentInvolvement": {
            "type": "string",
            "enum": ["only_ai", "agents_involved"]
          },
          "unassigned": {
            "type": "boolean"
          },
          "createdByUserId": {
            "type": "string"
          },
          "taskIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "noTaskIds": {
            "type": "boolean"
          },
          "taskTeamIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "search": {
            "type": "string"
          },
          "phoneNumber": {
            "type": "string",
            "description": "Single value or comma-separated values."
          },
          "orderName": {
            "type": "string",
            "description": "Single value or comma-separated values."
          },
          "ticketNumber": {
            "type": "string",
            "description": "Exact ticket name or number; may contain comma-separated values."
          },
          "source": {
            "type": "string"
          },
          "manualSourceLabel": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "subcategory": {
            "type": "string"
          },
          "sentiments": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "excludeChildTickets": {
            "type": "boolean"
          },
          "parentTicketId": {
            "type": "string"
          }
        }
      },
      "TicketListRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TicketFilters"
          },
          {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "minimum": 1,
                "default": 1
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 250,
                "default": 10
              }
            }
          }
        ]
      },
      "Ticket": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "ticketNumber": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "status": {
            "type": "string"
          },
          "summary": {
            "type": ["string", "null"]
          },
          "orderName": {
            "type": ["string", "null"]
          },
          "source": {
            "type": ["string", "null"]
          },
          "manualSourceLabel": {
            "type": ["string", "null"]
          },
          "customerId": {
            "type": ["string", "null"]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        },
        "additionalProperties": true
      },
      "TicketListResponse": {
        "type": "object",
        "required": ["data", "total", "page", "limit", "totalPages"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Ticket"
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "limit": {
            "type": "integer",
            "minimum": 1
          },
          "totalPages": {
            "type": "integer",
            "minimum": 0
          }
        },
        "additionalProperties": true
      },
      "TicketExportRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TicketFilters"
          },
          {
            "type": "object",
            "properties": {
              "timezone": {
                "type": "string",
                "description": "IANA timezone name used to format local timestamps."
              },
              "locale": {
                "type": "string",
                "default": "en-US",
                "description": "Unicode locale identifier used to format local timestamps."
              },
              "timestampFormat": {
                "type": "string",
                "enum": ["display", "legacy", "iso"],
                "default": "display",
                "description": "Format used for local timestamp columns in the CSV."
              }
            }
          }
        ]
      },
      "TicketExportStartResponse": {
        "type": "object",
        "required": ["success", "jobId", "status", "total", "fileName", "statusUrl"],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "jobId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "const": "queued"
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "fileName": {
            "type": "string"
          },
          "statusUrl": {
            "type": "string",
            "description": "Relative URL to poll for progress and a download URL."
          }
        },
        "additionalProperties": false
      },
      "TicketExportJob": {
        "type": "object",
        "required": [
          "jobId",
          "status",
          "total",
          "processed",
          "fileName",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "jobId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": ["queued", "running", "succeeded", "failed"]
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "processed": {
            "type": "integer",
            "minimum": 0
          },
          "fileName": {
            "type": "string"
          },
          "fileSizeBytes": {
            "type": "integer",
            "minimum": 0
          },
          "error": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "completedAt": {
            "type": "string",
            "format": "date-time"
          },
          "availableUntil": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": true
      },
      "TicketExportStatusResponse": {
        "type": "object",
        "required": ["success", "job"],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "job": {
            "$ref": "#/components/schemas/TicketExportJob"
          },
          "downloadUrl": {
            "type": "string",
            "format": "uri"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "downloadExpired": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "WhatsAppTemplate": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string"
          },
          "language": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "$ref": "#/components/schemas/TemplateLanguage"
              }
            ]
          },
          "namespace": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "parameter_format": {
            "type": "string"
          },
          "components": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "additionalProperties": true
      },
      "TemplateLanguage": {
        "type": "object",
        "required": ["code"],
        "properties": {
          "code": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "TemplateSyncResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WhatsAppTemplate"
            }
          }
        },
        "additionalProperties": true
      },
      "TemplateSendRequest": {
        "type": "object",
        "required": ["to", "template"],
        "properties": {
          "to": {
            "type": "string",
            "description": "Recipient phone number. E.164 format is recommended."
          },
          "template": {
            "$ref": "#/components/schemas/WhatsAppTemplate"
          },
          "campaign": {
            "type": "string"
          },
          "msg_id": {
            "type": "string"
          },
          "from": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "TemplateSendSuccess": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "status": {
            "type": "string",
            "const": "success"
          }
        },
        "additionalProperties": true
      },
      "TemplateSendFailure": {
        "type": "object",
        "required": ["status", "error"],
        "properties": {
          "status": {
            "type": "string",
            "const": "failure"
          },
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      },
      "ResourceData": {
        "type": "object",
        "description": "Values keyed by fields configured on the Flowcall resource.",
        "additionalProperties": true
      },
      "ResourceRecord": {
        "type": "object",
        "required": ["id", "objectId", "data"],
        "properties": {
          "id": {
            "type": "string"
          },
          "objectId": {
            "type": "string"
          },
          "customerId": {
            "type": ["string", "null"]
          },
          "data": {
            "$ref": "#/components/schemas/ResourceData"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": true
      },
      "ResourceInsertRequest": {
        "type": "object",
        "required": ["objectId", "data"],
        "properties": {
          "objectId": {
            "type": "string",
            "description": "ID of the resource that receives the record."
          },
          "data": {
            "$ref": "#/components/schemas/ResourceData"
          }
        },
        "additionalProperties": false
      },
      "ResourceInsertResponse": {
        "type": "object",
        "required": ["success", "record", "conflicts", "conflictCount"],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "record": {
            "$ref": "#/components/schemas/ResourceRecord"
          },
          "conflicts": {
            "type": "array",
            "items": {}
          },
          "conflictCount": {
            "type": "integer",
            "minimum": 0
          }
        },
        "additionalProperties": true
      },
      "ResourceUpsertRequest": {
        "type": "object",
        "required": ["objectId", "idField", "idValue", "data"],
        "properties": {
          "objectId": {
            "type": "string",
            "description": "ID of the resource that receives the record."
          },
          "idField": {
            "type": "string",
            "description": "Configured resource field key used to find an existing record."
          },
          "idValue": {
            "description": "Exact value matched in idField. The API converts it using the configured field type."
          },
          "data": {
            "$ref": "#/components/schemas/ResourceData"
          }
        },
        "additionalProperties": false
      },
      "ResourceUpsertResponse": {
        "type": "object",
        "required": ["success", "operation", "record", "conflicts", "conflictCount"],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "operation": {
            "type": "string",
            "enum": ["inserted", "updated"]
          },
          "record": {
            "$ref": "#/components/schemas/ResourceRecord"
          },
          "conflicts": {
            "type": "array",
            "items": {}
          },
          "conflictCount": {
            "type": "integer",
            "minimum": 0
          }
        },
        "additionalProperties": true
      },
      "ExecuteActionRunRequest": {
        "type": "object",
        "properties": {
          "workflowConfigLibraryId": {
            "type": "string",
            "description": "ID of the execute action in the Data Library. Takes precedence over executeActionKey."
          },
          "executeActionKey": {
            "type": "string",
            "description": "Key of the execute action. Used when workflowConfigLibraryId is not supplied."
          },
          "inputs": {
            "type": "object",
            "description": "Input values keyed by the action's input names.",
            "additionalProperties": true
          }
        },
        "anyOf": [
          {
            "required": ["workflowConfigLibraryId"]
          },
          {
            "required": ["executeActionKey"]
          }
        ],
        "additionalProperties": false
      },
      "ExecuteActionRunSuccess": {
        "type": "object",
        "required": ["success", "workflowConfigLibraryId", "result"],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "workflowConfigLibraryId": {
            "type": "string"
          },
          "executeActionKey": {
            "type": "string"
          },
          "result": {
            "description": "Value returned by the action's output function. Its shape depends on the action."
          }
        },
        "additionalProperties": true
      },
      "ExecuteActionRunFailure": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "description": "Individual input validation errors.",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      }
    }
  }
}
