Cloee Docs
Paymenter ExtensionsAI Assistant

API docs

API reference for the Paymenter AIAssistant extension.

AI Assistant API

API reference for the Paymenter AIAssistant extension.

The API is intended for server-side integrations such as Discord bots, helpdesk bridges, custom dashboards, and automation services. It uses Paymenter's admin API key middleware and never exposes provider API keys.

Base URL

/api/v1/ai-assistant

Example full URL:

https://billing.example.com/api/v1/ai-assistant/status

Authentication

Send a Paymenter admin API key as a bearer token:

Authorization: Bearer <admin-api-key>
Accept: application/json
Content-Type: application/json

Permissions

Grant the narrowest permission your integration needs.

PermissionAllows
admin.ai_assistant.viewRead status, usage, chats, messages, and logs
admin.ai_assistant.createCreate chats and send prompts
admin.ai_assistant.updateUpdate, close, or reopen chats
admin.ai_assistant.deleteArchive chats

Keys with * or admin.ai_assistant.* are also accepted.

Response Format

Successful non-paginated responses use:

{
  "data": {}
}

Paginated responses also include meta:

{
  "data": [],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 25,
    "total": 0
  }
}

Errors use Paymenter/Laravel JSON responses where possible:

{
  "message": "The API key is missing the admin.ai_assistant.view permission."
}

Modes

The extension exposes two prompt modes.

ModeEndpointBehavior
PersonalizedPOST /messages or POST /chats/{chat_public_id}/messagesUses a Paymenter user, chat history, and user-scoped tools.
GeneralPOST /general/messagesAPI-only public help. No user_id, no saved chat, no private account tools. Public portal/catalog tools are allowed.

Use personalized mode for account-specific support. Use general mode for public FAQ/product/catalog bots.

Endpoints

MethodPathPermission
GET/statusadmin.ai_assistant.view
GET/logsadmin.ai_assistant.view
GET/users/{user_id}/usageadmin.ai_assistant.view
GET/users/{user_id}/chatsadmin.ai_assistant.view
POST/users/{user_id}/chatsadmin.ai_assistant.create
GET/users/{user_id}/chats/activeadmin.ai_assistant.view
POST/messagesadmin.ai_assistant.create
POST/general/messagesadmin.ai_assistant.create
GET/chats/{chat_public_id}admin.ai_assistant.view
PATCH/chats/{chat_public_id}admin.ai_assistant.update
POST/chats/{chat_public_id}/closeadmin.ai_assistant.update
POST/chats/{chat_public_id}/reopenadmin.ai_assistant.update
POST/chats/{chat_public_id}/archiveadmin.ai_assistant.delete
GET/chats/{chat_public_id}/messagesadmin.ai_assistant.view
POST/chats/{chat_public_id}/messagesadmin.ai_assistant.create

Status

Get Status

GET /api/v1/ai-assistant/status

Returns persistence table availability, enabled provider counts, request limits, and enabled feature flags.

Example response:

{
  "data": {
    "api_version": "1",
    "persistence": {
      "chats": true,
      "messages": true,
      "logs": true,
      "providers": true
    },
    "providers": {
      "total": 2,
      "enabled": 1
    },
    "limits": {
      "max_prompt_chars": 3000,
      "max_history_messages": 20,
      "max_requests_per_minute": 12,
      "monthly_request_limit": 2000
    },
    "features": {
      "ticket_creation_tool": true,
      "logging": true
    }
  }
}

Usage

Get User Usage

GET /api/v1/ai-assistant/users/{user_id}/usage

Returns monthly request usage for a Paymenter user.

Example response:

{
  "data": {
    "user_id": 42,
    "monthly_limit": 2000,
    "monthly_used": 14,
    "monthly_remaining": 1986,
    "resets_at": "2026-07-01T00:00:00+00:00"
  }
}

Chats

List User Chats

GET /api/v1/ai-assistant/users/{user_id}/chats?status=active&search=billing&per_page=25&page=1

Query parameters:

ParameterTypeNotes
statusstringOptional. active, closed, or archived.
searchstringOptional. Searches chat title and public id.
per_pageintegerOptional. 1-100, default 25.
pageintegerOptional pagination page.

Get Or Create Active Chat

GET /api/v1/ai-assistant/users/{user_id}/chats/active?create=true

Query parameters:

ParameterTypeNotes
createbooleanDefaults to true. If false, returns 404 when no active chat exists.

Create Chat

POST /api/v1/ai-assistant/users/{user_id}/chats

Request body:

{
  "title": "Billing follow-up",
  "status": "active",
  "metadata": {
    "external_thread_id": "thread_123"
  }
}

Fields:

FieldTypeNotes
titlestringOptional, max 180 characters.
statusstringOptional. active, closed, or archived. Defaults to active.
metadataobjectOptional integration metadata.

Get Chat

GET /api/v1/ai-assistant/chats/{chat_public_id}

Update Chat

PATCH /api/v1/ai-assistant/chats/{chat_public_id}

Request body:

{
  "title": "Resolved billing question",
  "status": "closed",
  "metadata": {
    "external_thread_id": "thread_123"
  }
}

Close, Reopen, Or Archive Chat

POST /api/v1/ai-assistant/chats/{chat_public_id}/close
POST /api/v1/ai-assistant/chats/{chat_public_id}/reopen
POST /api/v1/ai-assistant/chats/{chat_public_id}/archive

Messages

List Chat Messages

GET /api/v1/ai-assistant/chats/{chat_public_id}/messages?per_page=25&page=1

Query parameters:

ParameterTypeNotes
after_idintegerOptional. Return messages newer than this id.
before_idintegerOptional. Return messages older than this id.
per_pageintegerOptional. 1-100, default 25.
pageintegerOptional pagination page.

Messages are returned oldest-first inside each page.

Send Prompt To Existing Chat

POST /api/v1/ai-assistant/chats/{chat_public_id}/messages

The chat owner becomes the scoped Paymenter user. Personalized tools are scoped to that user.

Request body:

{
  "prompt": "Can you check whether I have unpaid invoices?",
  "source": "external_client",
  "external_id": "msg_123",
  "extra_prompt": "Optional extra system instructions for this request.",
  "enable_tools": true,
  "include_ticket_creation_tool": true,
  "force_first_tool_call": true,
  "max_tool_rounds": 4
}

Fields:

FieldTypeNotes
promptstringRequired. Max length follows the extension setting.
sourcestringOptional, max 80 characters. Defaults to api.
external_idstringOptional, max 120 characters.
extra_promptstringOptional, max 4000 characters. Appended to system instructions for this request.
enable_toolsbooleanOptional. Defaults to true.
include_ticket_creation_toolbooleanOptional. Defaults to the extension ticket tool setting.
force_first_tool_callbooleanOptional. Defaults to automatic detection.
max_tool_roundsintegerOptional. 0-24.

Send Prompt And Resolve Chat

POST /api/v1/ai-assistant/messages

Use this endpoint when the integration does not already know the chat public id.

Request body:

{
  "user_id": 42,
  "prompt": "Open a support ticket about my suspended service.",
  "chat_public_id": null,
  "create_chat": true,
  "new_chat": false,
  "title": "Service help",
  "metadata": {
    "external_thread_id": "thread_123"
  },
  "source": "external_client",
  "external_id": "msg_123",
  "extra_prompt": "Optional extra system instructions for this request.",
  "enable_tools": true,
  "include_ticket_creation_tool": true,
  "force_first_tool_call": false,
  "max_tool_rounds": 4
}

Additional fields:

FieldTypeNotes
user_idintegerRequired. Paymenter user id.
chat_public_idstringOptional. Existing chat to use.
create_chatbooleanOptional. Defaults to true.
new_chatbooleanOptional. If true, always creates a fresh chat.
titlestringOptional title for newly created chats.
metadataobjectOptional metadata for newly created chats.

Chat resolution order:

  1. If new_chat=true, create a fresh chat.
  2. If chat_public_id is provided, use that chat after confirming it belongs to user_id.
  3. Otherwise use the active chat for user_id.
  4. If no active chat exists and create_chat=true, create a chat.

Example success response:

{
  "data": {
    "status": "success",
    "chat": {
      "id": 12,
      "public_id": "f4dfcb61-d6e7-4a7f-8efe-4be9d11b3178",
      "user_id": 42,
      "title": "Service help",
      "status": "active",
      "messages_count": 2,
      "last_activity_at": "2026-06-13T12:00:00+00:00",
      "closed_at": null,
      "metadata": {}
    },
    "user_message": {
      "id": 1001,
      "role": "user",
      "content": "Can you check whether I have unpaid invoices?"
    },
    "assistant_message": {
      "id": 1002,
      "role": "assistant",
      "content": "You have one unpaid invoice..."
    },
    "provider": {
      "id": 1,
      "name": "Primary Provider",
      "model": "gpt-4.1-mini"
    },
    "usage": {
      "prompt_tokens": 1200,
      "completion_tokens": 180,
      "total_tokens": 1380
    },
    "tool_calls": 1
  }
}

If every provider fails, the endpoint returns HTTP 502 and still stores a user-visible assistant error message in the chat.

General Prompt API

Send General Prompt

POST /api/v1/ai-assistant/general/messages

Use this API-only endpoint for general, non-account-specific answers. It does not accept user_id, does not create or read chats, does not load history, and does not persist user/assistant messages.

General mode can use public tools only:

ToolPurpose
get_portal_infoPublic portal basics, company name, currencies, ticket departments, common links.
get_portal_page_statusPublic page availability such as cart, tickets, account, KYC detection signals.
get_portal_linksPublic portal, category, product, and checkout links.
list_catalog_categoriesPublic product categories and visible product counts.
list_catalog_productsVisible products, plans, pricing, product links, and checkout links.

Private account tools are not exposed in general mode. This includes invoices, tickets, ticket creation, account info, and purchased services.

Request body:

{
  "prompt": "Which hosting plans are available?",
  "source": "discord_bot",
  "external_id": "discord_message_123",
  "extra_prompt": "Use a short support-friendly tone."
}

Fields:

FieldTypeNotes
promptstringRequired. Max length follows the extension setting.
sourcestringOptional, max 80 characters. Defaults to api_general.
external_idstringOptional, max 120 characters.
extra_promptstringOptional, max 4000 characters. Treated as style guidance only; it cannot enable private account tools.

Example success response:

{
  "data": {
    "status": "success",
    "mode": "general",
    "assistant_message": {
      "role": "assistant",
      "content": "The available plans are Starter, Pro, and Business..."
    },
    "provider": {
      "id": 1,
      "name": "Primary Provider",
      "model": "gpt-4.1-mini"
    },
    "usage": {
      "prompt_tokens": 450,
      "completion_tokens": 90,
      "total_tokens": 540
    },
    "tool_calls": 1,
    "latency_ms": 1800
  }
}

Example failed provider response:

{
  "data": {
    "status": "failed",
    "mode": "general",
    "assistant_message": {
      "role": "assistant",
      "content": "The AI provider request failed. Please try again later."
    },
    "error": {
      "message": "The AI provider request failed. Please try again later.",
      "internal_message": null
    },
    "latency_ms": 1200
  }
}

Logs

List Logs

GET /api/v1/ai-assistant/logs?user_id=42&status=success&chat_public_id=<id>&per_page=25

Query parameters:

ParameterTypeNotes
user_idintegerOptional. Filter by Paymenter user.
provider_idintegerOptional. Filter by provider id.
statusstringOptional. Usually success or failed.
chat_public_idstringOptional. Filter by chat public id.
per_pageintegerOptional. 1-100, default 25.
pageintegerOptional pagination page.

General prompt calls are not written to ext_ai_assistant_logs because the existing log table is user-scoped. Personalized prompt calls are logged when extension logging is enabled.

Rate Limits

Personalized prompt endpoints use:

  • Per-user per-minute limit from max_requests_per_minute.
  • Monthly per-user request limit from monthly_request_limit.

General prompt endpoint uses:

  • Per-admin-key and IP per-minute limit from max_requests_per_minute.
  • No monthly user limit because no Paymenter user is attached.

Provider-level limits still apply to both modes.

Security Notes

  • Store admin API keys server-side only.
  • Use admin.ai_assistant.create for prompt-only integrations.
  • Use admin.ai_assistant.view only when the integration needs status, logs, chats, or message reads.
  • In personalized mode, every response is generated as the resolved Paymenter user. Private tools remain user-scoped.
  • Do not pass a chat public id that belongs to a different user_id; the API rejects that pairing.
  • In general mode, do not send account identifiers or private user data. The endpoint is designed for public product, plan, portal, and FAQ style answers.
  • Provider credentials are never returned by the API.
  • Use source, external_id, and metadata to map external messages or threads. Do not store secrets in these fields.

cURL Examples

General Product/Plan Question

curl -X POST "https://billing.example.com/api/v1/ai-assistant/general/messages" \
  -H "Authorization: Bearer $PAYMENTER_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Which plans are available?",
    "source": "discord_bot",
    "external_id": "msg_123"
  }'

Personalized User Prompt

curl -X POST "https://billing.example.com/api/v1/ai-assistant/messages" \
  -H "Authorization: Bearer $PAYMENTER_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": 42,
    "prompt": "Do I have any unpaid invoices?",
    "create_chat": true,
    "source": "external_client"
  }'

Read Chat Messages

curl "https://billing.example.com/api/v1/ai-assistant/chats/f4dfcb61-d6e7-4a7f-8efe-4be9d11b3178/messages" \
  -H "Authorization: Bearer $PAYMENTER_API_KEY" \
  -H "Accept: application/json"

On this page