API Documentation

Integrate QuickWise into your workflow. Manage tickets, chatbots, conversations, and documents programmatically with our RESTful API.

Base URL https://your-domain/api/v1/{team_id}

Authentication

All API v1 endpoints are protected by Laravel Sanctum and scoped to a specific team. Include a valid Sanctum token in the Authorization header.

Tokens can be created from Settings > API Tokens in the application dashboard.

Header
Authorization: Bearer {your-api-token}
cURL Example
curl -X GET https://your-domain/api/v1/{team_id}/tickets \
  -H "Authorization: Bearer {your-api-token}" \
  -H "Accept: application/json"

Rate Limiting

All v1 endpoints are rate limited to 120 requests per minute per authenticated user. When the limit is exceeded, the API returns a 429 status code.

Status Codes

Code Description
200 Request successful
201 Resource created
401 Missing or invalid token
403 User is not a member of the specified team
404 Resource not found or does not belong to the team
422 Validation error
429 Rate limit exceeded

Tickets

GET /api/v1/{team}/tickets

Returns a paginated list of tickets for the team.

Query Parameters

Parameter Type Description
status string Filter by status: open in_progress waiting resolved closed
priority string Filter by priority: low medium high urgent
form_id integer Filter by ticket form ID
search string Search in subject, reference, submitter email
per_page integer Results per page (default: 20, max: 100)
page integer Page number

Response

200 Success
{
  "data": [
    {
      "id": 1,
      "public_id": "550e8400-e29b-41d4-a716-446655440000",
      "reference": "TK-000001",
      "subject": "Cannot login to dashboard",
      "description": "I get an error when trying to login...",
      "status": "open",
      "priority": "high",
      "submitter_name": "Mario Rossi",
      "submitter_email": "mario@example.com",
      "form_data": { "category": "bug" },
      "deflected": false,
      "assigned_to": { "id": 1, "name": "Admin User" },
      "form": { "id": 1, "public_id": "...", "name": "Support Form" },
      "resolved_at": null,
      "created_at": "2026-03-07T10:00:00.000000Z",
      "updated_at": "2026-03-07T10:00:00.000000Z"
    }
  ],
  "meta": { "current_page": 1, "total": 42, "per_page": 20 }
}
POST /api/v1/{team}/tickets

Creates a new ticket for the given team and form. The ticket is handled like a normal one: the submitter gets a confirmation email, the team owner gets a new-ticket email, and an in-app notification is created. Optional attachments supported via multipart/form-data with attachments[].

Request Body

Field Type Required Description
ticket_form_public_id string (UUID) Yes Public ID of the ticket form (from the form’s public_id; must belong to the team)
subject string Yes Subject (max 255)
description string Yes Description (max 5000)
submitter_name string No Submitter name (max 255)
submitter_email string Yes Submitter email
form_data object No Custom form field values
priority string No low medium high urgent (default: medium)
assigned_to integer No User ID of a team member to assign the ticket to
attachments[] file No Up to 5 files (images, PDF, Word, Excel, text, ZIP; max 10MB each). Use multipart/form-data.

Example Request

JSON
{
  "ticket_form_public_id": "550e8400-e29b-41d4-a716-446655440000",
  "subject": "API-created request",
  "description": "Details here...",
  "submitter_name": "Jane Doe",
  "submitter_email": "jane@example.com",
  "priority": "high",
  "assigned_to": 2
}

Response

201 Created — same structure as Show Ticket

Returns 404 if ticket_form_public_id does not exist or the form does not belong to the team. Returns 422 if assigned_to is not the team owner or a team member.

GET /api/v1/{team}/tickets/{ticket_id}

Returns a single ticket with its replies and attachments.

Response

200 Success
{
  "data": {
    "id": 1,
    "public_id": "550e8400-e29b-41d4-a716-446655440000",
    "reference": "TK-000001",
    "subject": "Cannot login to dashboard",
    "description": "I get an error when trying to login...",
    "status": "open",
    "priority": "high",
    "submitter_name": "Mario Rossi",
    "submitter_email": "mario@example.com",
    "form_data": { "category": "bug" },
    "deflected": false,
    "assigned_to": { "id": 1, "name": "Admin User" },
    "form": { "id": 1, "public_id": "...", "name": "Support Form" },
    "replies": [
      {
        "id": 1,
        "content": "We are looking into this issue.",
        "is_internal_note": false,
        "is_ai_generated": false,
        "author": { "id": 1, "name": "Admin", "email": "admin@example.com" },
        "attachments": [],
        "created_at": "2026-03-07T11:00:00.000000Z"
      }
    ],
    "attachments": [
      {
        "id": 1,
        "filename": "screenshot.png",
        "mime_type": "image/png",
        "size": "245.3 KB",
        "type": "image"
      }
    ],
    "resolved_at": null,
    "created_at": "2026-03-07T10:00:00.000000Z",
    "updated_at": "2026-03-07T10:00:00.000000Z"
  }
}
PATCH /api/v1/{team}/tickets/{ticket_id}

Update status, priority, or assignment of a ticket. All fields are optional. When setting status to resolved, the resolved_at timestamp is set automatically.

Request Body

Field Type Description
status string open in_progress waiting resolved closed
priority string low medium high urgent
assigned_to int | null User ID to assign, or null to unassign

Example Request

JSON
{
  "status": "resolved",
  "priority": "low"
}
cURL
curl -X PATCH https://your-domain/api/v1/{team_id}/tickets/{ticket_id} \
  -H "Authorization: Bearer {your-api-token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"status": "resolved", "priority": "low"}'

Returns the updated ticket object (same structure as Show Ticket).

POST /api/v1/{team}/tickets/{ticket_id}/replies

Add a reply to an existing ticket.

Request Body

Field Type Required Description
content string Yes Reply content (max 10,000 characters)
is_internal_note boolean No Set to true for internal notes not visible to submitter (default: false)

Example Request

JSON
{
  "content": "We have identified the issue and deployed a fix.",
  "is_internal_note": false
}

Response

201 Created
{
  "data": {
    "id": 5,
    "content": "We have identified the issue and deployed a fix.",
    "is_internal_note": false,
    "is_ai_generated": false,
    "author": { "id": 1, "name": "Admin", "email": "admin@example.com" },
    "created_at": "2026-03-07T14:30:00.000000Z"
  }
}
GET /api/v1/{team}/tickets/{ticket_id}/attachments/{attachment_id}

Downloads a ticket or reply attachment file. Use the attachment id from the ticket payload (data.attachments or data.replies[].attachments).

Response

Returns the file stream (200) with Content-Type and Content-Disposition: attachment, or a redirect (302) to a temporary signed URL when using object storage. Returns 404 if the attachment does not belong to the ticket or the file is missing.

200 File stream | 302 Redirect to signed URL
curl -X GET "https://your-domain/api/v1/{team_id}/tickets/{ticket_id}/attachments/{attachment_id}" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Ticket Forms

GET /api/v1/{team}/ticket-forms

Returns all ticket forms for the team with ticket counts.

Response

200 Success
{
  "data": [
    {
      "id": 1,
      "public_id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Bug Report",
      "description": "Report a bug or issue",
      "color": "#6366f1",
      "fields": [
        {
          "name": "severity",
          "type": "select",
          "label": "Severity",
          "required": true,
          "options": ["low", "medium", "high"]
        }
      ],
      "ai_deflection_enabled": true,
      "success_message": "Your ticket has been submitted!",
      "is_active": true,
      "tickets_count": 42,
      "created_at": "2026-03-01T09:00:00.000000Z",
      "updated_at": "2026-03-01T09:00:00.000000Z"
    }
  ]
}
GET /api/v1/{team}/ticket-forms/{ticket_form_id}

Returns a single ticket form with its configuration and ticket count.

Response uses the same object structure as the list item above, wrapped in { "data": { ... } }.

Chatbots

GET /api/v1/{team}/chatbots

Returns all chatbots for the team with conversation counts.

Response

200 Success
{
  "data": [
    {
      "id": 1,
      "name": "Support Bot",
      "description": "Main customer support chatbot",
      "model": "gpt-4o-mini",
      "language": "it",
      "tone": "professional",
      "company_name": "Acme Corp",
      "is_active": true,
      "public_page_enabled": false,
      "conversations_count": 156,
      "created_at": "2026-03-01T09:00:00.000000Z",
      "updated_at": "2026-03-05T14:00:00.000000Z"
    }
  ]
}
GET /api/v1/{team}/chatbots/{chatbot_id}

Returns a single chatbot with conversation count.

Response uses the same object structure as the list item above, wrapped in { "data": { ... } }.

Conversations

GET /api/v1/{team}/chatbots/{chatbot_id}/conversations

Returns a paginated list of conversations for a specific chatbot.

Query Parameters

Parameter Type Description
status string Filter by status: active closed
search string Search by visitor name or email
per_page integer Results per page (default: 20, max: 100)
page integer Page number

Response

200 Success
{
  "data": [
    {
      "id": 1,
      "public_id": "550e8400-e29b-41d4-a716-446655440000",
      "visitor_id": "v_abc123",
      "visitor_name": "Mario Rossi",
      "visitor_email": "mario@example.com",
      "visitor_phone": null,
      "status": "active",
      "source_url": "https://example.com/pricing",
      "messages_count": 8,
      "created_at": "2026-03-07T09:00:00.000000Z",
      "updated_at": "2026-03-07T09:15:00.000000Z"
    }
  ],
  "meta": { "current_page": 1, "total": 156, "per_page": 20 }
}
GET /api/v1/{team}/chatbots/{chatbot_id}/conversations/{conversation_public_id}

Returns a single conversation with the complete message history.

Note: The conversation is identified by its public_id (UUID), not by the numeric id.

Response

200 Success
{
  "data": {
    "id": 1,
    "public_id": "550e8400-e29b-41d4-a716-446655440000",
    "visitor_id": "v_abc123",
    "visitor_name": "Mario Rossi",
    "visitor_email": "mario@example.com",
    "visitor_phone": null,
    "status": "active",
    "source_url": "https://example.com/pricing",
    "messages": [
      {
        "id": 1,
        "role": "user",
        "content": "What are your pricing plans?",
        "sources": null,
        "confidence": null,
        "token_count": 12,
        "created_at": "2026-03-07T09:00:00.000000Z"
      },
      {
        "id": 2,
        "role": "assistant",
        "content": "We offer three plans: Starter, Pro, and Ultimate...",
        "sources": [
          { "document": "pricing.pdf", "chunk": "Our pricing starts at..." }
        ],
        "confidence": 0.92,
        "token_count": 145,
        "created_at": "2026-03-07T09:00:02.000000Z"
      }
    ],
    "created_at": "2026-03-07T09:00:00.000000Z",
    "updated_at": "2026-03-07T09:15:00.000000Z"
  }
}

Doc Hubs

GET /api/v1/{team}/doc-hubs

Returns all documentation hubs for the team.

Response

200 Success
{
  "data": [
    {
      "id": 1,
      "name": "Help Center",
      "slug": "help-center",
      "description": "Main documentation portal",
      "is_published": true,
      "primary_color": "#6366f1",
      "hide_branding": false,
      "created_at": "2026-03-01T09:00:00.000000Z",
      "updated_at": "2026-03-05T14:00:00.000000Z"
    }
  ]
}
GET /api/v1/{team}/doc-hubs/{doc_hub_slug}

Returns a single doc hub with its categories.

Note: The doc hub is identified by its slug, not by the numeric ID.

Response

200 Success
{
  "data": {
    "id": 1,
    "name": "Help Center",
    "slug": "help-center",
    "description": "Main documentation portal",
    "is_published": true,
    "primary_color": "#6366f1",
    "hide_branding": false,
    "categories": [
      {
        "id": 1,
        "name": "Getting Started",
        "slug": "getting-started",
        "description": "Learn the basics",
        "icon": "book",
        "sort_order": 1,
        "articles_count": 5
      },
      {
        "id": 2,
        "name": "Advanced",
        "slug": "advanced",
        "description": "Advanced topics",
        "icon": "cog",
        "sort_order": 2,
        "articles_count": 12
      }
    ],
    "created_at": "2026-03-01T09:00:00.000000Z",
    "updated_at": "2026-03-05T14:00:00.000000Z"
  }
}
GET /api/v1/{team}/doc-hubs/{doc_hub_slug}/categories/{category_slug}/articles

Returns all articles within a specific category.

Note: Both doc hub and category are identified by their slug.

Response

200 Success
{
  "data": [
    {
      "id": 1,
      "title": "Quick Start Guide",
      "slug": "quick-start-guide",
      "content": "<p>Welcome to the platform...</p>",
      "excerpt": "Get started in 5 minutes",
      "is_published": true,
      "sort_order": 1,
      "meta_title": "Quick Start",
      "meta_description": "Learn how to get started",
      "created_at": "2026-03-01T09:00:00.000000Z",
      "updated_at": "2026-03-05T14:00:00.000000Z"
    }
  ]
}
GET /api/v1/{team}/doc-hubs/{doc_hub_slug}/articles/{article_slug}

Returns a single article with its category.

Note: The article is identified by its slug.

Response

200 Success
{
  "data": {
    "id": 1,
    "title": "Quick Start Guide",
    "slug": "quick-start-guide",
    "content": "<p>Welcome to the platform...</p>",
    "excerpt": "Get started in 5 minutes",
    "is_published": true,
    "sort_order": 1,
    "meta_title": "Quick Start",
    "meta_description": "Learn how to get started",
    "category": {
      "id": 1,
      "name": "Getting Started",
      "slug": "getting-started",
      "description": "Learn the basics",
      "icon": "book",
      "sort_order": 1,
      "articles_count": 5
    },
    "created_at": "2026-03-01T09:00:00.000000Z",
    "updated_at": "2026-03-05T14:00:00.000000Z"
  }
}

Documents

GET /api/v1/{team}/documents

Returns a paginated list of documents (knowledge base files) for the team with processing status.

Query Parameters

Parameter Type Description
knowledge_base_id integer Filter by knowledge base ID
status string Filter by processing status: pending processing completed failed
search string Search by document name
per_page integer Results per page (default: 20, max: 100)
page integer Page number

Response

200 Success
{
  "data": [
    {
      "id": 1,
      "name": "product-guide.pdf",
      "type": "pdf",
      "url": null,
      "status": "completed",
      "chunk_count": 24,
      "token_count": 8500,
      "file_size": 1048576,
      "mime_type": "application/pdf",
      "knowledge_base": { "id": 1, "name": "Product Documentation" },
      "created_at": "2026-03-01T09:00:00.000000Z",
      "updated_at": "2026-03-01T09:05:00.000000Z"
    }
  ],
  "meta": { "current_page": 1, "total": 15, "per_page": 20 }
}

The error_message field is only included when status is failed.

GET /api/v1/{team}/documents/{document_id}

Returns a single document with its processing status and knowledge base info.

Response uses the same object structure as the list item above, wrapped in { "data": { ... } }.

Utilities

GET /api/v1/{team}/test

A simple endpoint to verify that Sanctum authentication and team authorization are working correctly. Use this to test your API token before making other requests.

Example

cURL
curl -X GET https://your-domain/api/v1/{team_id}/test \
  -H "Authorization: Bearer {your-api-token}" \
  -H "Accept: application/json"

Response

200 Success
{
  "message": "Sanctum authentication is working correctly.",
  "team": { "id": 1, "name": "My Team" },
  "user": { "id": 1, "name": "Admin", "email": "admin@example.com" }
}

Ready to integrate?

Create your API token from the dashboard and start building integrations in minutes.

Get Started