{
  "openapi": "3.0.3",
  "info": {
    "title": "Tickets Please API",
    "version": "1.0.0",
    "description": "Organization-scoped API for helpdesk tickets, CRM contacts, leads, source lists, and campaigns."
  },
  "servers": [
    {
      "url": "https://tickets-please.xodelabs.com"
    }
  ],
  "tags": [
    {
      "name": "Authentication"
    },
    {
      "name": "Tickets"
    },
    {
      "name": "Leads"
    },
    {
      "name": "Contacts"
    },
    {
      "name": "Source lists"
    },
    {
      "name": "Campaigns"
    }
  ],
  "paths": {
    "/api-token-auth/": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Create or retrieve an API token",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Credentials are missing or invalid."
          }
        }
      }
    },
    "/api/v1/helpdesk/tickets/": {
      "get": {
        "tags": [
          "Tickets"
        ],
        "summary": "List tickets",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact state name."
          },
          {
            "name": "priority",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "low",
                "medium",
                "high"
              ]
            }
          },
          {
            "name": "contact_email",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "email"
            },
            "description": "Case-insensitive exact match."
          }
        ],
        "responses": {
          "200": {
            "description": "Newest-first, unpaginated ticket array.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Ticket"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Tickets"
        ],
        "summary": "Create a ticket",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Ticket",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ticket"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      }
    },
    "/api/v1/helpdesk/tickets/{ticket_uid}": {
      "parameters": [
        {
          "name": "ticket_uid",
          "in": "path",
          "required": true,
          "description": "Ticket public UUID.",
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Tickets"
        ],
        "summary": "Retrieve a ticket",
        "responses": {
          "200": {
            "description": "Ticket",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ticket"
                }
              }
            }
          },
          "404": {
            "description": "Ticket not found in this organization."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      },
      "patch": {
        "tags": [
          "Tickets"
        ],
        "summary": "Update selected ticket fields",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ticket",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ticket"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed."
          },
          "404": {
            "description": "Ticket not found in this organization."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Tickets"
        ],
        "summary": "Delete a ticket (platform superusers only)",
        "responses": {
          "204": {
            "description": "Ticket deleted."
          },
          "403": {
            "description": "Only platform superusers may delete tickets."
          },
          "404": {
            "description": "Ticket not found in this organization."
          },
          "401": {
            "description": "The token is missing or invalid."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      }
    },
    "/api/v1/leads/": {
      "get": {
        "tags": [
          "Leads"
        ],
        "summary": "List leads",
        "responses": {
          "200": {
            "description": "Unpaginated lead array.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Lead"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Leads"
        ],
        "summary": "Create a lead",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Lead created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadCreateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      }
    },
    "/api/v1/leads/{lead_uid}": {
      "parameters": [
        {
          "name": "lead_uid",
          "in": "path",
          "required": true,
          "description": "Lead public UUID.",
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Leads"
        ],
        "summary": "Retrieve a lead",
        "responses": {
          "200": {
            "description": "Lead",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Lead"
                }
              }
            }
          },
          "404": {
            "description": "Lead not found in this organization."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      },
      "patch": {
        "tags": [
          "Leads"
        ],
        "summary": "Update a lead name or phone number",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lead",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Lead"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed."
          },
          "404": {
            "description": "Lead not found in this organization."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Leads"
        ],
        "summary": "Delete a lead",
        "responses": {
          "204": {
            "description": "Lead deleted."
          },
          "404": {
            "description": "Lead not found in this organization."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      }
    },
    "/api/v1/crm/contacts/contact": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Create a CRM contact",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Contact created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      }
    },
    "/api/v1/source-lists/": {
      "post": {
        "tags": [
          "Source lists"
        ],
        "summary": "Import leads from a CSV source list",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "file"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 128
                  },
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Source list imported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UidResponse"
                }
              }
            }
          },
          "400": {
            "description": "File or CSV processing failed."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      }
    },
    "/api/v1/campaigns/": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Create a campaign",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Campaign created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UidResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      }
    },
    "/api/v1/campaign-lead-assignments/": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Assign a lead to a campaign",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignAssignment"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Lead assigned; the response body is empty."
          },
          "400": {
            "description": "Request validation failed."
          },
          "404": {
            "description": "Campaign or lead not found."
          },
          "401": {
            "description": "The token is missing or invalid."
          },
          "403": {
            "description": "The organization cannot access the service."
          }
        },
        "security": [
          {
            "TokenAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "TokenAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Use `Token YOUR_API_TOKEN`."
      }
    },
    "schemas": {
      "TokenRequest": {
        "type": "object",
        "required": [
          "username",
          "password"
        ],
        "properties": {
          "username": {
            "type": "string",
            "format": "email",
            "description": "The email address used to sign in."
          },
          "password": {
            "type": "string",
            "format": "password"
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "type": "string"
          }
        }
      },
      "TicketWrite": {
        "type": "object",
        "description": "On create, either description or message is required.",
        "properties": {
          "subject": {
            "type": "string",
            "maxLength": 256
          },
          "description": {
            "type": "string"
          },
          "message": {
            "type": "string",
            "description": "Alias for description."
          },
          "priority": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ]
          },
          "state": {
            "type": "string",
            "maxLength": 50
          },
          "company_uid": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "contact_uid": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "contact_first_name": {
            "type": "string",
            "maxLength": 128
          },
          "contact_last_name": {
            "type": "string",
            "maxLength": 128
          },
          "contact_email": {
            "type": "string",
            "format": "email"
          },
          "contact_number": {
            "type": "string",
            "maxLength": 50
          },
          "department_id": {
            "type": "integer",
            "nullable": true
          },
          "category_id": {
            "type": "integer",
            "nullable": true
          },
          "assigned_to_id": {
            "type": "integer",
            "nullable": true
          },
          "resolution_id": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "Ticket": {
        "type": "object",
        "properties": {
          "uid": {
            "type": "string",
            "format": "uuid"
          },
          "id": {
            "type": "integer"
          },
          "ticket_number": {
            "type": "integer"
          },
          "subject": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string"
          },
          "priority": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ]
          },
          "company_uid": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "contact_uid": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "contact_name": {
            "type": "string",
            "nullable": true
          },
          "contact_surname": {
            "type": "string",
            "nullable": true
          },
          "contact_email": {
            "type": "string",
            "format": "email",
            "nullable": true
          },
          "assigned_to_id": {
            "type": "integer",
            "nullable": true
          },
          "department_id": {
            "type": "integer",
            "nullable": true
          },
          "category_id": {
            "type": "integer",
            "nullable": true
          },
          "resolution_id": {
            "type": "integer",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_modified_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "closed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "LeadWrite": {
        "type": "object",
        "required": [
          "name",
          "surname",
          "phone_number"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "surname": {
            "type": "string",
            "maxLength": 100
          },
          "phone_number": {
            "type": "string",
            "maxLength": 50
          }
        }
      },
      "Lead": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LeadWrite"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer"
              },
              "uid": {
                "type": "string",
                "format": "uuid"
              },
              "created_at": {
                "type": "string",
                "format": "date-time"
              },
              "modified_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "stage": {
                "type": "string",
                "enum": [
                  "new",
                  "assigned",
                  "contacted",
                  "qualified",
                  "converted",
                  "disqualified"
                ]
              },
              "company_name": {
                "type": "string"
              },
              "street_number": {
                "type": "string",
                "nullable": true
              },
              "street_name": {
                "type": "string",
                "nullable": true
              },
              "suburb": {
                "type": "string"
              },
              "city": {
                "type": "string",
                "nullable": true
              },
              "postal_code": {
                "type": "string",
                "nullable": true
              },
              "email": {
                "type": "string",
                "format": "email",
                "nullable": true
              },
              "called_count": {
                "type": "integer"
              },
              "converted_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "status": {
                "type": "integer",
                "nullable": true
              },
              "agent": {
                "type": "integer",
                "nullable": true
              },
              "organization": {
                "type": "integer",
                "nullable": true
              },
              "converted_by": {
                "type": "integer",
                "nullable": true
              },
              "campaign": {
                "type": "integer",
                "nullable": true
              },
              "source_list": {
                "type": "integer",
                "nullable": true
              },
              "company": {
                "type": "integer",
                "nullable": true
              },
              "contact": {
                "type": "integer",
                "nullable": true
              }
            }
          }
        ]
      },
      "LeadCreateResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LeadWrite"
          },
          {
            "type": "object",
            "properties": {
              "uid": {
                "type": "string",
                "format": "uuid"
              }
            }
          }
        ]
      },
      "LeadPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "surname": {
            "type": "string",
            "maxLength": 100
          },
          "phone_number": {
            "type": "string",
            "maxLength": 50
          }
        }
      },
      "ContactWrite": {
        "type": "object",
        "required": [
          "name",
          "surname",
          "email",
          "contact_number"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 128
          },
          "surname": {
            "type": "string",
            "maxLength": 128
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "contact_number": {
            "type": "string",
            "maxLength": 50
          }
        }
      },
      "Contact": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ContactWrite"
          },
          {
            "type": "object",
            "properties": {
              "uid": {
                "type": "string",
                "format": "uuid"
              }
            }
          }
        ]
      },
      "UidResponse": {
        "type": "object",
        "required": [
          "uid"
        ],
        "properties": {
          "uid": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "CampaignWrite": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 128
          }
        }
      },
      "CampaignAssignment": {
        "type": "object",
        "required": [
          "campaign_uid",
          "lead_uid"
        ],
        "properties": {
          "campaign_uid": {
            "type": "string",
            "format": "uuid"
          },
          "lead_uid": {
            "type": "string",
            "format": "uuid"
          }
        }
      }
    }
  }
}