MailTrixy API
Build powerful integrations with the MailTrixy platform. Manage contacts, conversations, campaigns, and more programmatically.
Quick Start
1. Generate an API Token
Navigate to Settings → Account to create a personal API token. Select the scopes (permissions) your integration needs.
2. Base URL
https://mediacity.co.in/mailtrixy/public/api/v1
3. Make Your First Request
curl -X GET https://mediacity.co.in/mailtrixy/public/api/v1/contacts \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Accept: application/json"
Authentication
All API requests require a valid Bearer token sent in the Authorization header.
Authorization: Bearer your-api-token
Tokens are scoped. When you create a token, you select which API sections it can access:
contacts
Read and write contacts, lists and segments, including import and export.
conversations
Read inbox conversations, reply, assign and close them.
campaigns
Create, read and send bulk email and SMS campaigns.
outreach
Manage cold email sequences, push leads and read sequence reports.
emails
Send individual transactional emails and read their delivery status.
email-accounts
Read mailbox status, reconnect or disconnect mailboxes, and manage signatures.
templates
Read and write reusable email templates.
deals
Read and write CRM deals and pipelines.
suppressions
Read and write the bounce / unsubscribe suppression list.
workflows
Read workflows, and activate or pause them.
knowledge-base
Read and write knowledge base documents used for AI context.
temp-mail
Create disposable addresses and read their messages.
ai
Generate replies and analyse sentiment. Subject to stricter rate limits.
analytics
Read analytics and reporting data.
tags
Read and write workspace tags.
canned-responses
Read and write saved reply snippets.
Requests to endpoints outside the token's scopes will receive a 403 Forbidden response.
Rate Limiting
API requests are rate-limited to protect service stability. Default limits:
| Scope | Limit |
|---|---|
| General API | 600 requests/minute |
| Import/Export | 5 requests/minute |
| Campaign Send | 5 requests/minute |
| AI Generate Reply | 10 requests/minute |
| AI Analyze Sentiment | 20 requests/minute |
| KB Scrape | 3 requests/minute |
Rate limit headers are included in every response:
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 597
Retry-After: 42 // only when rate limited (429)
Errors
The API uses standard HTTP status codes. Errors return a JSON body with details:
| Code | Meaning |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid or missing token |
| 403 | Forbidden - Token lacks required scope |
| 404 | Not Found - Resource does not exist |
| 422 | Validation Error - Check the errors object |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Server Error - Unexpected failure |
{
"message": "Contact not found."
}
// Validation errors (422)
{
"errors": {
"email": ["The email field is required."]
}
}
Contacts
Manage your contact database. Requires contacts scope.
List contacts with search, filters, and pagination.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| search | string | No | Search by name, email, or company |
| status | string | No | Filter: active, inactive, unsubscribed |
| tag_id | integer | No | Filter by tag ID |
| country | string | No | Filter by country |
| min_score | integer | No | Minimum lead score (0-100) |
| max_score | integer | No | Maximum lead score (0-100) |
| sort_by | string | No | Sort field: first_name, last_name, email, company, lead_score, created_at, last_contacted_at |
| sort_dir | string | No | asc or desc (default: desc) |
| per_page | integer | No | Results per page (max 100, default 25) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/contacts?search=john&per_page=10' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": [
{
"id": 1,
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"phone": "+1234567890",
"company": "Acme Inc",
"lead_score": 75,
"status": "active",
"tags": [{"id": 1, "name": "VIP"}],
"created_at": "2026-03-01T10:00:00Z"
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": "..." },
"meta": { "current_page": 1, "last_page": 5, "per_page": 10, "total": 48 }
}
Create a new contact.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| first_name | string | Yes | Contact first name (max 255) |
| last_name | string | No | Contact last name |
| string | Yes | Valid email address | |
| phone | string | No | Phone number |
| company | string | No | Company name |
| job_title | string | No | Job title |
| city | string | No | City |
| country | string | No | Country |
| lead_score | integer | No | Lead score (0-100) |
| custom_fields | object | No | Custom field key-value pairs |
| tag_ids | array | No | Array of tag IDs to assign |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/contacts' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"first_name":"Jane","email":"[email protected]","company":"Acme"}'
Example Response
{
"data": {
"id": 42,
"first_name": "Jane",
"last_name": null,
"email": "[email protected]",
"company": "Acme",
"lead_score": 0,
"status": "active",
"tags": [],
"created_at": "2026-03-22T14:30:00Z"
}
}
Retrieve a single contact by ID.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/contacts/42' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": {
"id": 42,
"first_name": "Jane",
"last_name": "Smith",
"email": "[email protected]",
"conversations_count": 12,
"deals_count": 3
}
}
Update a contact. Only send fields you want to change.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| first_name | string | No | Contact first name |
| string | No | Valid email address | |
| status | string | No | active, inactive, or unsubscribed |
| tag_ids | array | No | Replace all tags with these IDs |
Example Request
curl -X PUT 'https://mediacity.co.in/mailtrixy/public/api/v1/contacts/42' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"lead_score":90,"status":"active"}'
Example Response
{
"data": {
"id": 42,
"first_name": "Jane",
"lead_score": 90,
"status": "active"
}
}
Soft-delete a contact.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/contacts/42' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
204 No Content
Import contacts from a CSV file. Rate limited to 5 req/min.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| file | file | Yes | CSV/XLSX file (max 10MB). Headers: first_name, last_name, email, phone, company, etc. |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/contacts/import' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -F '[email protected]'
Example Response
{
"data": {
"imported": 142,
"skipped": 3,
"errors": ["Row 15: invalid email 'not-an-email'"]
}
}
Export all contacts as a streamed CSV download. Rate limited to 5 req/min.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/contacts/export' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -o contacts.csv
Example Response
Binary CSV file stream
Conversations
Manage inbox conversations. Requires conversations scope.
List conversations with filters and pagination.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| status | string | No | Filter: open, closed, snoozed |
| channel | string | No | Filter by channel: email, chat, whatsapp, sms |
| assigned_to | integer | No | Filter by assigned user ID |
| contact_id | integer | No | Filter by contact ID |
| per_page | integer | No | Results per page (max 100) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/conversations?status=open' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": [
{
"id": 1,
"subject": "Billing question",
"status": "open",
"channel": "email",
"contact": {"id": 5, "email": "[email protected]"},
"assigned_to": {"id": 2, "name": "Agent Smith"},
"last_message_at": "2026-03-22T09:30:00Z"
}
],
"meta": {"current_page": 1, "total": 24}
}
Send a reply to a conversation.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| body | string | Yes | Reply message body (HTML supported) |
| internal | boolean | No | If true, add as internal note (not sent to contact) |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/conversations/1/reply' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"body":"Thanks for reaching out! We will look into this."}'
Example Response
{
"data": {
"id": 145,
"conversation_id": 1,
"body": "Thanks for reaching out! We will look into this.",
"type": "reply",
"created_at": "2026-03-22T14:30:00Z"
}
}
Assign a conversation to a team member.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| user_id | integer | Yes | User ID to assign the conversation to |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/conversations/1/assign' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"user_id":3}'
Example Response
{
"data": {"id": 1, "assigned_to": {"id": 3, "name": "Agent Jones"}}
}
Close a conversation.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/conversations/1/close' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {"id": 1, "status": "closed"}
}
Campaigns
Create and manage email campaigns. Requires campaigns scope.
List campaigns with filters.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| status | string | No | Filter: draft, scheduled, sending, sent, paused |
| type | string | No | Filter by campaign type |
| search | string | No | Search by name or subject |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/campaigns?status=sent' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": [
{
"id": 1,
"name": "March Newsletter",
"subject": "What is new in March",
"status": "sent",
"sent_count": 1250,
"open_rate": 34.5,
"click_rate": 8.2,
"created_at": "2026-03-01T08:00:00Z"
}
]
}
Create a new campaign (draft).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Campaign name |
| subject | string | Yes | Email subject line |
| html_body | string | Yes | HTML email body |
| segment_id | integer | No | Segment ID to target |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/campaigns' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"April Promo","subject":"Special offer inside","html_body":"<h1>Hello!</h1>"}'
Example Response
{
"data": {"id": 15, "name": "April Promo", "status": "draft"}
}
Send or schedule a campaign. Rate limited to 5 req/min.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| scheduled_at | datetime | No | ISO 8601 datetime to schedule (omit to send immediately) |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/campaigns/15/send' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json'
Example Response
{
"data": {"id": 15, "status": "sending"}
}
Workflows
Manage automation workflows. Requires workflows scope.
List all workflows.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/workflows' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": [
{"id": 1, "name": "Welcome Series", "status": "active", "trigger": "contact.created", "executions_count": 342}
]
}
Activate a paused workflow.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/workflows/1/activate' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{"data": {"id": 1, "status": "active"}}
Pause an active workflow.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/workflows/1/pause' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{"data": {"id": 1, "status": "paused"}}
Knowledge Base
Manage KB documents for AI context. Requires knowledge-base scope.
List knowledge base documents.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| search | string | No | Search document titles |
| per_page | integer | No | Results per page |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/knowledge-base' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": [
{"id": 1, "title": "Product FAQ", "type": "file", "file_size": 245760, "chunks_count": 24, "created_at": "2026-03-10T12:00:00Z"}
]
}
Upload a document to the knowledge base.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Document title |
| file | file | Yes | PDF, DOCX, or TXT file |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/knowledge-base' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -F 'title=Return Policy' \ -F '[email protected]'
Example Response
{
"data": {"id": 5, "title": "Return Policy", "status": "processing"}
}
Scrape a website URL and add it to the knowledge base. Rate limited to 3 req/min.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | URL to scrape |
| title | string | No | Custom title (auto-detected if omitted) |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/knowledge-base/scrape' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com/help"}'
Example Response
{
"data": {"id": 6, "title": "Help Center", "type": "url", "status": "processing"}
}
AI
AI-powered features. Requires ai scope. Stricter rate limits apply.
Generate an AI-powered reply for a conversation. Rate limited to 10 req/min.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| conversation_id | integer | Yes | Conversation to generate a reply for |
| tone | string | No | Reply tone: professional, friendly, concise |
| instructions | string | No | Additional context for the AI |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/ai/generate-reply' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"conversation_id":1,"tone":"professional"}'
Example Response
{
"data": {
"reply": "Thank you for contacting us regarding your billing inquiry...",
"tokens_used": 245,
"model": "gpt-4"
}
}
Analyze the sentiment of a text or conversation. Rate limited to 20 req/min.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| text | string | No | Text to analyze (provide this or conversation_id) |
| conversation_id | integer | No | Conversation ID to analyze |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/ai/analyze-sentiment' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"text":"I am very frustrated with the late delivery"}'
Example Response
{
"data": {
"sentiment": "negative",
"score": -0.78,
"emotions": ["frustration", "disappointment"],
"urgency": "high"
}
}
Analytics
Read-only analytics data. Requires analytics scope.
Get workspace analytics overview.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| period | string | No | 7d, 30d, 90d (default: 30d) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/analytics/overview?period=30d' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": {
"conversations": {"total": 524, "open": 38, "avg_resolution_hours": 4.2},
"contacts": {"total": 12500, "new_this_period": 320},
"campaigns": {"sent": 8, "avg_open_rate": 32.1, "avg_click_rate": 6.8},
"ai": {"replies_generated": 186, "tokens_used": 45200}
}
}
Get team performance metrics.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| period | string | No | 7d, 30d, 90d |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/analytics/team' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": [
{"user_id": 2, "name": "Agent Smith", "conversations_handled": 142, "avg_response_minutes": 12, "satisfaction_score": 4.6}
]
}
Canned Responses
Manage saved reply templates. Requires canned-responses scope.
List all canned responses.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/canned-responses' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Accept: application/json'
Example Response
{
"data": [
{"id": 1, "title": "Greeting", "shortcut": "/greet", "body": "Hello! How can I help you today?"}
]
}
Create a new canned response.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Template title |
| shortcut | string | No | Slash command shortcut (e.g. /thanks) |
| body | string | Yes | Response body (HTML supported) |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/canned-responses' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"title":"Thanks","shortcut":"/thanks","body":"Thank you for your patience!"}'
Example Response
{
"data": {"id": 5, "title": "Thanks", "shortcut": "/thanks", "body": "Thank you for your patience!"}
}
What's New in v1.9
Scoped API tokens
Create a scoped personal access token under Settings → Account → API Tokens,
choosing from 16 scopes with an optional expiry.
Token management is also fully scriptable via
/api/v1/tokens.
A request made with a token that lacks the scope a route requires returns a
403 naming exactly
what is missing, so you can correct the token without guesswork:
{
"message": "This token is not permitted to access that endpoint.",
"required_scopes": ["deals"]
}
New endpoint families
| Family | Scope | What it unblocks |
|---|---|---|
| /emails | emails | Sending a single email. The API could send bulk campaigns but not one message. |
| /email-accounts | email-accounts | Monitoring and repairing mailboxes. Reconnecting previously required a human in the web UI. |
| /outreach | outreach | Cold email sequences. Push leads straight from a prospecting tool. |
| /templates | templates | Reusable email templates, as block JSON and rendered HTML. |
| /contact-lists, /segments | contacts | Campaigns target a list or segment — neither was reachable before. |
| /deals, /pipelines | deals | The CRM half of the product had no API at all. |
| /suppressions | suppressions | Keep bounces and unsubscribes in sync with any other system that mails these people. |
| /update | none | Platform version, feature flags, and client build support. |
| /tokens | none | Create, list and revoke scoped tokens. |
Email Sending
Send individual transactional emails through a connected mailbox. Requires
emails scope.
Suppressions and unsubscribes are enforced server-side, and every send counts against your plan's
monthly email quota — the API cannot be used to bypass either.
Mailboxes available as from_account_id. Trimmed on purpose — the full mailbox surface lives under /email-accounts.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/emails/accounts' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 3,
"email": "[email protected]",
"display_name": "Acme Sales",
"provider": "imap",
"is_default": true
},
{
"id": 4,
"email": "[email protected]",
"display_name": "Acme",
"provider": "gmail",
"is_default": false
}
]
}
Sends one message. Omit from_account_id to use the workspace default mailbox. Pass conversation_id to thread onto an existing inbox conversation. Custom headers must be X- prefixed — From, Message-ID and In-Reply-To are stripped so a token cannot spoof your sender or hijack a thread.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| to | string | Yes | Recipient email address |
| subject | string | Yes | Subject line (max 255) |
| html | string | No | HTML body. Required unless text is supplied |
| text | string | No | Plain-text body. Wrapped for HTML clients if html is omitted |
| from_account_id | integer | No | Mailbox to send from. Must be connected and in your workspace |
| cc | array | No | Up to 20 addresses |
| bcc | array | No | Up to 20 addresses |
| reply_to | string | No | Reply-To address |
| headers | object | No | Custom headers. Only X- prefixed names are kept; CRLF is stripped |
| conversation_id | integer | No | Thread onto this conversation instead of starting a new one |
| contact_id | integer | No | Attach the logged message to this contact |
| log_to_inbox | boolean | No | Mirror into the unified inbox (default true) |
| skip_suppression_check | boolean | No | Owner/admin only. Bypasses the suppression list |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/emails/send' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"to": "[email protected]",
"subject": "Your invoice #1042",
"html": "<p>Hi Jane, your invoice is attached.</p>",
"reply_to": "[email protected]",
"headers": {"X-Invoice-Ref": "1042"}
}'
Example Response
201 Created
{
"status": "sent",
"message": "Email sent.",
"data": {
"message_id": "<[email protected]>",
"internal_message_id": 8821,
"conversation_id": 412,
"from": "[email protected]",
"to": "[email protected]",
"subject": "Your invoice #1042",
"sent_at": "2026-10-26T09:14:03+00:00"
}
}
422 — recipient on the suppression list
{
"error": "Recipient is on the suppression list.",
"code": "SUPPRESSED",
"reason": "hard_bounce"
}
422 — no mailbox to send from
{
"error": "No connected mailbox available to send from.",
"code": "NO_SENDING_ACCOUNT",
"hint": "Connect a mailbox under Settings -> Email Accounts, or pass a valid from_account_id."
}
502 — the transport rejected it
{
"error": "The message could not be sent.",
"code": "SEND_FAILED",
"detail": "535 Authentication credentials invalid"
}
Delivery status of a message this API sent. Poll this instead of needing a webhook. The id is internal_message_id from the send response.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/emails/8821' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {
"id": 8821,
"conversation_id": 412,
"subject": "Your invoice #1042",
"to": ["[email protected]"],
"from": "[email protected]",
"message_id": "<[email protected]>",
"delivery_status": "sent",
"delivery_error": null,
"opens_count": 2,
"clicks_count": 1,
"sent_at": "2026-10-26T09:14:03+00:00",
"opened_at": "2026-10-26T09:31:55+00:00",
"clicked_at": "2026-10-26T09:32:10+00:00",
"bounced_at": null,
"bounce_type": null
}
}
Mailboxes
Monitor, repair and configure connected mailboxes, plus their signatures. Requires
email-accounts scope.
Credentials are never returned — the *_configured
booleans tell you whether a secret is set without revealing it.
All mailboxes with status, error_message and last_synced_at — enough for a monitor to alert on a broken mailbox.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 3,
"uuid": "8a7c...",
"email": "[email protected]",
"display_name": "Acme Sales",
"provider": "imap",
"status": "connected",
"is_default": true,
"ai_auto_reply": false,
"is_oauth": false,
"error_message": null,
"last_synced_at": "2026-10-26T09:12:00+00:00",
"created_at": "2026-04-02T11:00:00+00:00"
},
{
"id": 4,
"uuid": "b31f...",
"email": "[email protected]",
"display_name": "Acme",
"provider": "gmail",
"status": "error",
"is_default": false,
"ai_auto_reply": true,
"is_oauth": true,
"error_message": "invalid_grant: Token has been expired or revoked.",
"last_synced_at": "2026-10-24T22:40:00+00:00",
"created_at": "2026-05-18T08:20:00+00:00"
}
]
}
Detail view. Adds host/port/encryption and the *_configured flags. Passwords and OAuth tokens are never included.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {
"id": 3,
"uuid": "8a7c...",
"email": "[email protected]",
"display_name": "Acme Sales",
"provider": "imap",
"status": "connected",
"is_default": true,
"ai_auto_reply": false,
"is_oauth": false,
"error_message": null,
"last_synced_at": "2026-10-26T09:12:00+00:00",
"created_at": "2026-04-02T11:00:00+00:00",
"imap_host": "imap.acme.com",
"imap_port": 993,
"imap_encryption": "ssl",
"smtp_host": "smtp.acme.com",
"smtp_port": 587,
"smtp_encryption": "tls",
"imap_configured": true,
"smtp_configured": true,
"sync_folders": ["INBOX"]
}
}
Repairs a mailbox after a password rotation or token expiry. Credentials are live-tested against the IMAP server BEFORE anything is written, so a wrong password can never leave the mailbox worse off than it already was. On success a sync is queued immediately.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| imap_host | string | Yes | IMAP hostname |
| imap_port | integer | Yes | IMAP port, usually 993 |
| imap_username | string | Yes | IMAP username |
| imap_password | string | Yes | IMAP password or app password |
| imap_encryption | string | Yes | ssl | tls | starttls | none |
| smtp_host | string | No | SMTP hostname. Omit to keep the existing value |
| smtp_port | integer | No | SMTP port |
| smtp_username | string | No | Blank or omitted leaves the stored value untouched |
| smtp_password | string | No | Blank or omitted leaves the stored value untouched |
| smtp_encryption | string | No | ssl | tls | starttls | none |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3/reconnect' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"imap_host": "imap.acme.com",
"imap_port": 993,
"imap_username": "[email protected]",
"imap_password": "new-app-password",
"imap_encryption": "ssl"
}'
Example Response
200 OK
{
"status": "success",
"message": "Mailbox reconnected.",
"data": { "id": 3, "status": "connected", "error_message": null, "...": "..." }
}
409 — OAuth mailbox. There is nothing to POST; the user must re-consent
in a browser, so we hand back the URL rather than pretend to succeed.
{
"status": "oauth_required",
"message": "Re-authorize this gmail mailbox to reconnect it.",
"provider": "gmail",
"authorize_url": "https://your-site/email-oauth/google/redirect?account_id=4",
"data": { "id": 4, "status": "error", "...": "..." }
}
422 — credentials rejected. The failure reason is also stored on the
mailbox, so the web UI and the next poll show the same message.
{
"status": "error",
"message": "Could not connect with those credentials.",
"detail": "AUTHENTICATIONFAILED Invalid credentials"
}
Stops syncing and sending but keeps the row and all of its conversation history. Use DELETE to remove the mailbox entirely.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3/disconnect' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"message": "Mailbox disconnected.",
"data": { "id": 3, "status": "disconnected", "error_message": null, "...": "..." }
}
Queues an immediate mail fetch for this mailbox.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3/sync' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
200 OK
{
"status": "queued",
"message": "Sync queued.",
"last_synced_at": "2026-10-26T09:12:00+00:00"
}
409 — mailbox is not connected
{
"error": "Mailbox is not connected.",
"code": "NOT_CONNECTED",
"status": "disconnected"
}
Makes this the workspace default sender. Exactly one mailbox is default at a time — the previous one is cleared in the same request.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/4/default' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"message": "Default mailbox updated.",
"data": { "id": 4, "is_default": true, "...": "..." }
}
Updates the safe, non-credential fields only. Rotating secrets must go through /reconnect, which live-tests them first.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| display_name | string | No | Visible sender name |
| ai_auto_reply | boolean | No | Let the AI auto-reply on this mailbox |
| is_default | boolean | No | Make this the default sender |
| sync_folders | array | No | IMAP folders to sync, e.g. ["INBOX"] |
Example Request
curl -X PUT 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"display_name":"Acme Sales Team","ai_auto_reply":true}'
Example Response
{
"message": "Email account updated.",
"data": { "id": 3, "display_name": "Acme Sales Team", "ai_auto_reply": true, "...": "..." }
}
Validates IMAP credentials without touching any stored mailbox. Useful in an onboarding flow before committing to a connection.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| imap_host | string | Yes | IMAP hostname |
| imap_port | integer | Yes | IMAP port |
| imap_username | string | Yes | IMAP username |
| imap_password | string | Yes | IMAP password |
| imap_encryption | string | Yes | ssl | tls | starttls | none |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/test' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"imap_host":"imap.acme.com","imap_port":993,"imap_username":"[email protected]","imap_password":"pw","imap_encryption":"ssl"}'
Example Response
200 OK
{ "status": "success", "message": "IMAP connection successful." }
422
{ "status": "error", "message": "AUTHENTICATIONFAILED Invalid credentials" }
Removes the mailbox. Prefer /disconnect if you want to keep conversation history.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{ "message": "Email account removed." }
Signatures
Signatures belong to a mailbox, so every route nests under one. Exactly one signature per mailbox
is is_default; deleting the default promotes another automatically.
All signatures on a mailbox.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3/signatures' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 11,
"email_account_id": 3,
"name": "Default",
"content_html": "<p>Jane Smith<br>Acme Corp</p>",
"is_default": true,
"append_to_new": true,
"append_to_replies": true,
"created_at": "2026-06-01T10:00:00+00:00"
}
]
}
Creates a signature. Setting is_default clears it on every other signature for that mailbox.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Internal label |
| content_html | string | Yes | Signature HTML |
| is_default | boolean | No | Make this the mailbox default |
| append_to_new | boolean | No | Append on new emails (default true) |
| append_to_replies | boolean | No | Append on replies (default true) |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3/signatures' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"Company footer","content_html":"<p>Acme Corp</p>","is_default":true}'
Example Response
201 Created
{
"message": "Signature created.",
"data": { "id": 12, "name": "Company footer", "is_default": true, "...": "..." }
}
Updates a signature. All fields optional.
Example Request
curl -X PUT 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3/signatures/12' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"content_html":"<p>Acme Corp — now hiring</p>"}'
Example Response
{
"message": "Signature updated.",
"data": { "id": 12, "content_html": "<p>Acme Corp — now hiring</p>", "...": "..." }
}
Deletes a signature. If it was the default, the next remaining signature is promoted.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/email-accounts/3/signatures/12' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{ "message": "Signature deleted." }
Cold Outreach
Multi-step cold email sequences with A/B variants, mailbox rotation and automatic reply detection.
Requires outreach scope.
Merge fields and spintax
Variant subjects and bodies support {{company}}-style merge
fields with an inline fallback after a pipe — {{first_name|there}}
renders "there" when the lead has no first name, so a blank field never leaks a raw token.
Any key under custom_fields is available as
{{custom.industry}}. Spintax
{Hi|Hey|Hello} picks one option per send so a thousand emails
off one template are not byte-identical.
Paginated sequences. Filter with ?status=draft|active|paused|completed|archived and ?search=.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| status | string | No | draft | active | paused | completed | archived |
| search | string | No | Match against the sequence name |
| per_page | integer | No | Max 100 (default 25) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach?status=active' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 7,
"uuid": "c4f2...",
"name": "Q4 outbound",
"description": null,
"status": "active",
"steps_count": 3,
"leads_count": 420,
"stats": {
"sent": 318,
"opened": 142,
"clicked": 37,
"replied": 21,
"bounced": 4,
"unsubscribed": 2,
"open_rate": 44.65,
"click_rate": 11.64,
"reply_rate": 6.6,
"bounce_rate": 1.26
},
"started_at": "2026-10-14T09:00:00+00:00",
"paused_at": null,
"completed_at": null,
"created_at": "2026-10-13T16:22:00+00:00"
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1 }
}
Full sequence: steps with their variants, all sending settings, and a readiness array listing anything that would block a start.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {
"id": 7,
"name": "Q4 outbound",
"status": "active",
"steps_count": 2,
"leads_count": 420,
"stats": { "sent": 318, "reply_rate": 6.6, "...": "..." },
"steps": [
{
"id": 21,
"position": 1,
"name": null,
"wait_days": 0,
"wait_hours": 0,
"reply_to_thread": true,
"condition": "always",
"is_active": true,
"variants": [
{
"id": 55,
"label": "A",
"subject": "Quick question about Acme",
"body_html": "<p>Hi Jane,</p>",
"weight": 1,
"is_winner": false,
"is_active": true,
"sent_count": 160
},
{
"id": 56,
"label": "B",
"subject": "Acme + us?",
"body_html": "<p>Hey Jane,</p>",
"weight": 1,
"is_winner": true,
"is_active": true,
"sent_count": 158
}
]
},
{
"id": 22,
"position": 2,
"wait_days": 3,
"wait_hours": 0,
"reply_to_thread": true,
"condition": "not_opened",
"is_active": true,
"variants": [
{ "id": 57, "label": "A", "subject": null, "sent_count": 94, "...": "..." }
]
}
],
"settings": {
"timezone": "Europe/London",
"use_lead_timezone": false,
"send_days": [1,2,3,4,5],
"send_start_time": "09:00",
"send_end_time": "17:00",
"daily_limit": 40,
"per_inbox_daily_limit": 20,
"min_delay_seconds": 60,
"max_delay_seconds": 300,
"email_account_ids": [3,4],
"track_opens": true,
"track_clicks": true,
"stop_on_reply": true,
"stop_on_click": false,
"append_unsubscribe": true,
"log_to_inbox": true,
"respect_suppressions": true,
"one_per_domain": false,
"winner_metric": "reply"
},
"readiness": []
}
}
Creates a sequence. The nested steps array means a whole sequence is one call instead of three round-trips per step. Step 1 sends on enrollment and needs a subject; later steps wait the given delay and reply inside the same thread — leave their subject null to inherit "Re: <opening subject>". Mailbox ids that do not belong to your workspace are silently dropped, never stored.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Sequence name |
| description | string | No | Internal note |
| timezone | string | No | IANA timezone for the send window (default UTC) |
| use_lead_timezone | boolean | No | Time sends to each lead's own timezone where known |
| send_days | array | No | ISO weekdays 1-7, 1=Mon (default Mon-Fri) |
| send_start_time | string | No | HH:MM window start (default 09:00) |
| send_end_time | string | No | HH:MM window end (default 17:00) |
| daily_limit | integer | No | Max sends per day for the sequence (default 50) |
| per_inbox_daily_limit | integer | No | Max sends per mailbox per day (default 50) |
| min_delay_seconds | integer | No | Minimum random gap between sends (default 60) |
| max_delay_seconds | integer | No | Maximum random gap between sends (default 300) |
| email_account_ids | array | No | Mailboxes to rotate across. Empty uses the workspace default |
| track_opens | boolean | No | Inject an open pixel (default true) |
| track_clicks | boolean | No | Rewrite links through a redirect (default true) |
| stop_on_reply | boolean | No | Stop a lead the moment they reply (default true) |
| stop_on_click | boolean | No | Stop a lead when they click (default false) |
| append_unsubscribe | boolean | No | Footer link + RFC 8058 one-click header (default true) |
| log_to_inbox | boolean | No | Mirror sends into the unified inbox (default true) |
| respect_suppressions | boolean | No | Skip suppressed addresses on import (default true) |
| one_per_domain | boolean | No | At most one lead per company domain (default false) |
| winner_metric | string | No | open | click | reply (default reply) |
| steps | array | No | Up to 20 steps, each requiring a variants array of 1-4 entries |
| steps[].wait_days | integer | No | 0-365. Measured from the previous step's send |
| steps[].wait_hours | integer | No | 0-23, added to wait_days |
| steps[].reply_to_thread | boolean | No | Send inside the opening thread (default true, ignored on step 1) |
| steps[].condition | string | No | always | not_opened | not_clicked |
| steps[].variants[].subject | string | No | Null on a threaded follow-up to inherit "Re: ..." |
| steps[].variants[].body_html | string | Yes | HTML body. Supports merge fields and spintax |
| steps[].variants[].weight | integer | No | Relative split weight, 1-100 (default 1) |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "Q4 outbound",
"daily_limit": 40,
"per_inbox_daily_limit": 20,
"send_days": [1,2,3,4,5],
"send_start_time": "09:00",
"send_end_time": "17:00",
"timezone": "Europe/London",
"email_account_ids": [3,4],
"stop_on_reply": true,
"steps": [
{"wait_days": 0, "variants": [
{"subject": "Quick question about {{company}}", "body_html": "<p>{Hi|Hey|Hello} {{first_name|there}},</p>", "weight": 1},
{"subject": "{{company}} + us?", "body_html": "<p>Hi {{first_name|there}},</p>", "weight": 1}
]},
{"wait_days": 3, "reply_to_thread": true, "condition": "not_opened", "variants": [
{"subject": null, "body_html": "<p>Floating this back up.</p>"}
]}
]
}'
Example Response
201 Created
{
"message": "Sequence created.",
"data": {
"id": 7,
"uuid": "c4f2...",
"name": "Q4 outbound",
"status": "draft",
"steps_count": 2,
"leads_count": 0,
"stats": { "sent": 0, "opened": 0, "reply_rate": 0, "...": "..." },
"started_at": null,
"created_at": "2026-10-26T09:40:00+00:00"
}
}
Pushes up to 1000 leads per call. Returns per-batch counts rather than failing on one bad row — a scraped list always contains some junk, and rejecting 999 good leads over one malformed address would make this endpoint unusable. Deduped against the sequence, screened against the workspace suppression list, and (optionally) one-per-domain.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| leads | array | Yes | 1-1000 lead objects |
| leads[].email | string | Yes | The only required field |
| leads[].first_name | string | No | Merge field |
| leads[].last_name | string | No | Merge field |
| leads[].company | string | No | Merge field |
| leads[].job_title | string | No | Merge field |
| leads[].website | string | No | Merge field |
| leads[].phone | string | No | Merge field |
| leads[].city | string | No | Merge field |
| leads[].country | string | No | Merge field |
| leads[].timezone | string | No | IANA timezone, used when use_lead_timezone is on |
| leads[].custom_fields | object | No | Arbitrary keys, available as custom.<key> merge fields |
| leads[].contact_id | integer | No | Link to an existing CRM contact |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/leads' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"leads": [
{"email": "[email protected]", "first_name": "Jane", "company": "Acme",
"job_title": "Head of Ops", "timezone": "America/New_York",
"custom_fields": {"industry": "SaaS"}},
{"email": "[email protected]", "first_name": "Sam"}
]
}'
Example Response
201 Created
{
"message": "Leads processed.",
"data": {
"imported": 2,
"duplicates": 0,
"invalid": 0,
"suppressed": 0,
"leads_total": 422
}
}
Paginated leads with their walk state. current_step is the last position actually sent; next_action_at is when the engine will look at this lead again.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| status | string | No | pending | active | completed | replied | bounced | unsubscribed | paused | failed | skipped |
| search | string | No | Match email, first name or company |
| per_page | integer | No | Max 200 (default 50) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/leads?status=replied' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 9014,
"uuid": "7e21...",
"email": "[email protected]",
"first_name": "Jane",
"last_name": "Smith",
"company": "Acme",
"job_title": "Head of Ops",
"status": "replied",
"exit_reason": "replied",
"current_step": 1,
"next_action_at": null,
"opened_count": 3,
"clicked_count": 1,
"last_sent_at": "2026-10-20T10:12:00+00:00",
"replied_at": "2026-10-20T14:48:00+00:00",
"contact_id": 42,
"conversation_id": 512,
"error_message": null
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 50, "total": 1 }
}
Moves the sequence to active and books a first send slot for every pending lead. Returns 422 with a problems array when it is not ready, so you can show the user exactly what to fix rather than a generic failure.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/start' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
200 OK
{
"message": "Sequence started.",
"data": { "id": 7, "status": "active", "started_at": "2026-10-26T09:45:00+00:00", "...": "..." }
}
422 — not ready
{
"error": "Import or add at least one lead.",
"code": "NOT_READY",
"problems": [
"Import or add at least one lead.",
"Step 2 variant A has an empty body."
]
}
Stops sending immediately. There is no job queue to drain — the engine simply stops selecting this sequence — so a paused sequence is safe to edit.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/pause' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"message": "Sequence paused.",
"data": { "id": 7, "status": "paused", "paused_at": "2026-10-26T10:00:00+00:00", "...": "..." }
}
Resumes a paused sequence. Leads whose slot elapsed while paused are pulled forward to the next valid send window instead of all firing at once.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/resume' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"message": "Sequence resumed.",
"data": { "id": 7, "status": "active", "paused_at": null, "...": "..." }
}
Deep-copies steps, variants and settings into a new draft. Never copies leads or stats, and clears any declared winner — a winner only means something against the numbers that were just dropped.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | No | Name for the copy (defaults to "<name> (copy)") |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/duplicate' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"Q1 outbound"}'
Example Response
201 Created
{
"message": "Sequence duplicated.",
"data": { "id": 8, "name": "Q1 outbound", "status": "draft", "leads_count": 0, "...": "..." }
}
Per-lead control. "unsubscribe" also adds the address to the workspace suppression list and marks the linked CRM contact, so campaigns and workflows honour it too.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| action | string | Yes | pause | resume | unsubscribe | remove |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/leads/9014/action' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"action":"pause"}'
Example Response
{
"message": "Lead updated.",
"data": { "id": 9014, "status": "paused", "next_action_at": null, "...": "..." }
}
Totals, lead-status breakdown, and per-variant performance. Rates are percentages already computed server-side.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/report' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {
"sequence": { "id": 7, "name": "Q4 outbound", "status": "active", "...": "..." },
"totals": {
"sent": 318, "opened": 142, "clicked": 37,
"replied": 21, "bounced": 4, "unsubscribed": 2,
"open_rate": 44.65, "click_rate": 11.64,
"reply_rate": 6.6, "bounce_rate": 1.26
},
"lead_statuses": {
"active": 98, "completed": 299, "replied": 21,
"bounced": 4, "unsubscribed": 2
},
"steps": [
{
"id": 21,
"position": 1,
"variants": [
{
"id": 55, "label": "A", "subject": "Quick question about Acme",
"is_winner": false, "sent": 160, "opened": 70, "clicked": 15,
"replied": 7, "bounced": 2,
"open_rate": 43.75, "click_rate": 9.38, "reply_rate": 4.38
},
{
"id": 56, "label": "B", "subject": "Acme + us?",
"is_winner": true, "sent": 158, "opened": 72, "clicked": 22,
"replied": 14, "bounced": 2,
"open_rate": 45.57, "click_rate": 13.92, "reply_rate": 8.86
}
]
}
]
}
}
Declares a winner for that step. Every remaining send on the step uses it — that is the point of declaring mid-flight. Clears the flag on the step's other variants.
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7/variants/56/winner' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{ "message": "Winner set for this step." }
Updates sequence settings only. Steps and variants have their own endpoints so a small tweak does not require resending the whole sequence body. Accepts the same fields as POST /outreach, minus steps.
Example Request
curl -X PUT 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"daily_limit":60,"send_days":[1,2,3,4],"stop_on_click":true}'
Example Response
{
"message": "Sequence updated.",
"data": { "id": 7, "name": "Q4 outbound", "...": "..." }
}
Deletes a sequence with its steps, variants, leads and history. Refused while the sequence is active — deleting mid-flight would strand leads between steps.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/outreach/7' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
200 OK
{ "message": "Sequence deleted." }
409 — still running
{
"error": "Pause the sequence before deleting it.",
"code": "SEQUENCE_ACTIVE"
}
Email Templates
Requires templates scope.
Templates are stored as block JSON so one template renders identically in campaigns, the inbox
picker and cold outreach. A detail request returns both the editable
blocks and the rendered html.
Paginated templates, including the shared built-in catalog. The rendered html is omitted from the list — rendering every template for an index page is wasted work.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| category | string | No | Filter by category |
| search | string | No | Match the template name |
| per_page | integer | No | Max 100 (default 25) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/templates' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 31,
"name": "Welcome email",
"category": "onboarding",
"is_default": false,
"is_editable": true,
"usage_count": 14,
"created_at": "2026-07-02T09:00:00+00:00",
"updated_at": "2026-10-01T12:30:00+00:00"
},
{
"id": 2,
"name": "Product announcement",
"category": "marketing",
"is_default": true,
"is_editable": false,
"usage_count": 220,
"created_at": "2026-04-21T00:00:00+00:00",
"updated_at": "2026-04-21T00:00:00+00:00"
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 2 }
}
Single template with both block JSON and rendered HTML.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/templates/31' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {
"id": 31,
"name": "Welcome email",
"category": "onboarding",
"is_default": false,
"is_editable": true,
"usage_count": 14,
"blocks": [
{ "type": "heading", "data": { "content": "Welcome aboard" } },
{ "type": "text", "data": { "content": "Thanks for signing up." } },
{ "type": "button", "data": { "label": "Get started", "url": "https://acme.com/start" } }
],
"html": "<div style=\"font-family:...\">...</div>",
"created_at": "2026-07-02T09:00:00+00:00",
"updated_at": "2026-10-01T12:30:00+00:00"
}
}
Creates a workspace-owned template. API-created templates are never part of the shared built-in catalog.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Template name |
| blocks | array | Yes | Block JSON, each entry {type, data} |
| category | string | No | Grouping label (default "custom") |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/templates' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "Renewal reminder",
"category": "lifecycle",
"blocks": [
{"type": "heading", "data": {"content": "Your plan renews soon"}},
{"type": "text", "data": {"content": "No action needed."}}
]
}'
Example Response
201 Created
{
"message": "Template created.",
"data": { "id": 32, "name": "Renewal reminder", "is_editable": true, "blocks": [], "html": "...", "...": "..." }
}
Updates a workspace template. Built-in catalog templates are read-only — duplicate first.
Example Request
curl -X PUT 'https://mediacity.co.in/mailtrixy/public/api/v1/templates/31' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"Welcome email v2"}'
Example Response
200 OK
{ "message": "Template updated.", "data": { "id": 31, "name": "Welcome email v2", "...": "..." } }
403 — built-in template
{
"error": "Built-in templates cannot be edited. Duplicate it first.",
"code": "READ_ONLY_TEMPLATE"
}
The supported way to start from a built-in template: copies it into your workspace as an editable template.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | No | Name for the copy (defaults to "<name> (copy)") |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/templates/2/duplicate' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
201 Created
{
"message": "Template duplicated.",
"data": { "id": 33, "name": "Product announcement (copy)", "is_default": false, "is_editable": true, "...": "..." }
}
Deletes a workspace template. Built-in templates cannot be deleted.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/templates/31' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{ "message": "Template deleted." }
Contact Lists & Segments
Requires contacts scope.
Campaigns target a list or a segment, so without these you could create contacts but had no way to
group them into something sendable. Segments are read-only here — their rule JSON is interpreted by
the campaign audience builder, so they are authored in the UI and referenced by id.
All contact lists with their cached member counts.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/contact-lists' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 2,
"name": "Newsletter subscribers",
"description": "Opted in via the website footer",
"contacts_count": 4820,
"created_at": "2026-05-10T08:00:00+00:00",
"updated_at": "2026-10-25T19:02:00+00:00"
}
]
}
Creates an empty list.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | List name |
| description | string | No | Internal note |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/contact-lists' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"Trial signups","description":"Last 30 days"}'
Example Response
201 Created
{
"message": "List created.",
"data": { "id": 3, "name": "Trial signups", "contacts_count": 0, "...": "..." }
}
Adds members by contact id and/or email. Idempotent — re-posting the same batch is safe. Emails that do not match an existing contact are returned under not_found rather than silently created, because an API that invents contacts from typos quietly corrupts your database.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| contact_ids | array | No | Up to 1000 contact ids. Scoped to your workspace |
| emails | array | No | Up to 1000 addresses, resolved to existing contacts |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/contact-lists/3/contacts' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"contact_ids": [42, 43],
"emails": ["[email protected]", "[email protected]"]
}'
Example Response
{
"message": "List updated.",
"data": {
"added": 3,
"already_present": 0,
"not_found": ["[email protected]"],
"contacts_count": 3
}
}
Paginated members of a list, including their unsubscribe state.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| per_page | integer | No | Max 200 (default 50) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/contact-lists/3/contacts' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 42,
"email": "[email protected]",
"first_name": "Jane",
"last_name": "Smith",
"company": "Acme Corp",
"status": "active",
"unsubscribed_at": null
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 50, "total": 1 }
}
Removes one member from the list. The contact itself is untouched.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/contact-lists/3/contacts/42' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"message": "Contact removed from list.",
"data": { "contacts_count": 2 }
}
Renames a list or changes its description.
Example Request
curl -X PUT 'https://mediacity.co.in/mailtrixy/public/api/v1/contact-lists/3' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"Trial signups (Q4)"}'
Example Response
{ "message": "List updated.", "data": { "id": 3, "name": "Trial signups (Q4)", "...": "..." } }
Deletes the list. The contacts in it are NOT removed.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/contact-lists/3' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{ "message": "List deleted. The contacts themselves were not removed." }
Read-only list of saved segments, for use as a campaign audience_id.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/segments' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 5,
"name": "High-value UK leads",
"is_dynamic": true,
"contacts_count": 318,
"created_at": "2026-08-14T11:20:00+00:00"
}
]
}
Deals & Pipelines
Requires deals scope.
Stage changes go through a dedicated /move endpoint rather than PUT,
because moving a stage also sets won/lost timestamps and fires the workflow trigger — burying that
in a generic update would make it easy to change a stage without them.
Pipelines with their ordered stages. You need the stage ids before creating or moving a deal.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/pipelines' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 1,
"name": "Sales Pipeline",
"is_default": true,
"stages": [
{ "id": 1, "name": "Lead", "color": "#6B7280", "win_probability": 10, "sort_order": 1 },
{ "id": 2, "name": "Qualified", "color": "#3B82F6", "win_probability": 25, "sort_order": 2 },
{ "id": 3, "name": "Proposal", "color": "#EAB308", "win_probability": 50, "sort_order": 3 },
{ "id": 4, "name": "Negotiation", "color": "#F97316", "win_probability": 75, "sort_order": 4 },
{ "id": 5, "name": "Won", "color": "#22C55E", "win_probability": 100, "sort_order": 5 },
{ "id": 6, "name": "Lost", "color": "#EF4444", "win_probability": 0, "sort_order": 6 }
]
}
]
}
Paginated deals with nested pipeline, stage and contact.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| status | string | No | open | won | lost |
| pipeline_id | integer | No | Filter by pipeline |
| stage_id | integer | No | Filter by stage |
| contact_id | integer | No | Filter by contact |
| search | string | No | Match the deal title |
| sort_by | string | No | created_at | updated_at | value | expected_close_date | title |
| sort_dir | string | No | asc | desc (default desc) |
| per_page | integer | No | Max 100 (default 25) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/deals?status=open&sort_by=value&sort_dir=desc' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 15,
"title": "Acme — annual plan",
"value": 24000.00,
"currency": "USD",
"status": "open",
"expected_close_date": "2026-11-30",
"won_at": null,
"lost_at": null,
"lost_reason": null,
"notes": "Procurement review in week 2.",
"custom_fields": { "source": "outbound" },
"pipeline": { "id": 1, "name": "Sales Pipeline" },
"stage": { "id": 3, "name": "Proposal", "win_probability": 50 },
"contact": { "id": 42, "email": "[email protected]", "first_name": "Jane", "last_name": "Smith", "company": "Acme Corp" },
"created_at": "2026-09-30T13:00:00+00:00",
"updated_at": "2026-10-20T08:45:00+00:00"
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1 }
}
Creates a deal. Omit pipeline_id to use the default pipeline, and deal_stage_id to land in its first stage — a new deal belongs at the top of the funnel. Referenced contacts and stages are verified to belong to your workspace.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Deal title |
| contact_id | integer | No | Linked contact. Must be in your workspace |
| pipeline_id | integer | No | Defaults to the workspace default pipeline |
| deal_stage_id | integer | No | Defaults to the pipeline's first stage |
| value | number | No | Deal value (default 0) |
| currency | string | No | 3-letter code (default USD) |
| expected_close_date | string | No | YYYY-MM-DD |
| notes | string | No | Free text, max 5000 |
| custom_fields | object | No | Arbitrary key/value pairs |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/deals' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"title": "Globex — pilot",
"contact_id": 43,
"value": 8000,
"currency": "GBP",
"expected_close_date": "2026-12-15",
"custom_fields": {"source": "outreach"}
}'
Example Response
201 Created
{
"message": "Deal created.",
"data": { "id": 16, "title": "Globex — pilot", "status": "open", "stage": { "id": 1, "name": "Lead" }, "...": "..." }
}
422 — no pipeline exists yet
{ "error": "No pipeline available. Create one in the Deals screen first.", "code": "NO_PIPELINE" }
422 — contact belongs to another workspace
{ "error": "Contact not found.", "code": "INVALID_CONTACT" }
Moves a deal to another stage in its own pipeline. A stage named "Won" (or with win_probability 100) sets status=won and won_at; a stage named "Lost" sets status=lost, lost_at and the optional lost_reason. Fires DealStageChanged so workflows react.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| deal_stage_id | integer | Yes | Target stage. Must belong to this deal's pipeline |
| lost_reason | string | No | Recorded when moving to a Lost stage |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/deals/15/move' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"deal_stage_id":5}'
Example Response
200 OK
{
"message": "Deal moved.",
"data": {
"id": 15,
"status": "won",
"won_at": "2026-10-26T10:15:00+00:00",
"stage": { "id": 5, "name": "Won", "win_probability": 100 },
"...": "..."
}
}
422 — stage from a different pipeline
{ "error": "That stage does not belong to this deal's pipeline.", "code": "INVALID_STAGE" }
Updates deal fields. Stage is deliberately excluded — use POST /deals/{id}/move.
Example Request
curl -X PUT 'https://mediacity.co.in/mailtrixy/public/api/v1/deals/15' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"value":26500,"notes":"Scope increased."}'
Example Response
{
"message": "Deal updated.",
"data": { "id": 15, "value": 26500.00, "notes": "Scope increased.", "...": "..." }
}
A single deal with its pipeline, stage and contact.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/deals/15' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{ "data": { "id": 15, "title": "Acme — annual plan", "stage": { "id": 3, "name": "Proposal" }, "...": "..." } }
Deletes a deal.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/deals/15' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{ "message": "Deal deleted." }
Suppressions
Requires suppressions scope.
This is the one piece of state that must stay in sync with any other system that also emails these
people: a bounce recorded here is invisible to an external sender, which keeps mailing a dead address
and damages your sending domain's reputation.
reason is one of
hard_bounce, spam_complaint,
unsubscribe, manual.
Paginated suppression list. Use ?since= for incremental sync — a nightly job can pull only what changed instead of the whole list.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| reason | string | No | hard_bounce | spam_complaint | unsubscribe | manual |
| search | string | No | Match the email address |
| since | string | No | ISO-8601 date or datetime. Only rows created at or after it |
| per_page | integer | No | Max 500 (default 100) |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/suppressions?since=2026-10-01' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{ "id": 88, "email": "[email protected]", "reason": "hard_bounce", "created_at": "2026-10-19T07:02:00+00:00" },
{ "id": 89, "email": "[email protected]", "reason": "unsubscribe", "created_at": "2026-10-22T16:41:00+00:00" }
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 100, "total": 2 }
}
A single yes/no for one address, so an external sender can gate one send without paging the whole list. Also reports contact-level unsubscribes, which live on the contacts table rather than here but suppress sending just the same.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| string | Yes | Address to check |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/suppressions/[email protected]' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
Suppressed via the list
{
"data": {
"email": "[email protected]",
"suppressed": true,
"reason": "hard_bounce",
"source": "suppression_list",
"suppressed_at": "2026-10-19T07:02:00+00:00"
}
}
Suppressed via a contact-level unsubscribe
{
"data": {
"email": "[email protected]",
"suppressed": true,
"reason": "unsubscribe",
"source": "contact_unsubscribe",
"suppressed_at": "2026-10-22T16:41:00+00:00"
}
}
Clear to send
{
"data": {
"email": "[email protected]",
"suppressed": false,
"reason": null,
"source": null,
"suppressed_at": null
}
}
Adds one address or up to 1000. Idempotent — re-posting an existing address is a no-op rather than a unique-key error, so a retrying sync is safe.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| string | No | Single address. Required unless emails is given | |
| emails | array | No | 1-1000 addresses. Required unless email is given |
| reason | string | No | hard_bounce | spam_complaint | unsubscribe | manual (default manual) |
| unsubscribe_contact | boolean | No | Also mark the matching CRM contact as unsubscribed |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/suppressions' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"emails": ["[email protected]", "[email protected]"],
"reason": "hard_bounce",
"unsubscribe_contact": true
}'
Example Response
201 Created
{
"message": "Suppression list updated.",
"data": { "added": 2, "already_suppressed": 0, "reason": "hard_bounce" }
}
Removes a suppression, resuming mail to that address. Owner/admin only — this is a deliverability decision, not a data edit. A contact-level unsubscribe is a separate record and is NOT cleared: consent has to be re-collected, not revoked by an API call.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/suppressions/88' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"message": "Suppression removed.",
"data": {
"email": "[email protected]",
"previous_reason": "hard_bounce",
"contact_unsubscribe_cleared": false
}
}
Update & Version
Metadata about this installation: platform version, which optional features are switched on, and
whether your own client build is still supported. No scope required — this describes
the installation your token already authenticates against, matching the
/user and /workspace precedent.
Minimal payload — safe for a status badge or health check to poll frequently.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/update/version' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {
"name": "MailTrixy",
"version": "1.9.0",
"build": 20261026,
"api_version": "v1"
}
}
Platform version, server-side feature flags and maintenance state. Pass platform and build to also receive update advice for that client — a mobile app has no other way to learn it is too old to talk to this server.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| platform | string | No | android | ios | web | desktop |
| build | integer | No | Your own build number. Without it no comparison is made |
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/update?platform=android&build=420' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {
"platform": {
"name": "MailTrixy",
"version": "1.9.0",
"build": 20261026,
"api_version": "v1",
"supported_api_versions": ["v1"]
},
"features": {
"outreach": true,
"campaigns": true,
"sms_campaigns": false,
"temp_mail": true,
"knowledge_base": true,
"workflows": true,
"deals": true,
"ai_replies": true,
"two_factor": true,
"social_login": true,
"push_notifications": false
},
"maintenance": { "active": false, "message": null },
"client": {
"platform": "android",
"your_build": 420,
"latest_build": 460,
"min_supported_build": 400,
"store_url": "https://play.google.com/store/apps/details?id=com.acme.mailtrixy",
"update_available": true,
"force_update": false,
"message": "A newer version is available."
}
}
}
A build below min_supported_build instead returns:
"client": { "update_available": true, "force_update": true,
"message": "This version is no longer supported. Please update to continue." }
Release notes, served from an admin-editable setting so an in-app "what's new" sheet does not require a client release to update. Admins who typed plain prose instead of JSON still get one usable entry.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/update/changelog' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": {
"current_version": "1.9.0",
"entries": [
{
"version": "1.9.0",
"date": "2026-10-26",
"title": "Cold Outreach + REST API overhaul",
"notes": [
"New: Cold Outreach — multi-step cold email sequences.",
"Fixed: every scoped /api/v1 endpoint returned HTTP 500.",
"New: API token management under Settings -> Account."
]
}
]
}
}
API Tokens
Create, list and revoke your own scoped tokens. No scope required, but creating one requires your account password — without that check, a leaked token could mint further tokens with wider scopes and outlive its own revocation. Tokens are shown exactly once, on create: only a hash is stored, so there is no way to reveal one later and no endpoint here pretends otherwise.
Your tokens, plus the full scope catalog for rendering a picker. is_full_access marks the ["*"] tokens issued by app login rather than by the token manager.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/tokens' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{
"id": 17,
"name": "Zapier integration",
"scopes": ["contacts", "deals"],
"is_full_access": false,
"last_used_at": "2026-10-26T08:55:00+00:00",
"expires_at": null,
"is_expired": false,
"is_current": true,
"created_at": "2026-10-20T12:00:00+00:00"
},
{
"id": 12,
"name": "iPhone",
"scopes": ["*"],
"is_full_access": true,
"last_used_at": "2026-10-25T19:30:00+00:00",
"expires_at": null,
"is_expired": false,
"is_current": false,
"created_at": "2026-08-02T07:10:00+00:00"
}
],
"available_scopes": [
{ "scope": "contacts", "label": "Contacts", "description": "Read and write contacts, lists and segments, including import and export." }
]
}
Creates a scoped token. Requires your account password. Max 25 live tokens per user — every live token is attack surface and nothing legitimate needs dozens.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Label, used only to identify it in the list |
| scopes | array | Yes | One or more scope names. See GET /tokens/scopes |
| password | string | Yes | Your account password |
| expires_in_days | integer | No | 1-3650. Omit for a token that never expires |
Example Request
curl -X POST 'https://mediacity.co.in/mailtrixy/public/api/v1/tokens' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "CI pipeline",
"scopes": ["contacts", "emails"],
"password": "your-account-password",
"expires_in_days": 90
}'
Example Response
201 Created — copy `token` now, it is never shown again
{
"message": "Token created. Copy it now — it will not be shown again.",
"data": {
"id": 18,
"name": "CI pipeline",
"scopes": ["contacts", "emails"],
"token": "19|xWq3...redacted...",
"expires_at": "2027-01-24T10:30:00+00:00",
"created_at": "2026-10-26T10:30:00+00:00"
}
}
422 — wrong password
{ "error": "That password is not correct.", "code": "INVALID_PASSWORD" }
422 — too many tokens
{ "error": "Token limit reached. Revoke an unused token first.", "code": "TOKEN_LIMIT" }
The scope catalog, so a UI can render a token picker without hardcoding the list.
Example Request
curl -X GET 'https://mediacity.co.in/mailtrixy/public/api/v1/tokens/scopes' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"data": [
{ "scope": "contacts", "label": "Contacts", "description": "Read and write contacts, lists and segments, including import and export." },
{ "scope": "outreach", "label": "Cold Outreach", "description": "Manage cold email sequences, push leads and read sequence reports." },
{ "scope": "emails", "label": "Email sending", "description": "Send individual transactional emails and read their delivery status." },
{ "scope": "email-accounts","label": "Mailboxes", "description": "Read mailbox status, reconnect or disconnect mailboxes, and manage signatures." }
]
}
Revokes a token immediately. revoked_current_token tells you whether you just killed the credential you authenticated this request with, so a client can stop retrying with it.
Example Request
curl -X DELETE 'https://mediacity.co.in/mailtrixy/public/api/v1/tokens/18' \ -H 'Authorization: Bearer YOUR_TOKEN'
Example Response
{
"message": "Token revoked.",
"revoked_current_token": false
}
Try It
Test API endpoints directly from this page.