{
  "openapi": "3.1.0",
  "info": {
    "title": "Alia API",
    "version": "1.0.0",
    "description": "Read the WhatsApp conversations of your agencies and send messages as them."
  },
  "paths": {
    "/me": {
      "get": {
        "tags": ["Integration"],
        "operationId": "me.get",
        "parameters": [],
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Your integration, agencies and scopes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "The key may not do this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerForbidden"
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerNotFound"
                }
              }
            }
          },
          "500": {
            "description": "Alia failed to handle the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerInternalError"
                }
              }
            }
          }
        },
        "description": "Returns the integration your API key belongs to, the agencies it may access and its scopes. Call it first: every other path needs the `id` of one of these agencies.",
        "summary": "Get your integration and agencies"
      }
    },
    "/agencies/{agencyId}/conversations": {
      "get": {
        "tags": ["Conversations"],
        "operationId": "conversations.list",
        "parameters": [
          {
            "name": "agencyId",
            "in": "path",
            "description": "Agency ID from `GET /me`, such as `agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6"
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Conversations per page, from 1 to 100. Default 50.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`nextCursor` from the previous page. Leave it out to read the first page.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Filter by contact phone number or name, such as `Marie` or `0470`. Three or more digits match part of a phone number; three or more letters match part of a name.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of conversations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationListResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerBadRequest"
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "The key may not do this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerForbidden"
                }
              }
            }
          },
          "500": {
            "description": "Alia failed to handle the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerInternalError"
                }
              }
            }
          }
        },
        "description": "Lists the agency's WhatsApp conversations, newest last message first. Pass `nextCursor` as `cursor` to read the next page; stop when `nextCursor` is null.",
        "summary": "List conversations"
      }
    },
    "/agencies/{agencyId}/conversations/lookup": {
      "post": {
        "tags": ["Conversations"],
        "operationId": "conversations.lookup",
        "parameters": [
          {
            "name": "agencyId",
            "in": "path",
            "description": "Agency ID from `GET /me`, such as `agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6"
          }
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Conversations for the phone numbers you sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationLookupResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerBadRequest"
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "The key may not do this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerForbidden"
                }
              }
            }
          },
          "500": {
            "description": "Alia failed to handle the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerInternalError"
                }
              }
            }
          }
        },
        "description": "Returns the conversation summary for each phone number you send, up to 100, in the same order. A number with no conversation gets `conversation: null`. Use it to show WhatsApp status next to a list of contacts; read messages with List messages. It only reads, so it needs `conversations:read`.",
        "summary": "Look up conversations",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConversationLookupRequest"
              }
            }
          },
          "required": true
        }
      }
    },
    "/agencies/{agencyId}/conversations/{phone}": {
      "get": {
        "tags": ["Conversations"],
        "operationId": "conversations.get",
        "parameters": [
          {
            "name": "agencyId",
            "in": "path",
            "description": "Agency ID from `GET /me`, such as `agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6"
          },
          {
            "name": "phone",
            "in": "path",
            "description": "Contact phone number in E.164 format.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "+32470123456"
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Messages in the returned message page, from 1 to 100. Default 50.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`nextCursor` from a previous message page, to read older messages. Leave it out for the newest.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "A conversation and its newest messages.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerBadRequest"
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "The key may not do this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerForbidden"
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerNotFound"
                }
              }
            }
          },
          "500": {
            "description": "Alia failed to handle the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerInternalError"
                }
              }
            }
          }
        },
        "description": "Returns one conversation, its AI and window state, any queued text and its newest messages. Use it to check whether a send would go out now or be queued.",
        "summary": "Get a conversation"
      }
    },
    "/agencies/{agencyId}/conversations/{phone}/messages": {
      "get": {
        "tags": ["Conversations"],
        "operationId": "conversations.listMessages",
        "parameters": [
          {
            "name": "agencyId",
            "in": "path",
            "description": "Agency ID from `GET /me`, such as `agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6"
          },
          {
            "name": "phone",
            "in": "path",
            "description": "Contact phone number in E.164 format.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "+32470123456"
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Messages per page, from 1 to 100. Default 50.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`nextCursor` from the previous page. Leave it out to read the newest messages.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of messages, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessagePage"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerBadRequest"
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "The key may not do this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerForbidden"
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerNotFound"
                }
              }
            }
          },
          "500": {
            "description": "Alia failed to handle the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerInternalError"
                }
              }
            }
          }
        },
        "description": "Lists the messages in one conversation, newest first. Pass `nextCursor` as `cursor` to read older messages; stop when `hasMore` is false.",
        "summary": "List messages"
      }
    },
    "/agencies/{agencyId}/messages": {
      "post": {
        "x-scalar-ignore": true,
        "tags": ["Messages"],
        "operationId": "messages.send",
        "parameters": [
          {
            "name": "agencyId",
            "in": "path",
            "description": "Agency ID from `GET /me`, such as `agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6"
          }
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "The text was sent or queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendMessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerBadRequest"
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerUnauthorized"
                }
              }
            }
          },
          "403": {
            "description": "The key may not do this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerForbidden"
                }
              }
            }
          },
          "409": {
            "description": "The conversation changed during the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerConflict"
                }
              }
            }
          },
          "500": {
            "description": "Alia failed to handle the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerInternalError"
                }
              }
            }
          }
        },
        "description": "Sends a plain-text WhatsApp message as the agency. If the 24-hour window is closed, Alia queues the text and asks the contact for consent first. A send takes over the conversation and turns the AI off for this contact.",
        "summary": "Send a message",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMessageRequest"
              }
            }
          },
          "required": true
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Integration": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Integration id.",
            "examples": ["8f14e45f-ceea-4c6b-9a3e-2d5f1c0b7a91"]
          },
          "name": {
            "type": "string",
            "description": "Integration name.",
            "examples": ["Acme CRM"]
          }
        },
        "required": ["id", "name"],
        "additionalProperties": false,
        "description": "The integration your API key belongs to."
      },
      "Agency": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Agency ID. Use it as `agencyId` in paths. It never changes.",
            "examples": ["agy_9f2c4e1a7b3d4c5e8f60a1b2c3d4e5f6"]
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Agency name. Null when the agency has no name set.",
            "examples": ["Immo Dupont"]
          }
        },
        "required": ["id", "name"],
        "additionalProperties": false,
        "description": "An agency your key may access."
      },
      "MeResponse": {
        "type": "object",
        "properties": {
          "integration": {
            "$ref": "#/components/schemas/Integration"
          },
          "agencies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Agency"
            },
            "description": "Agencies your key may access, sorted by name."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Actions your key may take.",
            "examples": [["conversations:read", "messages:write"]]
          }
        },
        "required": ["integration", "agencies", "scopes"],
        "additionalProperties": false,
        "description": "Your integration, agencies and scopes."
      },
      "PartnerNotFound": {
        "type": "object",
        "properties": {
          "_tag": {
            "type": "string",
            "enum": ["PartnerNotFound"],
            "description": "Error type. Use it to branch in code."
          },
          "message": {
            "type": "string",
            "description": "Plain-English reason. Safe to show or log.",
            "examples": ["Conversation not found"]
          }
        },
        "required": ["_tag", "message"],
        "additionalProperties": false,
        "description": "The resource does not exist or is hidden."
      },
      "PartnerUnauthorized": {
        "type": "object",
        "properties": {
          "_tag": {
            "type": "string",
            "enum": ["PartnerUnauthorized"],
            "description": "Error type. Use it to branch in code."
          },
          "message": {
            "type": "string",
            "description": "Plain-English reason. Safe to show or log.",
            "examples": ["Missing or invalid bearer token"]
          }
        },
        "required": ["_tag", "message"],
        "additionalProperties": false,
        "description": "The bearer token is missing, wrong, revoked or expired."
      },
      "PartnerForbidden": {
        "type": "object",
        "properties": {
          "_tag": {
            "type": "string",
            "enum": ["PartnerForbidden"],
            "description": "Error type. Use it to branch in code."
          },
          "message": {
            "type": "string",
            "description": "Plain-English reason. Safe to show or log.",
            "examples": ["Agency access denied"]
          }
        },
        "required": ["_tag", "message"],
        "additionalProperties": false,
        "description": "The key is valid but may not act on this agency or take this action."
      },
      "PartnerInternalError": {
        "type": "object",
        "properties": {
          "_tag": {
            "type": "string",
            "enum": ["PartnerInternalError"],
            "description": "Error type. Use it to branch in code."
          },
          "message": {
            "type": "string",
            "description": "Plain-English reason. Safe to show or log.",
            "examples": ["Something went wrong on our side. Try again later."]
          }
        },
        "required": ["_tag", "message"],
        "additionalProperties": false,
        "description": "Alia failed to handle the request. Retry later; the message holds no internal detail."
      },
      "ConversationVisibility": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "enum": ["focus", "unlinked", "tagged", "unknown"],
            "description": "Why the agency sees this conversation. `focus`: the agency owns it. `unlinked`: no agency owns it. `tagged`: the agency sees it through an agency tag. `unknown`: none of these.",
            "examples": ["focus"]
          },
          "isShared": {
            "type": "boolean",
            "description": "True when other agencies may also see this conversation."
          },
          "isVisibleThroughAgencyTag": {
            "type": "boolean",
            "description": "True when the agency sees it through an agency tag."
          }
        },
        "required": ["reason", "isShared", "isVisibleThroughAgencyTag"],
        "additionalProperties": false,
        "description": "Why this agency can see the conversation."
      },
      "ConversationSummary": {
        "type": "object",
        "properties": {
          "phoneNumber": {
            "type": "string",
            "description": "Contact phone number in E.164 format.",
            "examples": ["+32470123456"]
          },
          "contactName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Contact name, when known.",
            "examples": ["Marie Peeters"]
          },
          "lastMessageAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Time of the last message, in either direction.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          },
          "lastMessagePreview": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start of the last message text.",
            "examples": ["Is the flat on Rue Haute still available?"]
          },
          "lastMessageDirection": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Direction of the last message: `inbound` (from the contact) or `outbound`.",
            "examples": ["inbound"]
          },
          "totalMessages": {
            "description": "Number of messages in the conversation.",
            "examples": [12],
            "type": "integer"
          },
          "failedMessages": {
            "description": "Outbound messages that failed, went undelivered or carry an error code.",
            "examples": [0],
            "type": "integer"
          },
          "activeFlows": {
            "description": "Alia flows now running for this contact.",
            "examples": [1],
            "type": "integer"
          },
          "completedFlows": {
            "description": "Alia flows this contact has finished.",
            "examples": [2],
            "type": "integer"
          },
          "latestFlowStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Status of the most recently updated flow, such as `active`, `waiting`, `completed`, `cancelled`, `failed` or `timeout`.",
            "examples": ["completed"]
          },
          "lastInboundAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Time of the last message from the contact.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          },
          "windowExpiresAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the WhatsApp 24-hour window closes: 24 hours after the last message from the contact. Null when the contact has never written. After this time a send is queued, not sent.",
            "examples": ["2026-10-01T08:41:12.000Z"]
          },
          "aiEnabled": {
            "type": "boolean",
            "description": "True when the AI may reply to this contact."
          },
          "queuedMessages": {
            "description": "Messages waiting for the contact to reopen the WhatsApp window.",
            "examples": [0],
            "type": "integer"
          },
          "isUnlinked": {
            "type": "boolean",
            "description": "True when no agency owns this conversation."
          },
          "visibility": {
            "$ref": "#/components/schemas/ConversationVisibility"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque position of this row in the list. Pass it as `cursor` to read the rows after it. Null in lookup results.",
            "examples": ["eyJsYXN0TWVzc2FnZUF0IjoiMjAyNi0wMy0xNCJ9"]
          }
        },
        "required": [
          "phoneNumber",
          "contactName",
          "lastMessageAt",
          "lastMessagePreview",
          "lastMessageDirection",
          "totalMessages",
          "failedMessages",
          "activeFlows",
          "completedFlows",
          "latestFlowStatus",
          "lastInboundAt",
          "windowExpiresAt",
          "aiEnabled",
          "queuedMessages",
          "isUnlinked",
          "visibility",
          "cursor"
        ],
        "additionalProperties": false,
        "description": "One WhatsApp conversation with a contact."
      },
      "ConversationListResponse": {
        "type": "object",
        "properties": {
          "conversations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConversationSummary"
            },
            "description": "Conversations, newest last message first."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pass as `cursor` to read the next page. Null when there are no more conversations.",
            "examples": ["eyJsYXN0TWVzc2FnZUF0IjoiMjAyNi0wMy0xNCJ9"]
          },
          "pageSize": {
            "description": "The page size used for this page.",
            "examples": [50],
            "type": "integer"
          }
        },
        "required": ["conversations", "nextCursor", "pageSize"],
        "additionalProperties": false,
        "description": "A page of conversations."
      },
      "PartnerBadRequest": {
        "type": "object",
        "properties": {
          "_tag": {
            "type": "string",
            "enum": ["PartnerBadRequest"],
            "description": "Error type. Use it to branch in code."
          },
          "message": {
            "type": "string",
            "description": "Plain-English reason. Safe to show or log.",
            "examples": [
              "Invalid query parameter \"pageSize\": expected a value between 1 and 100"
            ]
          }
        },
        "required": ["_tag", "message"],
        "additionalProperties": false,
        "description": "The request is not valid. The message names the field or rule that failed."
      },
      "ConversationLookupRequest": {
        "type": "object",
        "properties": {
          "phoneNumbers": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Contact phone number in E.164 format.",
              "examples": ["+32470123456"],
              "allOf": [
                {
                  "minLength": 1
                },
                {
                  "maxLength": 32
                }
              ]
            },
            "description": "Phone numbers to look up, from 1 to 100.",
            "examples": [["+32470123456", "+32471987654"]],
            "allOf": [
              {
                "minItems": 1
              },
              {
                "maxItems": 100
              }
            ]
          }
        },
        "required": ["phoneNumbers"],
        "additionalProperties": false,
        "description": "The contacts whose conversations you want."
      },
      "ConversationLookupResult": {
        "type": "object",
        "properties": {
          "phoneNumber": {
            "type": "string",
            "description": "The phone number exactly as you sent it.",
            "examples": ["+32470123456"]
          },
          "conversation": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ConversationSummary"
              },
              {
                "type": "null"
              }
            ],
            "description": "The conversation with this contact. Null when there is none."
          }
        },
        "required": ["phoneNumber", "conversation"],
        "additionalProperties": false,
        "description": "The conversation for one phone number you sent."
      },
      "ConversationLookupResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConversationLookupResult"
            },
            "description": "One result per phone number, in the order you sent them."
          }
        },
        "required": ["results"],
        "additionalProperties": false,
        "description": "Conversations for the phone numbers you sent.",
        "examples": [
          {
            "results": [
              {
                "phoneNumber": "+32470123456",
                "conversation": {
                  "phoneNumber": "+32470123456",
                  "contactName": "Marie Peeters",
                  "lastMessageAt": "2026-09-30T08:41:12.000Z",
                  "lastMessagePreview": "Is the flat on Rue Haute still available?",
                  "lastMessageDirection": "inbound",
                  "totalMessages": 12,
                  "failedMessages": 0,
                  "activeFlows": 1,
                  "completedFlows": 2,
                  "latestFlowStatus": "completed",
                  "lastInboundAt": "2026-09-30T08:41:12.000Z",
                  "windowExpiresAt": "2026-10-01T08:41:12.000Z",
                  "aiEnabled": true,
                  "queuedMessages": 0,
                  "isUnlinked": false,
                  "visibility": {
                    "reason": "focus",
                    "isShared": false,
                    "isVisibleThroughAgencyTag": false
                  },
                  "cursor": null
                }
              },
              {
                "phoneNumber": "+32471987654",
                "conversation": null
              }
            ]
          }
        ]
      },
      "QueuedMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Queue entry id.",
            "examples": ["3f6c1a52-8d4e-4b7a-9c21-5e0f8a7b6d13"]
          },
          "body": {
            "type": "string",
            "description": "Text Alia will send once the contact reopens the window."
          },
          "attachmentUploadId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Upload id of an attached file, or null. API sends never attach files."
          },
          "attachmentFileName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Name of the attached file."
          },
          "attachmentMimeType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "MIME type of the attached file."
          },
          "attachmentFileSize": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Size of the attached file in bytes."
          },
          "status": {
            "type": "string",
            "description": "Queue status. Always `queued` here.",
            "examples": ["queued"]
          },
          "createdAt": {
            "type": "string",
            "description": "When Alia queued the text.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          },
          "updatedAt": {
            "type": "string",
            "description": "When the queued text last changed.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          }
        },
        "required": [
          "id",
          "body",
          "attachmentUploadId",
          "attachmentFileName",
          "attachmentMimeType",
          "attachmentFileSize",
          "status",
          "createdAt",
          "updatedAt"
        ],
        "additionalProperties": false,
        "description": "A text waiting for the contact to reopen the WhatsApp window. Alia sends it only after the contact accepts the consent message."
      },
      "AiSettings": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "True when the AI may reply to this contact."
          },
          "disabledReason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Why the AI is off: `manual_send` (a person sent a message) or `user_toggle` (agency staff turned it off). After a `manual_send`, the AI turns back on when the contact writes more than 24 hours later.",
            "examples": ["manual_send"]
          },
          "disabledAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the AI was turned off.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          }
        },
        "required": ["enabled", "disabledReason", "disabledAt"],
        "additionalProperties": false,
        "description": "AI state for this contact."
      },
      "UnapprovedTemplate": {
        "type": "object",
        "properties": {
          "templateCode": {
            "type": "string",
            "description": "Template code."
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "WhatsApp approval status.",
            "examples": ["pending"]
          }
        },
        "required": ["templateCode", "status"],
        "additionalProperties": false,
        "description": "A consent template WhatsApp has not approved."
      },
      "WindowReopenReadiness": {
        "type": "object",
        "properties": {
          "configured": {
            "type": "boolean",
            "description": "True when the agency has the consent flow turned on."
          },
          "templatesApproved": {
            "type": "boolean",
            "description": "True when every consent flow and template exists and is approved."
          },
          "eligibleForManualSend": {
            "type": "boolean",
            "description": "True when a send outside the 24-hour window can be queued: templates are approved and at least one language exists."
          },
          "availableLanguages": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Languages you may pass as `consentLanguage`.",
            "examples": [["fr", "nl"]]
          },
          "defaultLanguage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Language Alia uses by default.",
            "examples": ["fr"]
          },
          "flowCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Consent flow codes for the agency."
          },
          "missingFlowCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Consent flow codes Alia could not find."
          },
          "missingTemplates": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Consent templates the agency lacks."
          },
          "unapprovedTemplates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnapprovedTemplate"
            },
            "description": "Consent templates waiting for WhatsApp approval."
          }
        },
        "required": [
          "configured",
          "templatesApproved",
          "eligibleForManualSend",
          "availableLanguages",
          "defaultLanguage",
          "flowCodes",
          "missingFlowCodes",
          "missingTemplates",
          "unapprovedTemplates"
        ],
        "additionalProperties": false,
        "description": "Whether Alia can reach this contact after the 24-hour window closes, by queuing the text and sending a consent template first."
      },
      "ConversationDetail": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/ConversationSummary"
          },
          "queuedMessages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QueuedMessage"
            },
            "description": "The text waiting for the window to reopen, if any. Holds at most one entry."
          },
          "aiSettings": {
            "$ref": "#/components/schemas/AiSettings"
          },
          "windowReopenReadiness": {
            "$ref": "#/components/schemas/WindowReopenReadiness"
          }
        },
        "required": [
          "summary",
          "queuedMessages",
          "aiSettings",
          "windowReopenReadiness"
        ],
        "additionalProperties": false,
        "description": "A conversation with its current state."
      },
      "MessageMedia": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Media link as WhatsApp delivered it.",
            "examples": [
              "https://api.twilio.com/2010-04-01/Accounts/AC123/Messages/MM123/Media/ME123"
            ]
          },
          "index": {
            "description": "Position of the file in the message.",
            "examples": [0],
            "type": "number"
          },
          "contentType": {
            "type": "string",
            "description": "MIME type.",
            "examples": ["image/jpeg"]
          },
          "content_type": {
            "type": "string",
            "description": "MIME type (older records).",
            "examples": ["image/jpeg"]
          }
        },
        "required": ["url"],
        "additionalProperties": false,
        "description": "A file the contact sent."
      },
      "StoredMedia": {
        "type": "object",
        "properties": {
          "size": {
            "description": "File size in bytes.",
            "examples": [48213],
            "type": "number"
          },
          "stored_url": {
            "type": "string",
            "description": "Link to the copy Alia keeps.",
            "examples": ["https://storage.example.com/media/abc.jpg"]
          },
          "content_type": {
            "type": "string",
            "description": "MIME type.",
            "examples": ["image/jpeg"]
          },
          "original_url": {
            "type": "string",
            "description": "The WhatsApp media link the copy came from."
          },
          "storage_path": {
            "type": "string",
            "description": "Path of the copy in Alia storage.",
            "examples": ["agency-123/abc.jpg"]
          },
          "downloaded_at": {
            "type": "string",
            "description": "When Alia stored the copy.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          }
        },
        "required": [
          "size",
          "stored_url",
          "content_type",
          "original_url",
          "storage_path",
          "downloaded_at"
        ],
        "additionalProperties": false,
        "description": "A copy of an inbound file that Alia keeps."
      },
      "QuickReply": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Code Alia receives when the contact taps it."
          },
          "text": {
            "type": "string",
            "description": "Button label.",
            "examples": ["Yes"]
          }
        },
        "required": ["code", "text"],
        "additionalProperties": false,
        "description": "A reply button in a template."
      },
      "ListPickerItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id Alia receives when the contact picks it."
          },
          "title": {
            "type": "string",
            "description": "Item label."
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Extra line under the label."
          }
        },
        "required": ["id", "title"],
        "additionalProperties": false,
        "description": "One choice in a list picker."
      },
      "ListPicker": {
        "type": "object",
        "properties": {
          "buttonText": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Label of the button that opens the list."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListPickerItem"
            },
            "description": "Choices in the list."
          }
        },
        "required": ["items"],
        "additionalProperties": false,
        "description": "A list of choices in a template."
      },
      "CtaButton": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Button kind, such as `URL` or `PHONE_NUMBER`.",
            "examples": ["URL"]
          },
          "title": {
            "type": "string",
            "description": "Button label."
          },
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Link the button opens."
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number the button calls."
          },
          "code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Code the button copies."
          },
          "ttl_minutes": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Minutes the code stays valid."
          }
        },
        "required": ["type", "title"],
        "additionalProperties": false,
        "description": "A call-to-action button in a template."
      },
      "InteractiveContent": {
        "type": "object",
        "properties": {
          "quickReplies": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/QuickReply"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Reply buttons."
          },
          "listPicker": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ListPicker"
              },
              {
                "type": "null"
              }
            ],
            "description": "A list of choices."
          },
          "ctaButtons": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CtaButton"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Call-to-action buttons."
          }
        },
        "additionalProperties": false,
        "description": "Buttons or lists the template showed the contact."
      },
      "ReplyToMessage": {
        "type": "object",
        "properties": {
          "body": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Text of the quoted message."
          },
          "direction": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`inbound` or `outbound`.",
            "examples": ["outbound"]
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the quoted message was sent.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          },
          "templateName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Template code, when the quoted message was a template."
          },
          "hasMedia": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when the quoted message had files."
          }
        },
        "required": [
          "body",
          "direction",
          "createdAt",
          "templateName",
          "hasMedia"
        ],
        "additionalProperties": false,
        "description": "The message the contact replied to."
      },
      "Message": {
        "type": "object",
        "properties": {
          "id": {
            "description": "Alia message id.",
            "examples": [987654],
            "type": "integer"
          },
          "messageSid": {
            "type": "string",
            "description": "Twilio message SID.",
            "examples": ["SM0123456789abcdef0123456789abcdef"]
          },
          "body": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Message text. Null for a message with only files.",
            "examples": ["Hello!"]
          },
          "direction": {
            "type": "string",
            "description": "`inbound` (from the contact) or `outbound`.",
            "examples": ["inbound"]
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the message was sent or received.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          },
          "deliveredAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When WhatsApp reported delivery.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          },
          "readAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When WhatsApp reported the contact read it.",
            "examples": ["2026-09-30T08:41:12.000Z"]
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Twilio message status, such as `queued`, `sent`, `delivered`, `read`, `failed`, `undelivered` or, for inbound messages, `received`.",
            "examples": ["delivered"]
          },
          "media": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MessageMedia"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Files the contact sent. Sending files is not supported yet."
          },
          "mediaStored": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/StoredMedia"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Copies of inbound files, when the agency has media storage on."
          },
          "numMedia": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of files in the message.",
            "examples": [0]
          },
          "templateName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Template code, when Alia sent a template."
          },
          "buttonClicked": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Code of the button the contact tapped."
          },
          "profileName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "WhatsApp profile name of the contact.",
            "examples": ["Marie"]
          },
          "interactiveContent": {
            "$ref": "#/components/schemas/InteractiveContent"
          },
          "replyTo": {
            "$ref": "#/components/schemas/ReplyToMessage"
          }
        },
        "required": [
          "id",
          "messageSid",
          "body",
          "direction",
          "createdAt",
          "deliveredAt",
          "readAt",
          "status",
          "media",
          "mediaStored",
          "numMedia",
          "templateName",
          "buttonClicked",
          "profileName"
        ],
        "additionalProperties": false,
        "description": "One WhatsApp message."
      },
      "MessagePage": {
        "type": "object",
        "properties": {
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Message"
            },
            "description": "Messages, newest first."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pass as `cursor` to read older messages. Null when there are no more."
          },
          "pageSize": {
            "description": "The page size used for this page.",
            "examples": [50],
            "type": "integer"
          },
          "hasMore": {
            "type": "boolean",
            "description": "True when older messages exist."
          }
        },
        "required": ["messages", "nextCursor", "pageSize", "hasMore"],
        "additionalProperties": false,
        "description": "A page of messages, newest first."
      },
      "ConversationResponse": {
        "type": "object",
        "properties": {
          "conversation": {
            "$ref": "#/components/schemas/ConversationDetail"
          },
          "messagePage": {
            "$ref": "#/components/schemas/MessagePage"
          }
        },
        "required": ["conversation", "messagePage"],
        "additionalProperties": false,
        "description": "A conversation and its newest messages."
      },
      "SendMessageRequest": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string",
            "description": "Contact phone number in E.164 format.",
            "examples": ["+32470123456"]
          },
          "body": {
            "type": "string",
            "description": "Plain text to send. Files are not supported yet.",
            "examples": [
              "Hello Marie, is Thursday at 10:00 still good for the visit?"
            ]
          },
          "operationId": {
            "type": "string",
            "description": "Your id for this send. While the window is open, a retry with the same id does not send twice. Reusing an id with a different body fails. Without an id, every request is a new message.",
            "examples": ["crm-activity-8841"]
          },
          "subaccountId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "description": "The agency's WhatsApp sender to use. Leave it out to use the agency's default sender.",
            "examples": ["3f6c1a52-8d4e-4b7a-9c21-5e0f8a7b6d13"]
          },
          "consentLanguage": {
            "type": "string",
            "description": "Language of the consent template, such as `fr`, used only when the window is closed. Required when the agency has more than one consent language. See `windowReopenReadiness.availableLanguages`."
          }
        },
        "required": ["to", "body"],
        "additionalProperties": false,
        "description": "A plain-text WhatsApp message."
      },
      "SendMessageResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Always true on success."
          },
          "queued": {
            "type": "boolean",
            "description": "False: Alia sent the text now. True: the 24-hour window was closed, so Alia queued the text and sent the contact a consent template. Alia sends the text once the contact accepts. A new send while one is queued replaces the queued text."
          },
          "messageId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Twilio message SID of the sent text. Null when queued.",
            "examples": ["SM0123456789abcdef0123456789abcdef"]
          },
          "queueId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Queue entry id. Null when sent now.",
            "examples": ["3f6c1a52-8d4e-4b7a-9c21-5e0f8a7b6d13"]
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Twilio status right after sending, such as `queued` or `accepted`. Null when queued or on a retry.",
            "examples": ["queued"]
          },
          "windowOpen": {
            "type": "boolean",
            "description": "True when the WhatsApp 24-hour window was open."
          },
          "windowExpiresAt": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the 24-hour window closes. Null when the contact has never written.",
            "examples": ["2026-10-01T08:41:12.000Z"]
          }
        },
        "required": [
          "success",
          "queued",
          "messageId",
          "queueId",
          "status",
          "windowOpen",
          "windowExpiresAt"
        ],
        "additionalProperties": false,
        "description": "The text was sent or queued."
      },
      "PartnerConflict": {
        "type": "object",
        "properties": {
          "_tag": {
            "type": "string",
            "enum": ["PartnerConflict"],
            "description": "Error type. Use it to branch in code."
          },
          "message": {
            "type": "string",
            "description": "Plain-English reason. Safe to show or log.",
            "examples": [
              "Conversation ownership changed. Refresh and try again."
            ]
          }
        },
        "required": ["_tag", "message"],
        "additionalProperties": false,
        "description": "The conversation changed while Alia handled the request. Fetch it again, then retry."
      }
    },
    "securitySchemes": {
      "bearer": {
        "description": "Your Alia API key, sent as `Authorization: Bearer <key>`. Create keys in the Alia Console.",
        "type": "http",
        "scheme": "Bearer"
      }
    }
  },
  "security": [],
  "tags": [
    {
      "name": "Integration",
      "description": "Find out who your API key belongs to and what it may access."
    },
    {
      "name": "Conversations",
      "description": "Read WhatsApp conversations and messages for one agency."
    },
    {
      "name": "Messages",
      "description": "Send WhatsApp messages as an agency."
    }
  ],
  "servers": [
    {
      "url": "https://api.alia.cx/api/v1",
      "description": "Production"
    }
  ]
}
