API Documentation
Integrate QuickWise into your workflow. Manage tickets, chatbots, conversations, and documents programmatically with our RESTful API.
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.
Authorization: Bearer {your-api-token}
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 |
Pagination
List endpoints return paginated responses. Use the query parameter per_page (max 100) and page to navigate through results.
{
"data": [ ... ],
"links": {
"first": "...?page=1",
"last": "...?page=5",
"prev": null,
"next": "...?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 5,
"per_page": 20,
"to": 20,
"total": 93
}
}
Tickets
/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
{
"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 }
}
/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
{
"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
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.
/api/v1/{team}/tickets/{ticket_id}
Returns a single ticket with its replies and attachments.
Response
{
"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"
}
}
/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
{
"status": "resolved",
"priority": "low"
}
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).
/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.
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
/api/v1/{team}/ticket-forms
Returns all ticket forms for the team with ticket counts.
Response
{
"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"
}
]
}
/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
/api/v1/{team}/chatbots
Returns all chatbots for the team with conversation counts.
Response
{
"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"
}
]
}
/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
/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
{
"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 }
}
/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
{
"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
/api/v1/{team}/doc-hubs
Returns all documentation hubs for the team.
Response
{
"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"
}
]
}
/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
{
"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"
}
}
/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
{
"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"
}
]
}
/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
{
"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
/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
{
"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.
/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
/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 -X GET https://your-domain/api/v1/{team_id}/test \
-H "Authorization: Bearer {your-api-token}" \
-H "Accept: application/json"
Response
{
"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