REST API for the Plixa SaaS — WhatsApp customer service for small and medium businesses.
Plixa is API-first. Every action the customer panel takes is also available through this API, and the same contract powers the official SDKs and partner integrations.
curl https://api.plixa.app/v1/me \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Every endpoint returns the same JSON shape — the panel and SDKs rely on this consistency:
{ "data": { ... }, "meta": null, "errors": null }
Errors carry a machine-readable code so SDKs can switch on it
instead of parsing English:
{
"data": null,
"meta": null,
"errors": [{ "code": "AI_PLAN_REQUIRED", "message": "..." }]
}
Mutating endpoints (sending messages, AI previews) are rate-limited
per tenant. When a limit is hit the response is HTTP 429 with the
usual Retry-After header — back off and retry.
Plixa pushes events (new conversations, inbound messages, status
changes) to URLs you configure in the panel. Payloads are signed
with HMAC-SHA256 in the X-Plixa-Signature header so
you can verify authenticity. See the Webhooks group below.
To authenticate requests, include an Authorization header with the value "Bearer {PLIXA_API_TOKEN}".
All authenticated endpoints are marked with a requires authentication badge in the documentation below.
Generate a token by calling POST /v1/auth/login or POST /v1/auth/register. Send it as Authorization: Bearer {token}.
On-demand quick-reply suggestions inside the inbox. Calls the AI provider once and returns 3 short, distinct candidates an operator can click into the composer, edit and send. Plan-gated to the same tier that allows automated replies — and rate-limited so the "click again" pattern can't blow the token budget.
Runs the AI provider against the supplied business description and either a single message or a multi-turn conversation. Lets operators iterate on their prompt before flipping the toggle on.
Plan-gated to Professional+ (same guard as production replies) so the playground can't be used as a free LLM proxy. Additionally throttled to 10 requests per minute per tenant.
curl --request POST \
"https://api.plixa.app/v1/ai/preview" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"prompt\": \"We\'re a Brazilian bakery focused on sourdough...\",
\"message\": \"Do you ship to Vila Mariana?\",
\"history\": [
\"architecto\"
]
}"
Conversation id.
curl --request POST \
"https://api.plixa.app/v1/conversations/42/ai-suggestions" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Refuses the update with 403 + AI_PLAN_REQUIRED when the active plan doesn't include AI replies (Starter).
curl --request PUT \
"https://api.plixa.app/v1/ai-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"prompt\": \"We\'re a Brazilian bakery focused on sourdough...\",
\"enabled\": true
}"
curl --request POST \
"https://api.plixa.app/v1/ai-faqs" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"question\": \"b\",
\"answer\": \"n\"
}"
curl --request PUT \
"https://api.plixa.app/v1/ai-faqs/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"question\": \"b\",
\"answer\": \"n\"
}"
curl --request DELETE \
"https://api.plixa.app/v1/ai-faqs/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" ..] }`. Position is reassigned based on array order so the frontend can drag- and-drop without sending a full list of (id, position) pairs.
curl --request POST \
"https://api.plixa.app/v1/ai-faqs/reorder" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"ids\": [
16
]
}"
curl --request POST \
"https://api.plixa.app/v1/ai/improve-prompt" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"prompt\": \"b\"
}"
Personal access tokens used by external integrations (the panel
itself uses its own tokens minted at login under the panel name;
this controller never returns those). All token names are prefixed
with api: server-side so the listing can be filtered cleanly.
Owner-gated AND plan-gated (api_access feature).
The plain-text token is returned ONCE in this response — the panel must surface it for the operator to copy. Subsequent fetches only carry the hashed prefix.
curl --request POST \
"https://api.plixa.app/v1/api-tokens" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"CRM integration\",
\"abilities\": [
\"read\",
\"write\"
],
\"expires_in_days\": 90
}"
Token id.
curl --request DELETE \
"https://api.plixa.app/v1/api-tokens/11" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The signed-in agent's own availability for taking NEW conversations. Self-service: every member manages only their own state here. The owner's read-only view of the whole team lives on the dashboard.
Returns the authenticated user and the workspace (tenant) they belong to. Useful for the panel boot-up: a single call hydrates the session state.
curl --request GET \
--get "https://api.plixa.app/v1/me" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" {
"data": {
"user": {
"id": 1,
"tenant_id": 1,
"name": "Lucia Pereira",
"email": "[email protected]",
"role": "owner"
},
"tenant": {
"id": 1,
"name": "Lucia Studios",
"slug": "lucia-studios-ab12cd",
"country_code": "BR",
"timezone": "America/Sao_Paulo",
"locale": "pt",
"status": "active"
}
},
"meta": null,
"errors": null
}
Only fields the operator can edit on themselves — name, locale. Workspace-level settings (tenant.locale, plan, etc.) live on other endpoints.
curl --request PATCH \
"https://api.plixa.app/v1/me" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"Lucia Pereira\",
\"locale\": \"pt-BR\"
}"
curl --request PUT \
"https://api.plixa.app/v1/me/availability" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"is_available\": false
}"
curl --request POST \
"https://api.plixa.app/v1/me/availability/heartbeat" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request POST \
"https://api.plixa.app/v1/account/deletion" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"password\": \"secret-password\"
}"
curl --request DELETE \
"https://api.plixa.app/v1/account/deletion" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Sign-in for Plixa staff. Issues Sanctum tokens owned by the Admin model, resolved on subsequent requests by the AuthenticateAdmin middleware.
curl --request POST \
"https://api.plixa.app/v1/admin/auth/login" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"[email protected]\",
\"password\": \"|]|{+-\"
}"
curl --request POST \
"https://api.plixa.app/v1/admin/auth/logout" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Staff-authored marketing blasts sent from the backoffice through the verified Resend sender ([email protected]). Each send is recorded with per-recipient delivery status; every mutation lands in admin_audit_logs.
curl --request POST \
"https://api.plixa.app/v1/admin/campaigns" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request POST \
"https://api.plixa.app/v1/admin/campaigns/test" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the campaign.
curl --request DELETE \
"https://api.plixa.app/v1/admin/campaigns/architecto" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Staff CRUD over help articles. Reads bypass the published scope so drafts are editable; every mutation is recorded to admin_audit_logs.
curl --request POST \
"https://api.plixa.app/v1/admin/kb/articles" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request POST \
"https://api.plixa.app/v1/admin/kb/images" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The article.
curl --request PUT \
"https://api.plixa.app/v1/admin/kb/articles/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The article.
curl --request DELETE \
"https://api.plixa.app/v1/admin/kb/articles/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Shared staff canned responses (macros) used to speed up replies. Global to the backoffice team, not tenant-scoped.
curl --request POST \
"https://api.plixa.app/v1/admin/support/canned-replies" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request PATCH \
"https://api.plixa.app/v1/admin/support/canned-replies/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request DELETE \
"https://api.plixa.app/v1/admin/support/canned-replies/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request POST \
"https://api.plixa.app/v1/admin/support/tags" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"b\"
}"
The ID of the tag.
curl --request DELETE \
"https://api.plixa.app/v1/admin/support/tags/architecto" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ticket.
curl --request PUT \
"https://api.plixa.app/v1/admin/support/tickets/564/tags" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"tag_ids\": [
16
]
}"
The ticket.
curl --request POST \
"https://api.plixa.app/v1/admin/support/tickets/564/viewing" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ticket.
curl --request POST \
"https://api.plixa.app/v1/admin/support/tickets/564/priority" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"priority\": \"architecto\"
}"
The ticket.
curl --request POST \
"https://api.plixa.app/v1/admin/support/tickets/564/assign" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"admin_id\": 16
}"
The ticket.
curl --request POST \
"https://api.plixa.app/v1/admin/support/tickets/564/messages" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ticket.
curl --request POST \
"https://api.plixa.app/v1/admin/support/tickets/564/close" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ticket.
curl --request POST \
"https://api.plixa.app/v1/admin/support/tickets/564/reopen" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ticket.
curl --request POST \
"https://api.plixa.app/v1/admin/support/tickets/564/status" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"status\": \"architecto\"
}"
Cross-tenant oversight for staff: list every workspace with its plan, usage and status, drill into one, and run the safe lifecycle actions (suspend / reactivate). Every mutation is recorded to admin_audit_logs.
The ID of the tenant.
curl --request POST \
"https://api.plixa.app/v1/admin/tenants/16/suspend" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the tenant.
curl --request POST \
"https://api.plixa.app/v1/admin/tenants/16/reactivate" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the tenant.
curl --request POST \
"https://api.plixa.app/v1/admin/tenants/16/impersonate" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"user_id\": 16
}"
The ID of the tenant.
curl --request POST \
"https://api.plixa.app/v1/admin/tenants/16/license" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"plan_key\": \"architecto\",
\"expires_in_months\": 22
}"
The ID of the tenant.
curl --request DELETE \
"https://api.plixa.app/v1/admin/tenants/16/license" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Creates a Tenant (workspace) and the owner User in a single transaction, then issues a Sanctum bearer token for the owner.
curl --request POST \
"https://api.plixa.app/v1/auth/register" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"Lucia Pereira\",
\"email\": \"[email protected]\",
\"password\": \"super-secret-pw\",
\"company_name\": \"Lucia Studios\",
\"country_code\": \"BR\",
\"tax_id\": \"architecto\",
\"timezone\": \"America\\/Sao_Paulo\",
\"locale\": \"pt\",
\"password_confirmation\": \"super-secret-pw\"
}"
{
"data": {
"user": {
"id": 1,
"tenant_id": 1,
"name": "Lucia Pereira",
"email": "[email protected]",
"role": "owner"
},
"tenant": {
"id": 1,
"name": "Lucia Studios",
"slug": "lucia-studios-ab12cd",
"country_code": "BR",
"timezone": "America/Sao_Paulo",
"locale": "pt",
"status": "active"
},
"token": "1|abcdef0123456789"
},
"meta": null,
"errors": null
}
Returns a Sanctum bearer token on success. Email comparison is case-insensitive. Wrong email and wrong password both return the same 401 with code INVALID_CREDENTIALS — we don't leak user existence.
curl --request POST \
"https://api.plixa.app/v1/auth/login" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"[email protected]\",
\"password\": \"super-secret-pw\"
}"
{
"data": {
"user": {
"id": 1,
"tenant_id": 1,
"name": "Lucia Pereira",
"email": "[email protected]",
"role": "owner"
},
"tenant": {
"id": 1,
"name": "Lucia Studios",
"slug": "lucia-studios-ab12cd",
"country_code": "BR",
"timezone": "America/Sao_Paulo",
"locale": "pt",
"status": "active"
},
"token": "1|abcdef0123456789"
},
"meta": null,
"errors": null
}
curl --request POST \
"https://api.plixa.app/v1/auth/2fa-challenge" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"code\": \"architecto\",
\"recovery_code\": \"architecto\"
}"
Revokes the token that authenticated this request. Other tokens on the same account keep working (e.g. another device, another integration).
curl --request POST \
"https://api.plixa.app/v1/auth/logout" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" [Empty response]
Per-workspace routing rules that pick an assignee for brand-new conversations. Listing is open to every member so agents can see why they got assigned; mutation is owner-only and plan-gated.
curl --request POST \
"https://api.plixa.app/v1/auto-assignment-rules" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"priority\": 100,
\"condition_type\": \"keyword\",
\"condition_value\": \"architecto\",
\"action_type\": \"least_busy\",
\"action_user_id\": 16,
\"is_active\": false
}"
curl --request POST \
"https://api.plixa.app/v1/auto-assignment-rules/preview" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"message\": \"I want a refund\",
\"label_id\": 16
}"
curl --request PUT \
"https://api.plixa.app/v1/auto-assignment-rules/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request DELETE \
"https://api.plixa.app/v1/auto-assignment-rules/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" [Empty response]
Creates a Stripe Checkout Session for the authenticated user's workspace and returns the hosted URL the panel should redirect to. A 7-day free trial is applied to the workspace's first subscription.
curl --request POST \
"https://api.plixa.app/v1/billing/checkout" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"plan\": \"professional\",
\"interval\": \"year\"
}"
{
"data": {
"url": "https://checkout.stripe.com/c/pay/cs_test_abc123",
"plan": "professional",
"interval": "month"
},
"meta": null,
"errors": null
}
Returns a one-shot URL that lets the customer update card, change plan, see invoices, or cancel — all without us writing UI for it. The portal must be enabled in Stripe Dashboard → Settings → Billing → Customer portal (test mode and live mode are separate).
curl --request POST \
"https://api.plixa.app/v1/billing/portal" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" {
"data": {
"url": "https://billing.stripe.com/p/session/test_..."
},
"meta": null,
"errors": null
}
Mass-message campaigns. Owner-only writes, plan-gated to Professional+. Reads (list + detail + recipient breakdown) are open to every member so agents can see what's been sent and to whom.
curl --request POST \
"https://api.plixa.app/v1/broadcasts" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"Black Friday 50% off\",
\"body\": \"Hi {{first_name}}! 50% off this Friday.\",
\"source\": \"manual\",
\"recipients\": [
\"architecto\"
],
\"label_id\": 16,
\"scheduled_at\": \"2052-07-03\"
}"
The broadcast.
curl --request POST \
"https://api.plixa.app/v1/broadcasts/564/cancel" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Per-workspace open/closed schedule. When enabled, inbound messages outside the configured window trigger an auto-reply instead of an AI reply. Available on every plan — closed-hours signalling is a trust feature, not a paywalled extra.
curl --request PUT \
"https://api.plixa.app/v1/business-hours-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"enabled\": true,
\"message\": \"We\'re closed right now. We\'ll get back to you in the morning!\",
\"hours\": [
\"architecto\"
],
\"pause_sla\": false
}"
Post-resolution satisfaction survey. When a conversation is resolved the bot asks the customer to rate it 1-5; a low score optionally asks for a comment. Owner-managed, available on every plan.
curl --request PUT \
"https://api.plixa.app/v1/csat-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"enabled\": true,
\"question\": \"How was your support? Reply 1-5.\",
\"follow_up_enabled\": true,
\"follow_up_question\": \"What could we improve?\",
\"thank_you\": \"Thanks for the feedback!\",
\"visible_to_agents\": true
}"
Tenant-scoped contact directory. Reads are open to every member; writes are owner-gated because notes + field values are visible across the workspace and shouldn't be agent-mutable.
Custom field READS are always permitted (so agents see what the owner configured); only writes to definitions are plan-gated.
Idempotent per (tenant, phone): manual creation from the panel — e.g. booking an appointment for a walk-in who hasn't messaged yet — must not fail when that phone already wrote in. Open to every member because agents legitimately add customers while booking; only field-value writes and deletion stay owner-gated.
curl --request POST \
"https://api.plixa.app/v1/contacts" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_phone\": \"642559314232682282\",
\"contact_name\": \"u\"
}"
Idempotent: re-attaching is a no-op. Open to every workspace member so agents can tag customers without owner approval.
The contact.
The label.
curl --request POST \
"https://api.plixa.app/v1/contacts/564/labels/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The contact.
The label.
curl --request DELETE \
"https://api.plixa.app/v1/contacts/564/labels/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the contact.
curl --request PATCH \
"https://api.plixa.app/v1/contacts/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_name\": \"b\",
\"notes\": \"n\"
}"
Field values cascade with the contact row. Conversations stay
(their contact_id becomes null via the FK on-delete rule);
the panel still shows them by phone.
The ID of the contact.
curl --request DELETE \
"https://api.plixa.app/v1/contacts/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Body: { values: { [definition_id]: string|null } }. Empty
strings get coerced to null. Unknown definition ids are
silently skipped — keeps the panel resilient to an out-of-
date list. Owner-only, plan-gated.
The contact.
curl --request PUT \
"https://api.plixa.app/v1/contacts/564/custom-fields" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"values\": [
\"b\"
]
}"
Per-tenant schema for the custom fields operators attach to Contact rows. Listing is open to every member (the inbox renders the definitions inline next to the contact's values). Writes are owner-only AND plan-gated (Professional+).
curl --request POST \
"https://api.plixa.app/v1/custom-field-definitions" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request PUT \
"https://api.plixa.app/v1/custom-field-definitions/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Cascades: every value of this field across all contacts is wiped at the database level via the FK on-delete rule.
curl --request DELETE \
"https://api.plixa.app/v1/custom-field-definitions/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Same pattern as saved-replies reorder: ids in the desired top-to-bottom order. Ids from other tenants get silently dropped at the SQL update layer.
curl --request POST \
"https://api.plixa.app/v1/custom-field-definitions/reorder" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"ids\": [
16
]
}"
Cuts the number of round-trips for operators triaging the inbox. Supported actions: close, reopen, assign, delete, add_label, remove_label. Returns the number of rows actually affected (silently skips ids that don't belong to the tenant — withoutGlobalScope is never applied here).
curl --request POST \
"https://api.plixa.app/v1/conversations/bulk" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"action\": \"close\",
\"ids\": [
12,
17,
19
],
\"assignee_id\": 7,
\"label_id\": 3
}"
Edit the contact label shown for the conversation. WhatsApp doesn't always send a pushName, so operators need to tag contacts manually.
The ID of the conversation.
Conversation id.
curl --request PATCH \
"https://api.plixa.app/v1/conversations/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_name\": \"Lucia Pereira\",
\"notes\": \"n\",
\"assigned_user_id\": 16
}"
Hides the conversation from the default inbox list until the
given timestamp passes. The plixa:wake-snoozed-conversations
scheduled command clears the stamp at the right moment and
broadcasts a ConversationUpdated so the inbox refreshes
without a hard reload. Pass until: null to wake immediately.
Conversation id.
curl --request POST \
"https://api.plixa.app/v1/conversations/42/snooze" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"until\": \"2026-05-29T09:00:00Z\"
}"
The ID of the conversation.
curl --request POST \
"https://api.plixa.app/v1/conversations/architecto/messages" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"body\": \"b\",
\"type\": \"text\",
\"quoted_message_id\": 16
}"
Accepts a multipart upload (image, video, audio, document) plus an optional caption. The file is forwarded to Evolution as base64 — no S3 in MVP, no media URL we host. The resulting Message row stores trimmed metadata so the inbox renders a thumbnail / link inline just like inbound media.
The ID of the conversation.
Conversation id.
curl --request POST \
"https://api.plixa.app/v1/conversations/architecto/media-messages" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--header "Accept: application/json" \
--form "caption=architecto"\
--form "voice=1"\
--form "duration_seconds=5"\
--form "waveform[]=7"\
--form "file=@/tmp/phpfooGmL" Permanently removes a conversation and every message inside it for the authenticated tenant. The contact on the customer's phone is unaffected — only Plixa's local copy goes. Useful while sandbox-testing.
The ID of the conversation.
Conversation id.
curl --request DELETE \
"https://api.plixa.app/v1/conversations/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" [Empty response]
Owner-only toggle for the daily activity email. Off by default; flipping it on enrolls the workspace in tomorrow's 9am UTC run.
curl --request PUT \
"https://api.plixa.app/v1/digest-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"enabled\": true,
\"frequency\": \"weekly\"
}"
Uses the same stats payload + template as the scheduled job so the operator gets a real preview of what tomorrow's email will look like. Differences from the scheduled run:
curl --request POST \
"https://api.plixa.app/v1/digest-config/test" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request POST \
"https://api.plixa.app/v1/ai/extract-business-hours" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"prompt\": \"b\"
}"
Visual conversation flows: the bot walks an inbound conversation through a graph of steps (greeting, menu, capture, route to a sector, hand off) before the AI or a human takes over. Owner-only — flows are workspace automation, not per-agent settings.
Editing saves a draft; the live graph only changes on Publish, so a half-finished edit never reaches a real customer.
curl --request POST \
"https://api.plixa.app/v1/flows" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"WhatsApp reception\",
\"reprompt_after_minutes\": 22,
\"close_after_minutes\": 7,
\"reprompt_message\": \"z\",
\"close_conversation_on_timeout\": true
}"
Persists the working graph without affecting live conversations.
The ID of the flow.
curl --request PUT \
"https://api.plixa.app/v1/flows/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"b\",
\"reprompt_after_minutes\": 22,
\"close_after_minutes\": 7,
\"reprompt_message\": \"z\",
\"close_conversation_on_timeout\": true
}"
Validates the draft graph and copies it into the live definition.
The flow.
curl --request POST \
"https://api.plixa.app/v1/flows/564/publish" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Turning a flow on switches every other flow with the same trigger off, so only one reception flow runs at a time. A flow must be published before it can be enabled.
The flow.
curl --request POST \
"https://api.plixa.app/v1/flows/564/toggle" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"enabled\": true
}"
The ID of the flow.
curl --request DELETE \
"https://api.plixa.app/v1/flows/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The flow.
curl --request POST \
"https://api.plixa.app/v1/flows/564/ai-build" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"history\": [
\"architecto\"
],
\"graph\": []
}"
On-demand AI summary of an inbox thread. When an agent takes over a long conversation, this gives them a 3-6-sentence TL;DR so they don't have to scroll through hundreds of messages to ground themselves. Customer never sees the output — operator-facing only.
Plan-gated to the same tier that allows automated AI replies. Cached
on the conversation row; the cache invalidates when a new message
lands. A ?refresh=1 query param forces regeneration.
Conversation id.
Pass 1 to force regeneration even when the cache is fresh.
curl --request POST \
"https://api.plixa.app/v1/conversations/42/summary?refresh=1" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Workspace-level tags every member can pin onto conversations. Listing is open to every member (the inbox needs to render badges); creating, renaming, recoloring and deleting is owner-only — keeps the palette disciplined.
Any workspace member can attach. Idempotent: re-attaching is a 200 with the same payload, not a duplicate row.
The conversation.
The label.
curl --request POST \
"https://api.plixa.app/v1/conversations/564/labels/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The conversation.
The label.
curl --request DELETE \
"https://api.plixa.app/v1/conversations/564/labels/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only.
curl --request POST \
"https://api.plixa.app/v1/labels" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only.
The ID of the label.
curl --request PUT \
"https://api.plixa.app/v1/labels/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only. Also detaches the label from every conversation it's attached to (cascade on conversation_label).
The ID of the label.
curl --request DELETE \
"https://api.plixa.app/v1/labels/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" External entry point for sending outbound WhatsApp messages through
Plixa. Authenticates via Sanctum personal access token, with the
write ability required. Plan-gated to api_access = true.
Looks up the tenant's first connected phone instance and uses it (Plixa MVP only supports one number per workspace anyway). Creates or reopens a conversation for the contact and persists the outbound Message row so the panel renders it just like any other reply.
curl --request POST \
"https://api.plixa.app/v1/messages/send" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"phone\": \"642559314232682282\",
\"body\": \"u\"
}"
Computes the "getting started" checklist the dashboard banner uses to nudge new workspaces through their first-run setup. State is derived from existing tables on the fly — no extra columns, no background jobs to keep in sync. The only persisted bit is whether the owner explicitly dismissed the banner.
curl --request POST \
"https://api.plixa.app/v1/onboarding/dismiss" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only. Connects each workspace's own Stripe account (Express) so booking deposits land there, and surfaces the payments the workspace has received. No API keys: Stripe hosts the onboarding.
curl --request POST \
"https://api.plixa.app/v1/payments/connect" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request POST \
"https://api.plixa.app/v1/payments/dashboard-link" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only. Provisions a brand-new Evolution instance for the
tenant — up to the plan's whatsapp_numbers limit — and returns it
in pending_qr state so the panel can immediately show the pairing
QR. Rejected with PHONE_NUMBER_LIMIT_REACHED (409) once the plan's
allowance is exhausted.
curl --request POST \
"https://api.plixa.app/v1/phone-instances" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Logs the WhatsApp session out of Evolution and flips the local
status to disconnected. The next pairing will require a fresh
QR scan. Owner-only — disconnecting silently mid-day would
disrupt the entire workspace.
curl --request POST \
"https://api.plixa.app/v1/phone-instances/564/disconnect" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Asks Evolution to bounce the connection without unpairing. Useful
when the panel shows "disconnected" but the WhatsApp session is
still valid upstream and just needs a nudge. Flips the local
status to pending_qr so the next QR poll picks up a fresh code.
curl --request POST \
"https://api.plixa.app/v1/phone-instances/564/restart" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Browser-based push subscriptions backed by the W3C Push API + VAPID. The panel registers a service worker, asks the browser for a PushSubscription, and POSTs the endpoint + keys here. Notifications are then routed through the same Laravel queue as our emails.
Called by the panel right after the browser grants Notifications permission. Endpoint is unique per (user, browser) — the channel upserts so re-subscribing won't create duplicates.
curl --request POST \
"https://api.plixa.app/v1/push/subscriptions" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"endpoint\": \"b\",
\"keys\": {
\"p256dh\": \"architecto\",
\"auth\": \"architecto\"
},
\"content_encoding\": \"n\"
}"
Called when the user turns notifications off in the panel or when the service worker reports the subscription has been revoked.
curl --request DELETE \
"https://api.plixa.app/v1/push/subscriptions" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"endpoint\": \"b\"
}"
Called by the panel right after the browser grants Notifications permission. Endpoint is unique per (user, browser) — the channel upserts so re-subscribing won't create duplicates.
curl --request POST \
"https://api.plixa.app/v1/admin/push/subscriptions" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"endpoint\": \"b\",
\"keys\": {
\"p256dh\": \"architecto\",
\"auth\": \"architecto\"
},
\"content_encoding\": \"n\"
}"
Called when the user turns notifications off in the panel or when the service worker reports the subscription has been revoked.
curl --request DELETE \
"https://api.plixa.app/v1/admin/push/subscriptions" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"endpoint\": \"b\"
}"
Two optional service-level targets per workspace:
first_response_seconds — how long the customer should wait
before someone in the workspace answers their first message.resolution_seconds — how long a conversation should stay
open before it gets closed.NULL on either means "no target set"; the inbox and reports skip the SLA decoration entirely in that case. Each target is capped at 7 days (604800s) — anything longer is hardly an SLA.
curl --request PUT \
"https://api.plixa.app/v1/sla-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"first_response_seconds\": 900,
\"resolution_seconds\": 86400
}"
Canned messages every workspace member can pick from while composing in the inbox. Visible to every member (no per-user replies in MVP), but only owners can create/edit/delete — keeps the dropdown curated.
Owner-only.
curl --request POST \
"https://api.plixa.app/v1/saved-replies" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"label\": \"Hours\",
\"body\": \"We\'re open Monday to Saturday 9am-7pm.\"
}"
Owner-only.
curl --request PUT \
"https://api.plixa.app/v1/saved-replies/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"label\": \"b\",
\"body\": \"n\"
}"
Owner-only.
curl --request DELETE \
"https://api.plixa.app/v1/saved-replies/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Accepts an array of saved-reply ids in the desired display order.
Ids missing from the array keep their current position so a
partial drag (e.g., reordering 3 out of 30) doesn't trash the
rest. Owner-only.
curl --request POST \
"https://api.plixa.app/v1/saved-replies/reorder" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"ids\": [
12,
7,
9
]
}"
The calendar feed plus staff actions: manual booking, reschedule, cancel, and marking a no-show. All tenant-scoped; open to every member.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"service_id\": 16,
\"start\": \"2026-06-10T00:37:58\",
\"provider_id\": 16,
\"contact_id\": 16,
\"notes\": \"n\",
\"occurrences\": 7
}"
The booking form lets staff create an appointment without a contact (e.g. a slot reserved before the customer is on file). Those fields are otherwise stuck once the appointment exists — there's no generic edit — so this patches them in afterwards. Only the keys actually sent are touched, so the panel can update just the contact.
The ID of the appointment.
curl --request PATCH \
"https://api.plixa.app/v1/scheduling/appointments/16" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"contact_id\": 16,
\"notes\": \"n\"
}"
The appointment.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments/564/reschedule" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"start\": \"2026-06-10T00:37:58\"
}"
The appointment.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments/564/cancel" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"reason\": \"b\"
}"
The appointment.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments/564/no-show" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The appointment.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments/564/complete" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The appointment.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments/564/arrive" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The appointment.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments/564/payment-link" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The appointment.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments/564/approve" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The appointment.
curl --request POST \
"https://api.plixa.app/v1/scheduling/appointments/564/decline" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The workspace "base" weekly working hours: a template the owner defines once and imports into each provider, instead of typing the same hours for 30 people. Stored as JSON on the tenant; only the weekly open windows (no date overrides). Owner-only.
curl --request PUT \
"https://api.plixa.app/v1/scheduling/default-schedule" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"timezone\": \"Asia\\/Yekaterinburg\",
\"rules\": [
\"architecto\"
]
}"
Per-agent Google Calendar link. Each member connects their own Google account: Plixa writes their appointments to it and reads their free/busy back so outside commitments block Plixa slots. Tokens are encrypted at rest and never returned to the client.
curl --request POST \
"https://api.plixa.app/v1/scheduling/calendar/google/disconnect" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner toggle: import the workspace country's public holidays as closures so the AI never books on them. Enabling (or re-saving) runs a sync now; disabling drops future holiday closures. Owner-only (route group).
Enabling imports holidays immediately; a network hiccup still saves the toggle (synced=false) and the scheduled sync retries later.
curl --request PUT \
"https://api.plixa.app/v1/scheduling/holiday-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"block_holidays\": false
}"
A provider's bookable working hours: a timezone plus a flat list of rules (recurring weekday windows and date overrides, open or blocked). Readable by members; the full-replace update is owner-only.
Sends the full set of rules; the previous rules are replaced wholesale.
curl --request PUT \
"https://api.plixa.app/v1/scheduling/providers/564/schedule" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"timezone\": \"Asia\\/Yekaterinburg\",
\"rules\": [
{
\"kind\": \"architecto\",
\"weekday\": 4,
\"date\": \"2026-06-10\",
\"start_time\": \"00:37\",
\"end_time\": \"00:37\"
}
]
}"
Owner setting: when the workspace sends appointment reminders, as a list of "minutes before the appointment". Null falls back to the system default; an empty list turns reminders off. A service can still override per-service. Owner-only (route group).
curl --request PUT \
"https://api.plixa.app/v1/scheduling/reminder-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"offsets\": [
16
]
}"
Shared, capacity-limited assets (rooms, equipment). A booking of a linked service consumes one unit; the slot is full once capacity is reached. Readable by members; mutations owner-only.
curl --request POST \
"https://api.plixa.app/v1/scheduling/resources" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the resource.
curl --request PUT \
"https://api.plixa.app/v1/scheduling/resources/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the resource.
curl --request DELETE \
"https://api.plixa.app/v1/scheduling/resources/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Per-user saved calendar filters: which providers, services and statuses to show on the agenda. Each person manages their own; one can be the default, applied automatically when they open the calendar. Every member (not just owners) keeps their own set.
curl --request POST \
"https://api.plixa.app/v1/scheduling/calendar-filters" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request PUT \
"https://api.plixa.app/v1/scheduling/calendar-filters/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request DELETE \
"https://api.plixa.app/v1/scheduling/calendar-filters/564" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Bookable services. Readable by every member (the calendar + booking flows need them); create/update/delete are owner-only.
curl --request POST \
"https://api.plixa.app/v1/scheduling/services" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the service.
curl --request PUT \
"https://api.plixa.app/v1/scheduling/services/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the service.
curl --request DELETE \
"https://api.plixa.app/v1/scheduling/services/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Surfaces the appointment waitlist (built up by the AI when no slots are free) so staff can see who's waiting for which service and clear stale entries. Tenant-scoped; open to every member. The auto-notify-on-cancel flow lives in NativeSchedulingProvider — this is the human-facing view.
The ID of the entry.
curl --request DELETE \
"https://api.plixa.app/v1/scheduling/waitlist/16" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Days the whole workspace is closed. Adding one date blocks every provider (and the AI) for that day, so the owner closes the business once instead of editing each provider's schedule. Reads are open to members; create/delete are owner-only (route group).
Idempotent per (tenant, date): re-closing an already-closed day just returns it. Manual source — a holiday sync owns its own rows.
curl --request POST \
"https://api.plixa.app/v1/scheduling/closures" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"date\": \"2026-06-10\",
\"reason\": \"b\"
}"
The ID of the closure.
curl --request DELETE \
"https://api.plixa.app/v1/scheduling/closures/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Business departments (Sales, Support, Finance…) the owner defines so conversations can be routed to the right team. Listing is open to every member (the inbox and the flow editor both need it); creating, renaming and assigning agents is owner-only.
Owner-only.
curl --request POST \
"https://api.plixa.app/v1/sectors" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only. Pass user_ids to replace the assigned agents.
The ID of the sector.
curl --request PUT \
"https://api.plixa.app/v1/sectors/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only. Conversations tagged with this sector keep their history but lose the tag (sector_id is set to null).
The ID of the sector.
curl --request DELETE \
"https://api.plixa.app/v1/sectors/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Workspace-wide security / access toggles:
require_two_factor — every member must enable 2FA before the
panel grants access.agent_restricted_to_own_conversations — agents see only their
own + unassigned conversations in the inbox. Off by default
(matches the helpdesk industry pattern of a shared inbox); on
is the multi-team / compliance choice.Toggling require_two_factor ON is gated on the owner having
their own 2FA enabled — otherwise the owner could lock themselves
out instantly. Turning it OFF has no such gate.
curl --request PUT \
"https://api.plixa.app/v1/security-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"require_two_factor\": true,
\"agent_restricted_to_own_conversations\": false
}"
The customer side of in-app support: a workspace member opens a ticket and converses with Plixa staff. Auto-scoped to the caller's tenant by the BelongsToTenant global scope on SupportTicket.
curl --request POST \
"https://api.plixa.app/v1/support/tickets" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the ticket.
curl --request POST \
"https://api.plixa.app/v1/support/tickets/16/messages" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the ticket.
curl --request POST \
"https://api.plixa.app/v1/support/tickets/16/close" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the ticket.
curl --request POST \
"https://api.plixa.app/v1/support/tickets/16/reopen" \
--header "Content-Type: application/json" \
--header "Accept: application/json" The ID of the ticket.
curl --request POST \
"https://api.plixa.app/v1/support/tickets/16/rating" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"rating\": 1,
\"comment\": \"n\"
}"
Owner-only. Returns the freshly issued invitation including the
one-shot accept_url so the panel can render a copy-to-clipboard
button. After the response the token is hidden — losing it means
re-issuing the invite.
curl --request POST \
"https://api.plixa.app/v1/team/invitations" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"[email protected]\",
\"role\": \"agent\"
}"
Owner-only. Queues the same InvitationCreated mailable that the initial create() does — same accept_url, same expiry. Returns the invitation with the link so the owner can also copy-paste it to another channel.
Invitation id.
curl --request POST \
"https://api.plixa.app/v1/team/invitations/14/resend" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only. Accepted invitations cannot be cancelled — remove the user from the workspace instead via MemberController::destroy.
The ID of the invitation.
Invitation id.
curl --request DELETE \
"https://api.plixa.app/v1/team/invitations/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only. Unassigns any conversations that were attached to the removed user (their messages stay). Owners can't remove themselves — they should transfer ownership first (out of MVP scope).
The ID of the member.
The user id.
curl --request DELETE \
"https://api.plixa.app/v1/team/members/architecto" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Public — creates the user, attaches them to the tenant, marks the invitation accepted, and returns a Sanctum token so the panel can sign them in immediately.
curl --request POST \
"https://api.plixa.app/v1/team/invitations/accept" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"token\": \"aBcD1234…\",
\"name\": \"Lucia Pereira\",
\"password\": \"super-secret-pw\"
}"
Endpoints the user hits from /account to set up, confirm, regenerate recovery codes for, and disable their own TOTP second factor. All mutations require the current password — defence in depth against stolen session tokens.
Layout:
curl --request POST \
"https://api.plixa.app/v1/me/2fa/setup" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"password\": \"|]|{+-\"
}"
curl --request POST \
"https://api.plixa.app/v1/me/2fa/confirm" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"code\": \"architecto\"
}"
curl --request POST \
"https://api.plixa.app/v1/me/2fa/recovery-codes" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"password\": \"|]|{+-\"
}"
For when an operator suspects ONE code leaked (left a printout somewhere, sent it in a Slack DM by mistake) but wants to keep the others valid instead of regenerating the whole list.
Password-gated, audit-logged. Returns the count of remaining codes — the panel uses it to surface "you have N codes left".
curl --request POST \
"https://api.plixa.app/v1/me/2fa/recovery-codes/revoke" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"password\": \"********\",
\"code\": \"a1b2c3d4e5\"
}"
curl --request DELETE \
"https://api.plixa.app/v1/me/2fa" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"password\": \"|]|{+-\"
}"
Stores an email for early access. Plixa never sells this list. The landing page (plixa.app) posts here from its hero and footer forms.
curl --request POST \
"https://api.plixa.app/v1/waitlist" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"[email protected]\",
\"locale\": \"en-US\",
\"referrer\": \"https:\\/\\/news.ycombinator.com\\/\"
}"
{
"data": {
"id": 42,
"email": "[email protected]",
"created_at": "2026-05-25T12:00:00+00:00"
},
"meta": null,
"errors": null
}
curl --request POST \
"https://api.plixa.app/v1/webhooks/stripe" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-only management of customer-facing webhook endpoints. Plixa
fires message.{inbound,outbound} and conversation.{created, updated,deleted} to every active subscribed endpoint, signed with
HMAC-SHA256 (X-Plixa-Signature).
The endpoint secret is shown ONCE at create time. Storage is encrypted, the API never echoes it back — operators who lose the secret rotate the endpoint instead.
curl --request POST \
"https://api.plixa.app/v1/webhook-endpoints" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request PUT \
"https://api.plixa.app/v1/webhook-endpoints/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request DELETE \
"https://api.plixa.app/v1/webhook-endpoints/564" \
--header "Content-Type: application/json" \
--header "Accept: application/json" curl --request POST \
"https://api.plixa.app/v1/webhook-endpoints/564/test" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Resets the delivery back to pending, zeroes the attempts
counter so the existing exponential-backoff schedule starts
fresh, and queues a new DeliverWebhookJob with the same
payload. Useful after an operator fixes the receiver — they
don't have to wait for another organic event to confirm.
Refuses to act on deliveries that aren't in a terminal
failed state (no point retrying a pending one — the job
already has it).
curl --request POST \
"https://api.plixa.app/v1/webhook-deliveries/564/retry" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" Owner-defined greeting auto-sent the first time a contact reaches the workspace. Unlike the AI configuration, this is available on every plan — no plan gate.
curl --request PUT \
"https://api.plixa.app/v1/welcome-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"message\": \"Hi! Thanks for reaching out — we usually reply within 15 minutes.\",
\"enabled\": true,
\"delay_seconds\": 5
}"
Tenant-wide settings every member is bound to:
Owner-only. Members see their personal locale override in /account.
Owner-only. The timezone field accepts only real IANA identifiers (validated against DateTimeZone::listIdentifiers) so a typo can't silently corrupt every scheduled feature.
curl --request PUT \
"https://api.plixa.app/v1/workspace-config" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"timezone\": \"Asia\\/Yekaterinburg\",
\"locale\": \"sr_BA\",
\"currency\": \"architecto\"
}"
Owner-only. Stored on the shared public-image disk under a UUID key. PNG/JPEG/WebP, ≤ 1 MB — no SVG (XSS surface). Display size is enforced by the consumers (a fixed-height box), so any aspect ratio is fine.
curl --request POST \
"https://api.plixa.app/v1/workspace-config/logo" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--header "Accept: application/json" \
--form "logo=@/tmp/phpEBNBMg" curl --request DELETE \
"https://api.plixa.app/v1/workspace-config/logo" \
--header "Authorization: Bearer {PLIXA_API_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"