API Endpoints Reference

Complete reference for all MailTrixy REST API endpoints. All endpoints require authentication via Bearer token and are prefixed with /api/v1. See the API Overview for authentication, rate limiting, and response format details.

Contacts

Scope required: contacts

List Contacts

Method GET
URL /api/v1/contacts
Description Retrieve a paginated list of contacts. Supports filtering by tag, group, search query, and date range.

Query Parameters:

Parameter Type Description
page integer Page number (default: 1)
per_page integer Items per page, max 100 (default: 25)
search string Search by name, email, or company
tag string Filter by tag name
group_id integer Filter by contact group ID

Response: 200 OK

GET /api/v1/contacts?search=acme&per_page=2

{
    "success": true,
    "data": [
        {
            "id": 42,
            "name": "Jane Smith",
            "email": "jane@acme.com",
            "company": "Acme Corp",
            "phone": "+1-555-0123",
            "tags": [{"id": 1, "name": "lead"}],
            "created_at": "2026-03-20T08:30:00Z",
            "updated_at": "2026-03-25T10:00:00Z"
        },
        {
            "id": 43,
            "name": "Bob Johnson",
            "email": "bob@acme.com",
            "company": "Acme Corp",
            "phone": null,
            "tags": [],
            "created_at": "2026-03-21T09:15:00Z",
            "updated_at": "2026-03-21T09:15:00Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 2,
        "total": 5,
        "last_page": 3
    }
}

Get Single Contact

Method GET
URL /api/v1/contacts/{id}
Description Retrieve a single contact with all details including custom fields, tags, and groups.

Response: 200 OK

GET /api/v1/contacts/42

{
    "success": true,
    "data": {
        "id": 42,
        "name": "Jane Smith",
        "email": "jane@acme.com",
        "company": "Acme Corp",
        "phone": "+1-555-0123",
        "tags": [{"id": 1, "name": "lead"}, {"id": 2, "name": "enterprise"}],
        "groups": [{"id": 5, "name": "Newsletter Subscribers"}],
        "custom_fields": {
            "department": "Engineering",
            "deal_value": 50000
        },
        "conversations_count": 8,
        "last_contacted_at": "2026-03-24T14:20:00Z",
        "created_at": "2026-03-20T08:30:00Z",
        "updated_at": "2026-03-25T10:00:00Z"
    }
}

Error: 404 Not Found if the contact does not exist.

Create Contact

Method POST
URL /api/v1/contacts
Description Create a new contact. The email must be unique within the workspace.

Request Body:

{
    "name": "Jane Smith",
    "email": "jane@acme.com",
    "company": "Acme Corp",
    "phone": "+1-555-0123",
    "tags": ["lead", "enterprise"],
    "group_ids": [5, 12],
    "custom_fields": {
        "department": "Engineering",
        "deal_value": 50000
    }
}
Field Type Required Description
name string Yes Full name of the contact
email string Yes Unique email address
company string No Company or organization name
phone string No Phone number with country code
tags array No Array of tag names (created if they don't exist)
group_ids array No Array of contact group IDs to add the contact to
custom_fields object No Key-value pairs for custom field data

Response: 201 Created

{
    "success": true,
    "data": {
        "id": 42,
        "name": "Jane Smith",
        "email": "jane@acme.com",
        "company": "Acme Corp",
        "phone": "+1-555-0123",
        "tags": [{"id": 1, "name": "lead"}, {"id": 2, "name": "enterprise"}],
        "groups": [{"id": 5, "name": "Newsletter Subscribers"}, {"id": 12, "name": "VIP Clients"}],
        "custom_fields": {"department": "Engineering", "deal_value": 50000},
        "created_at": "2026-03-25T10:00:00Z",
        "updated_at": "2026-03-25T10:00:00Z"
    }
}

Errors:

Status Condition
422 Validation error (missing required fields, duplicate email)
401 Missing or invalid API token

Update Contact

Method PUT
URL /api/v1/contacts/{id}
Description Update an existing contact. Only the provided fields are updated (partial update).

Request Body:

PUT /api/v1/contacts/42

{
    "company": "Acme Industries",
    "phone": "+1-555-9999",
    "custom_fields": {
        "deal_value": 75000
    }
}

Response: 200 OK -- Returns the full updated contact object (same structure as GET).

Errors: 404 if not found, 422 if validation fails.

Delete Contact

Method DELETE
URL /api/v1/contacts/{id}
Description Permanently delete a contact and all associated data. This action cannot be undone.

Response: 200 OK

{
    "success": true,
    "data": {
        "message": "Contact deleted successfully."
    }
}

Errors: 404 if the contact does not exist.

Conversations

Scope required: conversations

List Conversations

Method GET
URL /api/v1/conversations
Description List conversations with optional filtering by status, assignee, contact, and label.

Query Parameters:

Parameter Type Description
status string Filter by status: open, closed, snoozed, all
assignee_id integer Filter by assigned team member ID
contact_id integer Filter by contact ID
label string Filter by conversation label

Response: 200 OK

{
    "success": true,
    "data": [
        {
            "id": 101,
            "subject": "Billing question",
            "status": "open",
            "contact": {"id": 42, "name": "Jane Smith", "email": "jane@acme.com"},
            "assignee": {"id": 3, "name": "Support Agent"},
            "labels": ["billing", "priority"],
            "messages_count": 5,
            "last_message_at": "2026-03-25T14:30:00Z",
            "created_at": "2026-03-24T09:00:00Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 25,
        "total": 28,
        "last_page": 2
    }
}

Reply to Conversation

Method POST
URL /api/v1/conversations/{id}/reply
Description Send a reply message in an existing conversation. The email is sent to the contact.

Request Body:

POST /api/v1/conversations/101/reply

{
    "body_html": "<p>Thanks for reaching out! Your invoice has been updated.</p>",
    "cc": ["manager@acme.com"],
    "bcc": [],
    "attachments": []
}
Field Type Required Description
body_html string Yes HTML body of the reply message
cc array No CC email addresses
bcc array No BCC email addresses

Response: 201 Created

{
    "success": true,
    "data": {
        "id": 580,
        "conversation_id": 101,
        "direction": "outbound",
        "body_html": "<p>Thanks for reaching out! Your invoice has been updated.</p>",
        "sender": {"id": 3, "name": "Support Agent"},
        "created_at": "2026-03-25T15:00:00Z"
    }
}

Campaigns

Scope required: campaigns

List Campaigns

Method GET
URL /api/v1/campaigns
Description List all campaigns with status filters. Returns campaign metadata and delivery statistics.

Query Parameters:

Parameter Type Description
status string draft, scheduled, sending, sent, paused

Response: 200 OK

{
    "success": true,
    "data": [
        {
            "id": 15,
            "name": "March Newsletter",
            "subject": "What's new in March 2026",
            "status": "sent",
            "from_email": "newsletter@yourcompany.com",
            "from_name": "Your Company",
            "recipients_count": 1200,
            "stats": {
                "delivered": 1180,
                "opened": 384,
                "clicked": 98,
                "bounced": 20,
                "unsubscribed": 3
            },
            "sent_at": "2026-03-20T09:00:00Z",
            "created_at": "2026-03-18T14:00:00Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 25,
        "total": 12,
        "last_page": 1
    }
}

Create Campaign

Method POST
URL /api/v1/campaigns
Description Create a new email campaign. The campaign is created in draft status by default. Use schedule_at to schedule or POST to /campaigns/{id}/send to send immediately.

Request Body:

{
    "name": "April Product Update",
    "subject": "Exciting new features in April",
    "from_email": "newsletter@yourcompany.com",
    "from_name": "Your Company",
    "body_html": "<h1>April Update</h1><p>Hello {{contact.name}}, check out what's new...</p>",
    "recipient_groups": [1, 3],
    "email_account_id": 5,
    "schedule_at": "2026-04-01T09:00:00Z"
}
Field Type Required Description
name string Yes Internal campaign name
subject string Yes Email subject line (supports merge tags)
from_email string Yes Sender email address (must be verified)
from_name string Yes Sender display name
body_html string Yes HTML content of the email
recipient_groups array Yes Array of contact group IDs to send to
email_account_id integer Yes ID of the connected email account to send from
schedule_at string No ISO 8601 datetime to schedule sending (omit for draft)

Response: 201 Created

{
    "success": true,
    "data": {
        "id": 16,
        "name": "April Product Update",
        "subject": "Exciting new features in April",
        "status": "scheduled",
        "recipients_count": 850,
        "schedule_at": "2026-04-01T09:00:00Z",
        "created_at": "2026-03-25T16:00:00Z"
    }
}

Tags

Scope required: contacts

List Tags

Method GET
URL /api/v1/tags
Description List all tags in the workspace with contact counts.

Response: 200 OK

{
    "success": true,
    "data": [
        {"id": 1, "name": "lead", "color": "#3B82F6", "contacts_count": 45},
        {"id": 2, "name": "enterprise", "color": "#8B5CF6", "contacts_count": 12},
        {"id": 3, "name": "churned", "color": "#EF4444", "contacts_count": 8}
    ]
}

Create Tag

Method POST
URL /api/v1/tags

Request Body:

{
    "name": "vip",
    "color": "#F59E0B"
}
Field Type Required Description
name string Yes Unique tag name (lowercase, no spaces)
color string No Hex color code (default: auto-assigned)

Response: 201 Created

{
    "success": true,
    "data": {
        "id": 4,
        "name": "vip",
        "color": "#F59E0B",
        "contacts_count": 0
    }
}

Update Tag

Method PUT
URL /api/v1/tags/{id}

Request Body:

{
    "name": "vip-client",
    "color": "#10B981"
}

Response: 200 OK -- Returns the updated tag object.

Delete Tag

Method DELETE
URL /api/v1/tags/{id}
Description Delete a tag. The tag is removed from all contacts that had it. Contacts themselves are not deleted.

Response: 200 OK

{
    "success": true,
    "data": {
        "message": "Tag deleted successfully."
    }
}

Contact Groups

Scope required: contacts

List Groups

Method GET
URL /api/v1/contact-groups
Description List all contact groups with member counts.

Response: 200 OK

{
    "success": true,
    "data": [
        {"id": 1, "name": "Newsletter Subscribers", "description": "Opted-in newsletter list", "members_count": 520, "created_at": "2026-01-10T08:00:00Z"},
        {"id": 2, "name": "Trial Users", "description": "Users on free trial", "members_count": 85, "created_at": "2026-02-15T12:00:00Z"}
    ]
}

Create Group

Method POST
URL /api/v1/contact-groups

Request Body:

{
    "name": "Webinar Attendees",
    "description": "Contacts who registered for the Q2 webinar"
}

Response: 201 Created

{
    "success": true,
    "data": {
        "id": 3,
        "name": "Webinar Attendees",
        "description": "Contacts who registered for the Q2 webinar",
        "members_count": 0,
        "created_at": "2026-03-25T16:30:00Z"
    }
}

Update Group

Method PUT
URL /api/v1/contact-groups/{id}

Request Body:

{
    "name": "Q2 Webinar Attendees",
    "description": "Updated description"
}

Response: 200 OK -- Returns the updated group object.

Delete Group

Method DELETE
URL /api/v1/contact-groups/{id}
Description Delete a contact group. Members are removed from the group but not deleted.

Response: 200 OK

{
    "success": true,
    "data": {
        "message": "Contact group deleted successfully."
    }
}

Manage Group Members

Method Endpoint Description
GET /contact-groups/{id}/members List all contacts in a group (paginated)
POST /contact-groups/{id}/members Add contacts to the group
DELETE /contact-groups/{id}/members Remove contacts from the group

Add Members -- Request Body:

POST /api/v1/contact-groups/3/members

{
    "contact_ids": [42, 43, 44]
}

Response: 200 OK

{
    "success": true,
    "data": {
        "added": 3,
        "already_members": 0,
        "members_count": 3
    }
}

Remove Members -- Request Body:

DELETE /api/v1/contact-groups/3/members

{
    "contact_ids": [44]
}

Response: 200 OK

{
    "success": true,
    "data": {
        "removed": 1,
        "members_count": 2
    }
}

Deals

Scope required: deals

List Deals

Method GET
URL /api/v1/deals
Description List all deals with optional filtering by stage, assignee, and contact.

Query Parameters:

Parameter Type Description
stage string lead, qualified, proposal, negotiation, won, lost
assignee_id integer Filter by assigned team member
contact_id integer Filter by associated contact

Response: 200 OK

{
    "success": true,
    "data": [
        {
            "id": 10,
            "title": "Acme Corp Enterprise Plan",
            "value": 75000,
            "currency": "USD",
            "stage": "proposal",
            "contact": {"id": 42, "name": "Jane Smith", "email": "jane@acme.com"},
            "assignee": {"id": 3, "name": "Sales Rep"},
            "expected_close_date": "2026-04-15",
            "created_at": "2026-03-10T11:00:00Z",
            "updated_at": "2026-03-24T16:00:00Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 25,
        "total": 18,
        "last_page": 1
    }
}

Create Deal

Method POST
URL /api/v1/deals

Request Body:

{
    "title": "Acme Corp Enterprise Plan",
    "value": 75000,
    "currency": "USD",
    "stage": "lead",
    "contact_id": 42,
    "assignee_id": 3,
    "expected_close_date": "2026-04-15",
    "notes": "Initial discussion about enterprise needs"
}
Field Type Required Description
title string Yes Name/title of the deal
value number Yes Monetary value of the deal
currency string No ISO 4217 currency code (default: workspace currency)
stage string No Pipeline stage (default: lead)
contact_id integer Yes Associated contact ID
assignee_id integer No Team member to assign the deal to
expected_close_date string No Expected close date (YYYY-MM-DD)
notes string No Free-text notes about the deal

Response: 201 Created -- Returns the full deal object.

Update Deal

Method PUT
URL /api/v1/deals/{id}

Request Body: Same fields as create (all optional for partial update).

PUT /api/v1/deals/10

{
    "stage": "negotiation",
    "value": 80000
}

Response: 200 OK -- Returns the full updated deal object.

Delete Deal

Method DELETE
URL /api/v1/deals/{id}

Response: 200 OK

{
    "success": true,
    "data": {
        "message": "Deal deleted successfully."
    }
}

Webhooks (Zapier Compatible)

MailTrixy can send real-time webhook notifications to external services when events occur. Webhooks use a Zapier-compatible JSON format, making them work seamlessly with Zapier, Make (Integromat), n8n, and custom integrations.

Scope required: webhooks

List Webhooks

Method GET
URL /api/v1/webhooks

Response: 200 OK

{
    "success": true,
    "data": [
        {
            "id": 1,
            "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
            "events": ["contact.created", "contact.updated", "deal.stage_changed"],
            "is_active": true,
            "created_at": "2026-03-20T10:00:00Z"
        }
    ]
}

Create Webhook

Method POST
URL /api/v1/webhooks

Request Body:

{
    "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
    "events": [
        "contact.created",
        "contact.updated",
        "contact.deleted",
        "conversation.created",
        "conversation.replied",
        "conversation.closed",
        "deal.created",
        "deal.stage_changed",
        "deal.won",
        "deal.lost",
        "campaign.sent",
        "campaign.completed"
    ]
}
Field Type Required Description
url string Yes HTTPS URL to receive webhook POST requests
events array Yes Array of event types to subscribe to

Response: 201 Created

{
    "success": true,
    "data": {
        "id": 2,
        "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
        "events": ["contact.created", "contact.updated", "..."],
        "secret": "whsec_abc123def456",
        "is_active": true,
        "created_at": "2026-03-25T17:00:00Z"
    }
}

The secret is returned only at creation time. Use it to verify webhook signatures via the X-MailTrixy-Signature header.

Delete Webhook

Method DELETE
URL /api/v1/webhooks/{id}

Response: 200 OK

{
    "success": true,
    "data": {
        "message": "Webhook deleted successfully."
    }
}

Webhook Payload Format

When an event occurs, MailTrixy sends a POST request to your webhook URL with the following Zapier-compatible JSON payload:

// Headers
POST https://hooks.zapier.com/hooks/catch/123456/abcdef/
Content-Type: application/json
X-MailTrixy-Signature: sha256=abc123...
X-MailTrixy-Event: contact.created

// Body
{
    "event": "contact.created",
    "timestamp": "2026-03-25T18:00:00Z",
    "workspace_id": 1,
    "data": {
        "id": 50,
        "name": "New Contact",
        "email": "new@example.com",
        "company": "Example Inc",
        "tags": ["lead"],
        "created_at": "2026-03-25T18:00:00Z"
    }
}

Available Events

Event Triggered When
contact.created A new contact is added
contact.updated A contact's details are modified
contact.deleted A contact is permanently deleted
conversation.created A new conversation is started
conversation.replied A reply is sent in a conversation
conversation.closed A conversation is resolved/closed
deal.created A new deal is created
deal.stage_changed A deal moves to a different pipeline stage
deal.won A deal is marked as won
deal.lost A deal is marked as lost
campaign.sent A campaign begins sending
campaign.completed A campaign has finished sending to all recipients

Status Codes Summary

Code Meaning
200 OK -- Request succeeded (GET, PUT, DELETE)
201 Created -- Resource created successfully (POST)
400 Bad Request -- Malformed request body
401 Unauthenticated -- Missing or invalid Bearer token
403 Forbidden -- Token lacks required scope
404 Not Found -- Resource does not exist
422 Validation Error -- Request validation failed (see error details)
429 Rate Limited -- Too many requests, retry after cooldown
500 Server Error -- Internal server error
Last updated 10/03/2026