{
  "openapi": "3.1.0",
  "info": {
    "title": "TalaLevel REST API",
    "version": "1",
    "summary": "Leads, notes, lists, deals, texts, emails, text batches and AI caller runs for a TalaLevel workspace.",
    "description": "TalaLevel is a sales CRM with a power dialer, texting from your own numbers and an AI assistant. This API is a workspace's own way in. Every call carries a workspace key as a Bearer token; the key holds a permission level for each area (leads, lists, notes, tasks, pipeline, calls, texts, emails, calendar, reports, team). A send goes through the same checks as a send in the app, and is refused with a 422 where a person would see a warning. Docs: https://talalevel.com/docs/",
    "contact": {
      "name": "TalaLevel",
      "url": "https://talalevel.com/docs/",
      "email": "hello@talalevel.com"
    },
    "termsOfService": "https://talalevel.com/terms/"
  },
  "externalDocs": {
    "description": "Developer docs",
    "url": "https://talalevel.com/docs/"
  },
  "servers": [
    {
      "url": "https://app.talalevel.com/api/v1"
    }
  ],
  "security": [
    {
      "key": []
    }
  ],
  "tags": [
    {
      "name": "Leads"
    },
    {
      "name": "Notes"
    },
    {
      "name": "Activity",
      "description": "A lead's texts, calls and emails. Read only."
    },
    {
      "name": "Lists"
    },
    {
      "name": "Deals"
    },
    {
      "name": "Sending"
    },
    {
      "name": "Batches and waves",
      "description": "Preview first, then start with the preview's id."
    },
    {
      "name": "AI caller"
    },
    {
      "name": "Tools",
      "description": "Every MCP tool as a REST call."
    }
  ],
  "paths": {
    "/leads": {
      "get": {
        "summary": "List leads",
        "tags": [
          "Leads"
        ],
        "description": "Oldest change first. Call again while has_more is true; then keep next_cursor for the next poll. Needs leads: read.",
        "x-talalevel-permission": "leads: read",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Where to carry on from: the next_cursor of the call before."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "How many rows to answer with."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only leads with this status, in any case."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of leads.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "leads": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Lead"
                      }
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "has_more": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      },
      "post": {
        "summary": "Make a lead",
        "tags": [
          "Leads"
        ],
        "description": "A lead needs a phone or an email. A phone already on a lead is a 409 with its lead_id. Needs leads: write.",
        "x-talalevel-permission": "leads: write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The business, or the person when there is no business."
                  },
                  "contact_name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string",
                    "description": "A number in the United States or Canada (+1), in any common form."
                  },
                  "email": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "description": "One of the workspace's own statuses, in any case."
                  },
                  "city": {
                    "type": "string"
                  },
                  "state": {
                    "type": "string",
                    "description": "Two letters."
                  },
                  "fields": {
                    "type": "object",
                    "description": "Custom fields by name. A value is a string, number or boolean; null removes the field. At most 50 a call.",
                    "additionalProperties": {
                      "type": [
                        "string",
                        "number",
                        "boolean",
                        "null"
                      ]
                    }
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new lead.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lead": {
                      "$ref": "#/components/schemas/Lead"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/leads/upsert": {
      "post": {
        "summary": "Find a lead by phone or email and update it, or make one",
        "tags": [
          "Leads"
        ],
        "description": "200 with created false for a lead found, 201 with created true for a new one (which needs name). An email on two leads is a 409 with their lead_ids. Needs leads: write.",
        "x-talalevel-permission": "leads: write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "match": {
                    "type": "string",
                    "enum": [
                      "phone",
                      "email"
                    ]
                  },
                  "name": {
                    "type": "string",
                    "description": "The business, or the person when there is no business."
                  },
                  "contact_name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string",
                    "description": "A number in the United States or Canada (+1), in any common form."
                  },
                  "email": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "description": "One of the workspace's own statuses, in any case."
                  },
                  "city": {
                    "type": "string"
                  },
                  "state": {
                    "type": "string",
                    "description": "Two letters."
                  },
                  "fields": {
                    "type": "object",
                    "description": "Custom fields by name. A value is a string, number or boolean; null removes the field. At most 50 a call.",
                    "additionalProperties": {
                      "type": [
                        "string",
                        "number",
                        "boolean",
                        "null"
                      ]
                    }
                  }
                },
                "required": [
                  "match"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The lead found, updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lead": {
                      "$ref": "#/components/schemas/Lead"
                    },
                    "created": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "A new lead.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lead": {
                      "$ref": "#/components/schemas/Lead"
                    },
                    "created": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/leads/{id}": {
      "get": {
        "summary": "Get a lead",
        "tags": [
          "Leads"
        ],
        "description": "Needs leads: read.",
        "x-talalevel-permission": "leads: read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The lead's id."
          }
        ],
        "responses": {
          "200": {
            "description": "The lead.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lead": {
                      "$ref": "#/components/schemas/Lead"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      },
      "patch": {
        "summary": "Change a lead",
        "tags": [
          "Leads"
        ],
        "description": "Only what is given changes. null clears the email, the city or the state. Needs leads: write.",
        "x-talalevel-permission": "leads: write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The lead's id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "email": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "status": {
                    "type": "string"
                  },
                  "city": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "state": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "fields": {
                    "type": "object",
                    "description": "Custom fields by name. A value is a string, number or boolean; null removes the field. At most 50 a call.",
                    "additionalProperties": {
                      "type": [
                        "string",
                        "number",
                        "boolean",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The lead as it is now.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lead": {
                      "$ref": "#/components/schemas/Lead"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/leads/{id}/notes": {
      "get": {
        "summary": "List a lead's notes",
        "tags": [
          "Notes"
        ],
        "description": "Newest first. Needs notes: read.",
        "x-talalevel-permission": "notes: read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The lead's id."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Where to carry on from: the next_cursor of the call before."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "How many rows to answer with."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of notes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "notes": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Note"
                      }
                    },
                    "next_cursor": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "has_more": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      },
      "post": {
        "summary": "Add a note",
        "tags": [
          "Notes"
        ],
        "description": "Needs notes: write.",
        "x-talalevel-permission": "notes: write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The lead's id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "maxLength": 10000
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The note.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "note": {
                      "$ref": "#/components/schemas/Note"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/leads/{id}/texts": {
      "get": {
        "summary": "List a lead's texts",
        "tags": [
          "Activity"
        ],
        "description": "Newest first. Needs texts: read.",
        "x-talalevel-permission": "texts: read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The lead's id."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Where to carry on from: the next_cursor of the call before."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "How many rows to answer with."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of texts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "texts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Text"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/leads/{id}/calls": {
      "get": {
        "summary": "List a lead's calls",
        "tags": [
          "Activity"
        ],
        "description": "Newest first. Needs calls: read.",
        "x-talalevel-permission": "calls: read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The lead's id."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Where to carry on from: the next_cursor of the call before."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "How many rows to answer with."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of calls.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "calls": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Call"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/leads/{id}/emails": {
      "get": {
        "summary": "List a lead's emails",
        "tags": [
          "Activity"
        ],
        "description": "Newest first. Needs emails: read.",
        "x-talalevel-permission": "emails: read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The lead's id."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Where to carry on from: the next_cursor of the call before."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "How many rows to answer with."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of emails.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "emails": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Email"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/lists": {
      "get": {
        "summary": "List the saved lists",
        "tags": [
          "Lists"
        ],
        "description": "Needs lists: read.",
        "x-talalevel-permission": "lists: read",
        "responses": {
          "200": {
            "description": "The lists.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lists": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/List"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      },
      "post": {
        "summary": "Make a fixed list",
        "tags": [
          "Lists"
        ],
        "description": "Needs lists: write.",
        "x-talalevel-permission": "lists: write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "lead_ids": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "minItems": 1
                  }
                },
                "required": [
                  "name",
                  "lead_ids"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "list": {
                      "$ref": "#/components/schemas/List"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/lists/{id}/leads": {
      "post": {
        "summary": "Put leads on a fixed list",
        "tags": [
          "Lists"
        ],
        "description": "A filter list takes no leads by hand (409). A lead not in the workspace is a 404 with missing. Needs lists: write.",
        "x-talalevel-permission": "lists: write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The list's id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "lead_ids": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "minItems": 1
                  }
                },
                "required": [
                  "lead_ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "How many were added and the list's size.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "added": {
                      "type": "integer"
                    },
                    "size": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      },
      "delete": {
        "summary": "Take leads off a fixed list",
        "tags": [
          "Lists"
        ],
        "description": "A change that would empty the list is a 409. Needs lists: write.",
        "x-talalevel-permission": "lists: write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The list's id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "lead_ids": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "minItems": 1
                  }
                },
                "required": [
                  "lead_ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "How many were removed and which were not on it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "removed": {
                      "type": "integer"
                    },
                    "not_here": {
                      "type": "array",
                      "items": {
                        "type": "integer"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/pipelines": {
      "get": {
        "summary": "List pipelines and their stages",
        "tags": [
          "Deals"
        ],
        "description": "Needs pipeline: read.",
        "x-talalevel-permission": "pipeline: read",
        "responses": {
          "200": {
            "description": "The pipelines.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pipelines": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          },
                          "stages": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/Stage"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/deals": {
      "get": {
        "summary": "List deals",
        "tags": [
          "Deals"
        ],
        "description": "Oldest change first, paged as /leads is. Needs pipeline: read.",
        "x-talalevel-permission": "pipeline: read",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Where to carry on from: the next_cursor of the call before."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "How many rows to answer with."
          },
          {
            "name": "lead_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "One lead's deals."
          },
          {
            "name": "stage_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Deals at this stage."
          },
          {
            "name": "pipeline_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Deals on this pipeline."
          },
          {
            "name": "outcome",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "won",
                "lost"
              ]
            },
            "description": "The stage's outcome."
          },
          {
            "name": "changed_since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only deals changed since this time."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of deals.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deals": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Deal"
                      }
                    },
                    "next_cursor": {
                      "type": "string"
                    },
                    "has_more": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      },
      "post": {
        "summary": "Open a deal",
        "tags": [
          "Deals"
        ],
        "description": "On the workspace's pipeline at its first open stage unless pipeline_id or stage_id say otherwise. Needs pipeline: write.",
        "x-talalevel-permission": "pipeline: write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "lead_id": {
                    "type": "integer"
                  },
                  "pipeline_id": {
                    "type": "integer"
                  },
                  "stage_id": {
                    "type": "integer",
                    "description": "A stage in progress."
                  },
                  "name": {
                    "type": "string",
                    "description": "What is sold."
                  },
                  "value_cents": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "description": "Whole cents."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "value_period": {
                    "type": "string",
                    "enum": [
                      "one_time",
                      "monthly",
                      "annual"
                    ]
                  },
                  "close_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "The day it should close."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "owner_id": {
                    "type": "integer",
                    "description": "A person on the team."
                  },
                  "term_months": {
                    "anyOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "renews_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "The renewal day."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "lead_id"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The deal.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deal": {
                      "$ref": "#/components/schemas/Deal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/deals/{id}": {
      "get": {
        "summary": "Get a deal",
        "tags": [
          "Deals"
        ],
        "description": "Needs pipeline: read.",
        "x-talalevel-permission": "pipeline: read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The deal's id."
          }
        ],
        "responses": {
          "200": {
            "description": "The deal.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deal": {
                      "$ref": "#/components/schemas/Deal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      },
      "patch": {
        "summary": "Change a deal's facts",
        "tags": [
          "Deals"
        ],
        "description": "null clears. An empty body is a 400. A changed amount on a won deal changes its commission. Needs pipeline: write.",
        "x-talalevel-permission": "pipeline: write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The deal's id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "What is sold."
                  },
                  "value_cents": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "description": "Whole cents."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "value_period": {
                    "type": "string",
                    "enum": [
                      "one_time",
                      "monthly",
                      "annual"
                    ]
                  },
                  "close_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "The day it should close."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "owner_id": {
                    "type": "integer",
                    "description": "A person on the team."
                  },
                  "term_months": {
                    "anyOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "renews_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "The renewal day."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The deal as it is now.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deal": {
                      "$ref": "#/components/schemas/Deal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/deals/{id}/move": {
      "post": {
        "summary": "Move a deal to another stage",
        "tags": [
          "Deals"
        ],
        "description": "To a won stage it is the sale and needs an amount, here or already on the deal. To a lost stage, the stage is the reason. Back to an open stage reopens it unless its commission was marked paid (409). Needs pipeline: write.",
        "x-talalevel-permission": "pipeline: write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The deal's id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "stage_id": {
                    "type": "integer",
                    "description": "A stage of the deal's own pipeline."
                  },
                  "won_on": {
                    "type": "string",
                    "format": "date",
                    "description": "For a won stage; today where the lead is when left out."
                  },
                  "closed_by": {
                    "type": "integer",
                    "description": "A person on the team; the deal's owner when left out."
                  },
                  "rep_bps": {
                    "type": "integer",
                    "description": "The closer's share in hundredths of a percent; the workspace's share when left out."
                  },
                  "name": {
                    "type": "string",
                    "description": "What is sold."
                  },
                  "value_cents": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "description": "Whole cents."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "value_period": {
                    "type": "string",
                    "enum": [
                      "one_time",
                      "monthly",
                      "annual"
                    ]
                  },
                  "close_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "The day it should close."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "owner_id": {
                    "type": "integer",
                    "description": "A person on the team."
                  },
                  "term_months": {
                    "anyOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "renews_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "The renewal day."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "stage_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The deal as it is now.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deal": {
                      "$ref": "#/components/schemas/Deal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/deals/{id}/cancel": {
      "post": {
        "summary": "Mark a won sale cancelled, or undo that",
        "tags": [
          "Deals"
        ],
        "description": "Needs pipeline: write.",
        "x-talalevel-permission": "pipeline: write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The deal's id."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "The day the customer cancelled; null undoes it."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "on"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The deal as it is now.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deal": {
                      "$ref": "#/components/schemas/Deal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/texts": {
      "post": {
        "summary": "Send a text",
        "tags": [
          "Sending"
        ],
        "description": "Goes from the workspace's own registered numbers to one of the lead's own numbers, through the checks a text in the app goes through. Refused with a 422 for an opt-out, quiet hours, over three segments, or the key's daily limit. Needs texts: send.",
        "x-talalevel-permission": "texts: send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "lead_id": {
                    "type": "integer"
                  },
                  "conversation_id": {
                    "type": "integer",
                    "description": "One thread, to answer in it."
                  },
                  "text": {
                    "type": "string",
                    "maxLength": 1600
                  },
                  "number": {
                    "type": "string",
                    "description": "One of the lead's own numbers, when not the first."
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The text was handed to the carrier or is waiting.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "state": {
                      "type": "string"
                    },
                    "messageId": {
                      "type": "integer"
                    },
                    "conversationId": {
                      "type": "integer"
                    },
                    "to": {
                      "type": "string"
                    },
                    "from": {
                      "type": "string"
                    },
                    "segments": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/emails": {
      "post": {
        "summary": "Send an email",
        "tags": [
          "Sending"
        ],
        "description": "To one of the lead's own addresses, from the key owner's Gmail or a workspace address. Needs emails: send.",
        "x-talalevel-permission": "emails: send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "lead_id": {
                    "type": "integer"
                  },
                  "subject": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "body": {
                    "type": "string",
                    "maxLength": 20000,
                    "description": "Plain text; a blank line between paragraphs."
                  },
                  "to": {
                    "type": "string",
                    "description": "One of the lead's own addresses."
                  },
                  "from": {
                    "type": "string",
                    "description": "One of the workspace's sending addresses."
                  }
                },
                "required": [
                  "lead_id",
                  "subject",
                  "body"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The email was sent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {},
                    "from": {
                      "type": "string"
                    },
                    "to": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/templates": {
      "get": {
        "summary": "List the text templates that are on",
        "tags": [
          "Batches and waves"
        ],
        "description": "Each has its id, name and a sample of how it reads. Needs texts: read.",
        "x-talalevel-permission": "texts: read",
        "responses": {
          "200": {
            "description": "The templates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/batches/preview": {
      "post": {
        "summary": "Preview a text batch",
        "tags": [
          "Batches and waves"
        ],
        "description": "Changes nothing. Says what would go, what it costs and who is left out. previewId is null when nothing can go. Good once, for 15 minutes. Needs texts: send.",
        "x-talalevel-permission": "texts: send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "template_id": {
                    "type": "integer"
                  },
                  "list_id": {
                    "type": "integer"
                  },
                  "lead_ids": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "minItems": 1
                  },
                  "template_b_id": {
                    "type": "integer",
                    "description": "A second template, for an A/B."
                  },
                  "split": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 99,
                    "description": "With two templates, the first one's share in percent."
                  },
                  "max_rows": {
                    "type": "integer",
                    "description": "Send to at most this many."
                  }
                },
                "required": [
                  "name",
                  "template_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The preview.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "previewId": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "texts": {
                      "type": "integer"
                    },
                    "excluded": {},
                    "cost": {}
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/batches": {
      "post": {
        "summary": "Start a previewed text batch",
        "tags": [
          "Batches and waves"
        ],
        "description": "Refused as changed if anything differs from the preview. The batch waits a minute before it sends; cancelBy is the end of that minute. Needs texts: send.",
        "x-talalevel-permission": "texts: send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "preview_id": {
                    "type": "string"
                  }
                },
                "required": [
                  "preview_id"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The batch.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "batchId": {
                      "type": "integer"
                    },
                    "cancelBy": {
                      "type": "string"
                    },
                    "texts": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/batches/{id}/cancel": {
      "post": {
        "summary": "Stop a text batch",
        "tags": [
          "Batches and waves"
        ],
        "description": "Needs texts: send.",
        "x-talalevel-permission": "texts: send",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The batch's id."
          }
        ],
        "responses": {
          "200": {
            "description": "What was stopped.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/waves": {
      "get": {
        "summary": "List the text waves",
        "tags": [
          "Batches and waves"
        ],
        "description": "Needs texts: read.",
        "x-talalevel-permission": "texts: read",
        "responses": {
          "200": {
            "description": "The waves.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/waves/{id}/preview": {
      "post": {
        "summary": "Preview a wave's run",
        "tags": [
          "Batches and waves"
        ],
        "description": "Needs texts: send.",
        "x-talalevel-permission": "texts: send",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The wave's id."
          }
        ],
        "responses": {
          "200": {
            "description": "The preview and its plan.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "previewId": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/waves/run": {
      "post": {
        "summary": "Run a previewed wave now",
        "tags": [
          "Batches and waves"
        ],
        "description": "Needs texts: send.",
        "x-talalevel-permission": "texts: send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "preview_id": {
                    "type": "string"
                  }
                },
                "required": [
                  "preview_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The wave that was queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "waveId": {
                      "type": "integer"
                    },
                    "name": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/ai-runs": {
      "get": {
        "summary": "The AI caller's run now and today's calls",
        "tags": [
          "AI caller"
        ],
        "description": "Needs calls: read.",
        "x-talalevel-permission": "calls: read",
        "responses": {
          "200": {
            "description": "The run and today's figures.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      },
      "post": {
        "summary": "Start a previewed AI caller run",
        "tags": [
          "AI caller"
        ],
        "description": "One run at a time in a workspace, inside its calling hours. Needs calls: send.",
        "x-talalevel-permission": "calls: send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "preview_id": {
                    "type": "string"
                  },
                  "calls_per_day": {
                    "type": "integer"
                  }
                },
                "required": [
                  "preview_id"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The run.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runId": {
                      "type": "integer"
                    },
                    "queued": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/ai-runs/preview": {
      "post": {
        "summary": "Preview an AI caller run",
        "tags": [
          "AI caller"
        ],
        "description": "Needs calls: send.",
        "x-talalevel-permission": "calls: send",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_id": {
                    "type": "integer"
                  },
                  "lead_ids": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "minItems": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The preview.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "previewId": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "leads": {}
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/ai-runs/stop": {
      "post": {
        "summary": "Stop the AI caller",
        "tags": [
          "AI caller"
        ],
        "description": "No new calls; a call already on carries on to its end. Needs calls: send.",
        "x-talalevel-permission": "calls: send",
        "responses": {
          "200": {
            "description": "The run that was stopped.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runId": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/ai-runs/{id}/resume": {
      "post": {
        "summary": "Start a stopped run again",
        "tags": [
          "AI caller"
        ],
        "description": "Needs calls: send.",
        "x-talalevel-permission": "calls: send",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The run's id."
          }
        ],
        "responses": {
          "200": {
            "description": "The run.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runId": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/tools": {
      "get": {
        "summary": "List the tools this key may run",
        "tags": [
          "Tools"
        ],
        "description": "The MCP server's tools, filtered by the key's permissions. input is JSON Schema. Needs any permission.",
        "x-talalevel-permission": "any permission",
        "responses": {
          "200": {
            "description": "The tools.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tools": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          },
                          "area": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "level": {
                            "type": "string",
                            "enum": [
                              "read",
                              "write",
                              "send"
                            ]
                          },
                          "changes": {
                            "type": "boolean"
                          },
                          "sends": {
                            "type": "boolean"
                          },
                          "input": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    },
    "/tools/{name}": {
      "post": {
        "summary": "Run one tool by name",
        "tags": [
          "Tools"
        ],
        "description": "The body is the tool's input. A refusal is a 422 with its reason; an unknown name is a 404. Needs the tool's own area and level.",
        "x-talalevel-permission": "the tool's own area and level",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A tool's name, such as search_calls or get_lead."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's answer: text for a model to read, and data as fields where the tool has them.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "data": {}
                  },
                  "required": [
                    "text"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooMany"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "key": {
        "type": "http",
        "scheme": "bearer",
        "description": "A workspace key, tl_live_…, made by an owner in Settings → Connections → API and webhooks."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The body could not be read, has a field we do not know, or a bad value. Nothing was written.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "No valid key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key's permissions do not cover this call.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "string"
                },
                "area": {
                  "type": "string"
                },
                "needs": {
                  "type": "string",
                  "enum": [
                    "read",
                    "write",
                    "send"
                  ]
                }
              },
              "required": [
                "error"
              ]
            }
          }
        }
      },
      "NotFound": {
        "description": "No such record, or it is another workspace's.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "A duplicate, an ambiguous match, or a change the record cannot take.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "string"
                },
                "lead_id": {
                  "type": "integer"
                },
                "lead_ids": {
                  "type": "array",
                  "items": {
                    "type": "integer"
                  }
                }
              },
              "required": [
                "error"
              ]
            }
          }
        }
      },
      "Refused": {
        "description": "The send or the tool was refused, with the reason. Nothing was sent.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooMany": {
        "description": "Too many calls. Wait for the time in retry-after.",
        "headers": {
          "retry-after": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds to wait."
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "What went wrong, in a sentence."
          }
        },
        "required": [
          "error"
        ]
      },
      "Lead": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "One of the workspace's own statuses."
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "city": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "time_zone": {
            "anyOf": [
              {
                "type": "string",
                "description": "An IANA zone, such as America/Chicago."
              },
              {
                "type": "null"
              }
            ]
          },
          "contacts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "phones": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "phone": {
                        "type": "string",
                        "description": "E.164."
                      },
                      "type": {
                        "type": "string"
                      }
                    }
                  }
                },
                "emails": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "email": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The workspace's custom fields."
          },
          "owner": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "integer"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "starred": {
            "type": "boolean"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "url": {
            "type": "string",
            "description": "The lead's page in the app."
          }
        }
      },
      "Note": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "text": {
            "type": "string"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "by": {}
        }
      },
      "Text": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "direction": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "number": {
            "type": "string",
            "description": "The lead's number."
          },
          "line": {
            "type": "string",
            "description": "Your number."
          },
          "state": {
            "type": "string"
          },
          "receipt": {
            "anyOf": [
              {
                "type": "string",
                "description": "The carrier's word as it came."
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "Call": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "direction": {
            "type": "string"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "duration": {
            "type": "integer",
            "description": "Seconds."
          },
          "disposition": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "line": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "Email": {
        "type": "object",
        "properties": {
          "id": {},
          "direction": {
            "type": "string"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "from": {
            "type": "string"
          },
          "to": {},
          "cc": {},
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          }
        }
      },
      "List": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "fixed",
              "filter"
            ]
          },
          "size": {
            "anyOf": [
              {
                "type": "integer",
                "description": "null for a filter list."
              },
              {
                "type": "null"
              }
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Stage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "outcome": {
            "type": "string",
            "enum": [
              "open",
              "won",
              "lost"
            ]
          }
        }
      },
      "Deal": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "lead_id": {
            "type": "integer"
          },
          "lead_name": {
            "type": "string"
          },
          "pipeline": {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "stage": {
            "$ref": "#/components/schemas/Stage"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "value_cents": {
            "anyOf": [
              {
                "type": "integer",
                "description": "Whole cents. A monthly or yearly deal's amount is one month's or one year's."
              },
              {
                "type": "null"
              }
            ]
          },
          "value_period": {
            "type": "string",
            "enum": [
              "one_time",
              "monthly",
              "annual"
            ]
          },
          "close_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": "Expected close."
              },
              {
                "type": "null"
              }
            ]
          },
          "won_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": ""
              },
              {
                "type": "null"
              }
            ]
          },
          "lost_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": ""
              },
              {
                "type": "null"
              }
            ]
          },
          "cancelled_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": ""
              },
              {
                "type": "null"
              }
            ]
          },
          "paid_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": ""
              },
              {
                "type": "null"
              }
            ]
          },
          "term_months": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "renews_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": ""
              },
              {
                "type": "null"
              }
            ]
          },
          "owner": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "integer"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "closed_by": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "integer"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "commission": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "rep_bps": {
                    "type": "integer"
                  },
                  "rep_cents": {
                    "type": "integer"
                  },
                  "house_cents": {
                    "type": "integer"
                  },
                  "each_month": {},
                  "taken_back": {}
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "url": {
            "type": "string"
          }
        }
      }
    }
  }
}